File Coverage

blib/lib/Types/Standard.pm
Criterion Covered Total %
statement 69 70 98.5
branch 9 20 45.0
condition 5 8 62.5
subroutine 21 21 100.0
pod 3 3 100.0
total 107 122 87.7


line stmt bran cond sub pod time code
1             package Types::Standard;
2              
3 281     281   4049066 use 5.008001;
  281         1153  
4 281     281   2019 use strict;
  281         3011  
  281         11643  
5 281     281   1466 use warnings;
  281         562  
  281         34142  
6              
7             BEGIN {
8 281     281   1130 eval { require re };
  281         1787  
9 281 50       16220 if ( $] < 5.010 ) { require Devel::TypeTiny::Perl58Compat }
  0         0  
10             }
11              
12             BEGIN {
13 281     281   1004 $Types::Standard::AUTHORITY = 'cpan:TOBYINK';
14 281         17029 $Types::Standard::VERSION = '2.010001';
15             }
16              
17             $Types::Standard::VERSION =~ tr/_//d;
18              
19 281     281   104348 use Type::Library -base;
  281         974  
  281         3267  
20              
21             our @EXPORT_OK = qw( slurpy );
22              
23 281     281   20658 use Eval::TypeTiny qw( set_subname );
  281         955  
  281         1853  
24 281     281   147048 use Scalar::Util qw( blessed looks_like_number );
  281         676  
  281         24724  
25 281     281   1973 use Type::Tiny ();
  281         600  
  281         4639  
26 281     281   1200 use Types::TypeTiny ();
  281         577  
  281         48088  
27              
28             my $is_class_loaded;
29              
30             BEGIN {
31 281     281   1205 $is_class_loaded = q{sub {
32             no strict 'refs';
33             return !!0 if ref $_[0];
34             return !!0 if not $_[0];
35             return !!0 if ref(do { my $tmpstr = $_[0]; \$tmpstr }) ne 'SCALAR';
36             my $stash = \%{"$_[0]\::"};
37             return !!1 if exists($stash->{'ISA'}) && *{$stash->{'ISA'}}{ARRAY} && @{$_[0].'::ISA'};
38             return !!1 if exists($stash->{'VERSION'});
39             foreach my $globref (values %$stash) {
40             return !!1
41             if ref \$globref eq 'GLOB'
42             ? *{$globref}{CODE}
43             : ref $globref; # const or sub ref
44             }
45             return !!0;
46             }};
47            
48 281 0   2   1221 *_is_class_loaded =
  2 0       12  
  2 0       2  
  2         295  
49             Type::Tiny::_USE_XS
50             ? \&Type::Tiny::XS::Util::is_class_loaded
51             : eval $is_class_loaded;
52            
53             *_HAS_REFUTILXS = eval {
54 281         151953 require Ref::Util::XS;
55 281         463016 Ref::Util::XS::->VERSION( 0.100 );
56 281         89374 1;
57             }
58             ? sub () { !!1 }
59 281 50       696 : sub () { !!0 };
60             } #/ BEGIN
61              
62             my $add_core_type = sub {
63             my $meta = shift;
64             my ( $typedef ) = @_;
65            
66             my $name = $typedef->{name};
67             my ( $xsub, $xsubname );
68            
69             # We want Map and Tuple to be XSified, even if they're not
70             # really core.
71             $typedef->{_is_core} = 1
72             unless $name eq 'Map' || $name eq 'Tuple';
73            
74             if ( Type::Tiny::_USE_XS
75             and not( $name eq 'RegexpRef' ) )
76             {
77             $xsub = Type::Tiny::XS::get_coderef_for( $name );
78             $xsubname = Type::Tiny::XS::get_subname_for( $name );
79             }
80            
81             elsif ( Type::Tiny::_USE_MOUSE
82             and not( $name eq 'RegexpRef' or $name eq 'Int' or $name eq 'Object' ) )
83             {
84             require Mouse::Util::TypeConstraints;
85             $xsub = "Mouse::Util::TypeConstraints"->can( $name );
86             $xsubname = "Mouse::Util::TypeConstraints::$name" if $xsub;
87             }
88            
89             if ( Type::Tiny::_USE_XS
90             and Type::Tiny::XS->VERSION < 0.014
91             and $name eq 'Bool' )
92             {
93             # Broken implementation of Bool
94             $xsub = $xsubname = undef;
95             }
96            
97             if ( Type::Tiny::_USE_XS
98             and ( Type::Tiny::XS->VERSION < 0.016 or $] < 5.018 )
99             and $name eq 'Int' )
100             {
101             # Broken implementation of Int
102             $xsub = $xsubname = undef;
103             }
104              
105             if ( Type::Tiny::_USE_XS
106             and $name eq 'Int'
107 281     281   2653 and do { use Config (); $Config::Config{usequadmath} } )
  281         553  
  281         259113  
108             {
109             # Broken implementation of Int
110             $xsub = $xsubname = undef;
111             }
112            
113             $typedef->{compiled_type_constraint} = $xsub if $xsub;
114            
115             my $orig_inlined = $typedef->{inlined};
116             if (
117             defined( $xsubname ) and (
118            
119             # These should be faster than their normal inlined
120             # equivalents
121             $name eq 'Str'
122             or $name eq 'Bool'
123             or $name eq 'Int'
124             or $name eq 'ClassName'
125             or $name eq 'RegexpRef'
126             or $name eq 'FileHandle'
127             )
128             )
129             {
130             $typedef->{inlined} = sub {
131             $Type::Tiny::AvoidCallbacks ? goto( $orig_inlined ) : "$xsubname\($_[1])";
132             };
133             } #/ if ( defined( $xsubname...))
134            
135             @_ = ( $meta, $typedef );
136             goto \&Type::Library::add_type;
137             };
138              
139             my $maybe_load_modules = sub {
140             my $code = pop;
141             if ( $Type::Tiny::AvoidCallbacks ) {
142             $code = sprintf(
143             'do { %s %s; %s }',
144             $Type::Tiny::SafePackage,
145             join( '; ', map "use $_ ()", @_ ),
146             $code,
147             );
148             }
149             $code;
150             };
151              
152 3     3   38 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  3         38  
153              
154             my $meta = __PACKAGE__->meta;
155              
156             # Stringable and LazyLoad are optimizations that complicate
157             # this module somewhat, but they have led to performance
158             # improvements. If Types::Standard wasn't such a key type
159             # library, I wouldn't use them. I strongly discourage anybody
160             # from using them in their own code. If you're looking for
161             # examples of how to write a type library sanely, you're
162             # better off looking at the code for Types::Common::Numeric
163             # and Types::Common::String.
164              
165             {
166              
167             sub Stringable (&) {
168 42     42 1 535 bless +{ code => $_[0] }, 'Types::Standard::_Stringable';
169             }
170             Types::Standard::_Stringable->Type::Tiny::_install_overloads(
171 71   66 71   521 q[""] => sub { $_[0]{text} ||= $_[0]{code}->() } );
172            
173             sub LazyLoad ($$) {
174 10959     10959 1 71028 bless \@_, 'Types::Standard::LazyLoad';
175             }
176             'Types::Standard::LazyLoad'->Type::Tiny::_install_overloads(
177             q[&{}] => sub {
178 194     194   560 my ( $typename, $function ) = @{ $_[0] };
  194         1623  
179 194         2035 my $type = $meta->get_type( $typename );
180 194         710 my $class = "Types::Standard::$typename";
181 194 50       23387 eval "require $class; 1" or die( $@ );
182            
183             # Majorly break encapsulation for Type::Tiny :-O
184 194         2964 for my $key ( keys %$type ) {
185 3886 100       10546 next unless ref( $type->{$key} ) eq 'Types::Standard::LazyLoad';
186 746         3200 my $f = $type->{$key}[1];
187 746         7097 $type->{$key} = $class->can( "__$f" );
188             }
189 194   66     1712 my $mm = $type->{my_methods} || {};
190 194         805 for my $key ( keys %$mm ) {
191 126 50       488 next unless ref( $mm->{$key} ) eq 'Types::Standard::LazyLoad';
192 126         320 my $f = $mm->{$key}[1];
193 126         731 $mm->{$key} = $class->can( "__$f" );
194             set_subname(
195             sprintf( "%s::my_%s", $type->qualified_name, $key ),
196 126         551 $mm->{$key},
197             );
198             } #/ for my $key ( keys %$mm)
199 194         2001 return $class->can( "__$function" );
200             },
201             );
202             }
203              
204 281     281   2532 no warnings;
  281         641  
  281         31913  
205              
206             BEGIN {
207             *STRICTNUM =
208             $ENV{PERL_TYPES_STANDARD_STRICTNUM}
209             ? sub() { !!1 }
210             : sub() { !!0 }
211 281 50   281   2370682 }
212              
213             my $_any = $meta->$add_core_type(
214             {
215             name => "Any",
216             inlined => sub { "!!1" },
217             complement_name => 'None',
218             type_default => sub { return undef; },
219             }
220             );
221              
222             my $_item = $meta->$add_core_type(
223             {
224             name => "Item",
225             inlined => sub { "!!1" },
226             parent => $_any,
227             }
228             );
229              
230             my $_bool = $meta->$add_core_type(
231             {
232             name => "Bool",
233             parent => $_item,
234             constraint => sub {
235             !ref $_ and ( !defined $_ or $_ eq q() or $_ eq '0' or $_ eq '1' );
236             },
237             inlined => sub {
238             "!ref $_[1] and (!defined $_[1] or $_[1] eq q() or $_[1] eq '0' or $_[1] eq '1')";
239             },
240             type_default => sub { return !!0; },
241             }
242             );
243              
244             $_bool->coercion->add_type_coercions( $_any, q{!!$_} );
245              
246             my $_undef = $meta->$add_core_type(
247             {
248             name => "Undef",
249             parent => $_item,
250             constraint => sub { !defined $_ },
251             inlined => sub { "!defined($_[1])" },
252             type_default => sub { return undef; },
253             }
254             );
255              
256             my $_def = $meta->$add_core_type(
257             {
258             name => "Defined",
259             parent => $_item,
260             constraint => sub { defined $_ },
261             inlined => sub { "defined($_[1])" },
262             complementary_type => $_undef,
263             }
264             );
265              
266             # hackish, but eh
267             Scalar::Util::weaken( $_undef->{complementary_type} ||= $_def );
268              
269             my $_val = $meta->$add_core_type(
270             {
271             name => "Value",
272             parent => $_def,
273             constraint => sub { not ref $_ },
274             inlined => sub { "defined($_[1]) and not ref($_[1])" },
275             }
276             );
277              
278             my $_str = $meta->$add_core_type(
279             {
280             name => "Str",
281             parent => $_val,
282             constraint => sub {
283             ref( \$_ ) eq 'SCALAR' or ref( \( my $val = $_ ) ) eq 'SCALAR';
284             },
285             inlined => sub {
286             "defined($_[1]) and do { ref(\\$_[1]) eq 'SCALAR' or ref(\\(my \$val = $_[1])) eq 'SCALAR' }";
287             },
288             sorter => sub { $_[0] cmp $_[1] },
289             type_default => sub { return ''; },
290             }
291             );
292              
293             my $_laxnum = $meta->add_type(
294             {
295             name => "LaxNum",
296             parent => $_str,
297             constraint => sub { looks_like_number( $_ ) and ref( \$_ ) ne 'GLOB' },
298             inlined => sub {
299             $maybe_load_modules->(
300             qw/ Scalar::Util /,
301             'Scalar::Util'->VERSION ge '1.18' # RT 132426
302             ? "defined($_[1]) && !ref($_[1]) && Scalar::Util::looks_like_number($_[1])"
303             : "defined($_[1]) && !ref($_[1]) && Scalar::Util::looks_like_number($_[1]) && ref(\\($_[1])) ne 'GLOB'"
304             );
305             },
306             sorter => sub { $_[0] <=> $_[1] },
307             type_default => sub { return 0; },
308             }
309             );
310              
311             my $_strictnum = $meta->add_type(
312             {
313             name => "StrictNum",
314             parent => $_str,
315             constraint => sub {
316             my $val = $_;
317             ( $val =~ /\A[+-]?[0-9]+\z/ )
318             || (
319             $val =~ /\A(?:[+-]?) #matches optional +- in the beginning
320             (?=[0-9]|\.[0-9]) #matches previous +- only if there is something like 3 or .3
321             [0-9]* #matches 0-9 zero or more times
322             (?:\.[0-9]+)? #matches optional .89 or nothing
323             (?:[Ee](?:[+-]?[0-9]+))? #matches E1 or e1 or e-1 or e+1 etc
324             \z/x
325             );
326             },
327             inlined => sub {
328             'my $val = '
329             . $_[1] . ';'
330             . Value()->inline_check( '$val' )
331             . ' && ( $val =~ /\A[+-]?[0-9]+\z/ || '
332             . '$val =~ /\A(?:[+-]?) # matches optional +- in the beginning
333             (?=[0-9]|\.[0-9]) # matches previous +- only if there is something like 3 or .3
334             [0-9]* # matches 0-9 zero or more times
335             (?:\.[0-9]+)? # matches optional .89 or nothing
336             (?:[Ee](?:[+-]?[0-9]+))? # matches E1 or e1 or e-1 or e+1 etc
337             \z/x ); '
338             },
339             sorter => sub { $_[0] <=> $_[1] },
340             type_default => sub { return 0; },
341             }
342             );
343              
344             my $_num = $meta->add_type(
345             {
346             name => "Num",
347             parent => ( STRICTNUM ? $_strictnum : $_laxnum ),
348             }
349             );
350              
351             $meta->$add_core_type(
352             {
353             name => "Int",
354             parent => $_num,
355             constraint => sub { /\A-?[0-9]+\z/ },
356             inlined => sub {
357             "do { my \$tmp = $_[1]; defined(\$tmp) and !ref(\$tmp) and \$tmp =~ /\\A-?[0-9]+\\z/ }";
358             },
359             type_default => sub { return 0; },
360             }
361             );
362              
363             my $_classn = $meta->add_type(
364             {
365             name => "ClassName",
366             parent => $_str,
367             constraint => \&_is_class_loaded,
368             inlined => sub {
369             $Type::Tiny::AvoidCallbacks
370             ? "($is_class_loaded)->(do { my \$tmp = $_[1] })"
371             : "Types::Standard::_is_class_loaded(do { my \$tmp = $_[1] })";
372             },
373             }
374             );
375              
376             $meta->add_type(
377             {
378             name => "RoleName",
379             parent => $_classn,
380             constraint => sub { not $_->can( "new" ) },
381             inlined => sub {
382             $Type::Tiny::AvoidCallbacks
383             ? "($is_class_loaded)->(do { my \$tmp = $_[1] }) and not $_[1]\->can('new')"
384             : "Types::Standard::_is_class_loaded(do { my \$tmp = $_[1] }) and not $_[1]\->can('new')";
385             },
386             }
387             );
388              
389             my $_ref = $meta->$add_core_type(
390             {
391             name => "Ref",
392             parent => $_def,
393             constraint => sub { ref $_ },
394             inlined => sub { "!!ref($_[1])" },
395             constraint_generator => sub {
396             return $meta->get_type( 'Ref' ) unless @_;
397            
398             Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Standard', 'Ref', \@_, 1 );
399             my $reftype = shift;
400             $reftype =~
401             /^(SCALAR|ARRAY|HASH|CODE|REF|GLOB|LVALUE|FORMAT|IO|VSTRING|REGEXP|Regexp)$/i
402             or _croak(
403             "Parameter to Ref[`a] expected to be a Perl ref type; got $reftype" );
404            
405             $reftype = "$reftype";
406             return sub {
407             ref( $_[0] ) and Scalar::Util::reftype( $_[0] ) eq $reftype;
408             }
409             },
410             inline_generator => sub {
411             my $reftype = shift;
412             return sub {
413             my $v = $_[1];
414             $maybe_load_modules->(
415             qw/ Scalar::Util /,
416             "ref($v) and Scalar::Util::reftype($v) eq q($reftype)"
417             );
418             };
419             },
420             deep_explanation => sub {
421             require B;
422             my ( $type, $value, $varname ) = @_;
423             my $param = $type->parameters->[0];
424             return if $type->check( $value );
425             my $reftype = Scalar::Util::reftype( $value );
426             return [
427             sprintf(
428             '"%s" constrains reftype(%s) to be equal to %s', $type, $varname,
429             B::perlstring( $param )
430             ),
431             sprintf(
432             'reftype(%s) is %s', $varname,
433             defined( $reftype ) ? B::perlstring( $reftype ) : "undef"
434             ),
435             ];
436             },
437             }
438             );
439              
440             $meta->$add_core_type(
441             {
442             name => "CodeRef",
443             parent => $_ref,
444             constraint => sub { ref $_ eq "CODE" },
445             inlined => sub {
446             _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks
447             ? "Ref::Util::XS::is_plain_coderef($_[1])"
448             : "ref($_[1]) eq 'CODE'";
449             },
450             type_default => sub { return sub {}; },
451             }
452             );
453              
454             my $_regexp = $meta->$add_core_type(
455             {
456             name => "RegexpRef",
457             parent => $_ref,
458             constraint => sub {
459             ref( $_ ) && !!re::is_regexp( $_ ) or blessed( $_ ) && $_->isa( 'Regexp' );
460             },
461             inlined => sub {
462             my $v = $_[1];
463             $maybe_load_modules->(
464             qw/ Scalar::Util re /,
465             "ref($v) && !!re::is_regexp($v) or Scalar::Util::blessed($v) && $v\->isa('Regexp')"
466             );
467             },
468             type_default => sub { return qr//; },
469             }
470             );
471              
472             $meta->$add_core_type(
473             {
474             name => "GlobRef",
475             parent => $_ref,
476             constraint => sub { ref $_ eq "GLOB" },
477             inlined => sub {
478             _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks
479             ? "Ref::Util::XS::is_plain_globref($_[1])"
480             : "ref($_[1]) eq 'GLOB'";
481             },
482             }
483             );
484              
485             $meta->$add_core_type(
486             {
487             name => "FileHandle",
488             parent => $_ref,
489             constraint => sub {
490             ( ref( $_ ) && Scalar::Util::openhandle( $_ ) )
491             or ( blessed( $_ ) && $_->isa( "IO::Handle" ) );
492             },
493             inlined => sub {
494             $maybe_load_modules->(
495             qw/ Scalar::Util /,
496             "(ref($_[1]) && Scalar::Util::openhandle($_[1])) "
497             . "or (Scalar::Util::blessed($_[1]) && $_[1]\->isa(\"IO::Handle\"))"
498             );
499             },
500             }
501             );
502              
503             my $_arr = $meta->$add_core_type(
504             {
505             name => "ArrayRef",
506             parent => $_ref,
507             constraint => sub { ref $_ eq "ARRAY" },
508             inlined => sub {
509             _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks
510             ? "Ref::Util::XS::is_plain_arrayref($_[1])"
511             : "ref($_[1]) eq 'ARRAY'";
512             },
513             constraint_generator => LazyLoad( ArrayRef => 'constraint_generator' ),
514             inline_generator => LazyLoad( ArrayRef => 'inline_generator' ),
515             deep_explanation => LazyLoad( ArrayRef => 'deep_explanation' ),
516             coercion_generator => LazyLoad( ArrayRef => 'coercion_generator' ),
517             type_default => sub { return []; },
518             type_default_generator => sub {
519             return $Type::Tiny::parameterize_type->type_default if @_ < 2;
520             return undef;
521             },
522             }
523             );
524              
525             my $_hash = $meta->$add_core_type(
526             {
527             name => "HashRef",
528             parent => $_ref,
529             constraint => sub { ref $_ eq "HASH" },
530             inlined => sub {
531             _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks
532             ? "Ref::Util::XS::is_plain_hashref($_[1])"
533             : "ref($_[1]) eq 'HASH'";
534             },
535             constraint_generator => LazyLoad( HashRef => 'constraint_generator' ),
536             inline_generator => LazyLoad( HashRef => 'inline_generator' ),
537             deep_explanation => LazyLoad( HashRef => 'deep_explanation' ),
538             coercion_generator => LazyLoad( HashRef => 'coercion_generator' ),
539             type_default => sub { return {}; },
540             type_default_generator => sub {
541             return $Type::Tiny::parameterize_type->type_default if @_ < 2;
542             return undef;
543             },
544             my_methods => {
545             hashref_allows_key => LazyLoad( HashRef => 'hashref_allows_key' ),
546             hashref_allows_value => LazyLoad( HashRef => 'hashref_allows_value' ),
547             },
548             }
549             );
550              
551             $meta->$add_core_type(
552             {
553             name => "ScalarRef",
554             parent => $_ref,
555             constraint => sub { ref $_ eq "SCALAR" or ref $_ eq "REF" },
556             inlined => sub { "ref($_[1]) eq 'SCALAR' or ref($_[1]) eq 'REF'" },
557             constraint_generator => LazyLoad( ScalarRef => 'constraint_generator' ),
558             inline_generator => LazyLoad( ScalarRef => 'inline_generator' ),
559             deep_explanation => LazyLoad( ScalarRef => 'deep_explanation' ),
560             coercion_generator => LazyLoad( ScalarRef => 'coercion_generator' ),
561             type_default => sub { my $x; return \$x; },
562             }
563             );
564              
565             my $_obj = $meta->$add_core_type(
566             {
567             name => "Object",
568             parent => $_ref,
569             constraint => sub { blessed $_ },
570             inlined => sub {
571             _HAS_REFUTILXS && !$Type::Tiny::AvoidCallbacks
572             ? "Ref::Util::XS::is_blessed_ref($_[1])"
573             : $maybe_load_modules->(
574             'Scalar::Util',
575             "Scalar::Util::blessed($_[1])"
576             );
577             },
578             is_object => 1,
579             }
580             );
581              
582             $meta->$add_core_type(
583             {
584             name => "Maybe",
585             parent => $_item,
586             constraint_generator => sub {
587             return $meta->get_type( 'Maybe' ) unless @_;
588            
589             Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Standard', 'Maybe', \@_, 1 );
590             my $param = Types::TypeTiny::to_TypeTiny( shift );
591             Types::TypeTiny::is_TypeTiny( $param )
592             or _croak(
593             "Parameter to Maybe[`a] expected to be a type constraint; got $param" );
594            
595             my $param_compiled_check = $param->compiled_check;
596             my @xsub;
597             if ( Type::Tiny::_USE_XS ) {
598             my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
599             push @xsub, Type::Tiny::XS::get_coderef_for( "Maybe[$paramname]" )
600             if $paramname;
601             }
602             elsif ( Type::Tiny::_USE_MOUSE and $param->_has_xsub ) {
603             require Mouse::Util::TypeConstraints;
604             my $maker = "Mouse::Util::TypeConstraints"->can( "_parameterize_Maybe_for" );
605             push @xsub, $maker->( $param ) if $maker;
606             }
607            
608             return (
609             sub {
610             my $value = shift;
611             return !!1 unless defined $value;
612             return $param->check( $value );
613             },
614             @xsub,
615             );
616             },
617             inline_generator => sub {
618             my $param = shift;
619            
620             my $param_compiled_check = $param->compiled_check;
621             my $xsubname;
622             if ( Type::Tiny::_USE_XS ) {
623             my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
624             $xsubname = Type::Tiny::XS::get_subname_for( "Maybe[$paramname]" );
625             }
626            
627             return unless $param->can_be_inlined;
628             return sub {
629             my $v = $_[1];
630             return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
631             my $param_check = $param->inline_check( $v );
632             "!defined($v) or $param_check";
633             };
634             },
635             deep_explanation => sub {
636             my ( $type, $value, $varname ) = @_;
637             my $param = $type->parameters->[0];
638            
639             return [
640             sprintf( '%s is defined', Type::Tiny::_dd( $value ) ),
641             sprintf(
642             '"%s" constrains the value with "%s" if it is defined', $type, $param
643             ),
644             @{ $param->validate_explain( $value, $varname ) },
645             ];
646             },
647             coercion_generator => sub {
648             my ( $parent, $child, $param ) = @_;
649             return unless $param->has_coercion;
650             return $param->coercion;
651             },
652             type_default => sub { return undef; },
653             type_default_generator => sub {
654             $_[0]->type_default || $Type::Tiny::parameterize_type->type_default ;
655             },
656             }
657             );
658              
659             my $_map = $meta->$add_core_type(
660             {
661             name => "Map",
662             parent => $_hash,
663             constraint_generator => LazyLoad( Map => 'constraint_generator' ),
664             inline_generator => LazyLoad( Map => 'inline_generator' ),
665             deep_explanation => LazyLoad( Map => 'deep_explanation' ),
666             coercion_generator => LazyLoad( Map => 'coercion_generator' ),
667             my_methods => {
668             hashref_allows_key => LazyLoad( Map => 'hashref_allows_key' ),
669             hashref_allows_value => LazyLoad( Map => 'hashref_allows_value' ),
670             },
671             type_default_generator => sub {
672             return $Type::Tiny::parameterize_type->type_default;
673             },
674             }
675             );
676              
677             my $_Optional = $meta->add_type(
678             {
679             name => "Optional",
680             parent => $_item,
681             constraint_generator => sub {
682             return $meta->get_type( 'Optional' ) unless @_;
683            
684             Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Standard', 'Optional', \@_, 1 );
685             my $param = Types::TypeTiny::to_TypeTiny( shift );
686             Types::TypeTiny::is_TypeTiny( $param )
687             or _croak(
688             "Parameter to Optional[`a] expected to be a type constraint; got $param" );
689            
690             sub { $param->check( $_[0] ) }
691             },
692             inline_generator => sub {
693             my $param = shift;
694             return unless $param->can_be_inlined;
695             return sub {
696             my $v = $_[1];
697             $param->inline_check( $v );
698             };
699             },
700             deep_explanation => sub {
701             my ( $type, $value, $varname ) = @_;
702             my $param = $type->parameters->[0];
703            
704             return [
705             sprintf( '%s exists', $varname ),
706             sprintf( '"%s" constrains %s with "%s" if it exists', $type, $varname, $param ),
707             @{ $param->validate_explain( $value, $varname ) },
708             ];
709             },
710             coercion_generator => sub {
711             my ( $parent, $child, $param ) = @_;
712             return unless $param->has_coercion;
713             return $param->coercion;
714             },
715             type_default_generator => sub {
716             return $_[0]->type_default;
717             },
718             }
719             );
720              
721             my $_slurpy;
722             $_slurpy = $meta->add_type(
723             {
724             name => "Slurpy",
725             slurpy => 1,
726             parent => $_item,
727             constraint_generator => sub {
728             my $self = $_slurpy;
729            
730             Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Standard', 'Slurpy', \@_, 1 );
731             my $param = @_ ? Types::TypeTiny::to_TypeTiny(shift) : $_any;
732             Types::TypeTiny::is_TypeTiny( $param )
733             or _croak(
734             "Parameter to Slurpy[`a] expected to be a type constraint; got $param" );
735            
736             return $self->create_child_type(
737             slurpy => 1,
738             display_name => $self->name_generator->( $self, $param ),
739             parameters => [ $param ],
740             constraint => sub { $param->check( $_[0] ) },
741             type_default => $param->type_default,
742             _build_coercion => sub {
743             my $coercion = shift;
744             $coercion->add_type_coercions( @{ $param->coercion->type_coercion_map } )
745             if $param->has_coercion;
746             $coercion->freeze;
747             },
748             $param->can_be_inlined
749             ? ( inlined => sub { $param->inline_check( $_[1] ) } )
750             : (),
751             );
752             },
753             deep_explanation => sub {
754             my ( $type, $value, $varname ) = @_;
755             my $param = $type->parameters->[0];
756             return [
757             sprintf( '%s is slurpy', $varname ),
758             @{ $param->validate_explain( $value, $varname ) },
759             ];
760             },
761             my_methods => {
762             'unslurpy' => sub {
763             my $self = shift;
764             $self->{_my_unslurpy} ||= $self->find_parent(
765             sub { $_->parent->{uniq} == $_slurpy->{uniq} }
766             )->type_parameter;
767             },
768             'slurp_into' => sub {
769             my $self = shift;
770             my $parameters = $self->find_parent(
771             sub { $_->parent->{uniq} == $_slurpy->{uniq} }
772             )->parameters;
773             if ( $parameters->[1] ) {
774             return $parameters->[1];
775             }
776             my $constraint = $parameters->[0];
777             return 'HASH'
778             if $constraint->is_a_type_of( HashRef() )
779             or $constraint->is_a_type_of( Map() )
780             or $constraint->is_a_type_of( Dict() );
781             return 'ARRAY';
782             },
783             },
784             }
785             );
786              
787             sub slurpy {
788 97     97 1 7069 my $t = shift;
789 97         598 my $s = $_slurpy->of( $t );
790 95   50     510 $s->{slurpy} ||= 1;
791 95 100       938 wantarray ? ( $s, @_ ) : $s;
792             }
793              
794             $meta->$add_core_type(
795             {
796             name => "Tuple",
797             parent => $_arr,
798             name_generator => sub {
799             my ( $s, @a ) = @_;
800             sprintf( '%s[%s]', $s, join q[,], @a );
801             },
802             constraint_generator => LazyLoad( Tuple => 'constraint_generator' ),
803             inline_generator => LazyLoad( Tuple => 'inline_generator' ),
804             deep_explanation => LazyLoad( Tuple => 'deep_explanation' ),
805             coercion_generator => LazyLoad( Tuple => 'coercion_generator' ),
806             }
807             );
808              
809             $meta->add_type(
810             {
811             name => "CycleTuple",
812             parent => $_arr,
813             name_generator => sub {
814             my ( $s, @a ) = @_;
815             sprintf( '%s[%s]', $s, join q[,], @a );
816             },
817             constraint_generator => LazyLoad( CycleTuple => 'constraint_generator' ),
818             inline_generator => LazyLoad( CycleTuple => 'inline_generator' ),
819             deep_explanation => LazyLoad( CycleTuple => 'deep_explanation' ),
820             coercion_generator => LazyLoad( CycleTuple => 'coercion_generator' ),
821             }
822             );
823              
824             $meta->add_type(
825             {
826             name => "Dict",
827             parent => $_hash,
828             name_generator => sub {
829             my ( $s, @p ) = @_;
830             my $l = @p
831             && Types::TypeTiny::is_TypeTiny( $p[-1] )
832             && $p[-1]->is_strictly_a_type_of( Types::Standard::Slurpy() )
833             ? pop(@p)
834             : undef;
835             my %a = @p;
836             sprintf(
837             '%s[%s%s]', $s,
838             join( q[,], map sprintf( "%s=>%s", $_, $a{$_} ), sort keys %a ),
839             $l ? ",$l" : ''
840             );
841             },
842             constraint_generator => LazyLoad( Dict => 'constraint_generator' ),
843             inline_generator => LazyLoad( Dict => 'inline_generator' ),
844             deep_explanation => LazyLoad( Dict => 'deep_explanation' ),
845             coercion_generator => LazyLoad( Dict => 'coercion_generator' ),
846             my_methods => {
847             dict_is_slurpy => LazyLoad( Dict => 'dict_is_slurpy' ),
848             hashref_allows_key => LazyLoad( Dict => 'hashref_allows_key' ),
849             hashref_allows_value => LazyLoad( Dict => 'hashref_allows_value' ),
850             },
851             }
852             );
853              
854             $meta->add_type(
855             {
856             name => "Overload",
857             parent => $_obj,
858             constraint => sub { require overload; overload::Overloaded( $_ ) },
859             inlined => sub {
860             $maybe_load_modules->(
861             qw/ Scalar::Util overload /,
862             $INC{'overload.pm'}
863             ? "Scalar::Util::blessed($_[1]) and overload::Overloaded($_[1])"
864             : "Scalar::Util::blessed($_[1]) and do { use overload (); overload::Overloaded($_[1]) }"
865             );
866             },
867             constraint_generator => sub {
868             return $meta->get_type( 'Overload' ) unless @_;
869            
870             my @operations = map {
871             Types::TypeTiny::is_StringLike( $_ )
872             ? "$_"
873             : _croak( "Parameters to Overload[`a] expected to be a strings; got $_" );
874             } @_;
875            
876             require overload;
877             return sub {
878             my $value = shift;
879             for my $op ( @operations ) {
880             return unless overload::Method( $value, $op );
881             }
882             return !!1;
883             }
884             },
885             inline_generator => sub {
886             my @operations = @_;
887             return sub {
888             require overload;
889             my $v = $_[1];
890             $maybe_load_modules->(
891             qw/ Scalar::Util overload /,
892             join " and ",
893             "Scalar::Util::blessed($v)",
894             map "overload::Method($v, q[$_])", @operations
895             );
896             };
897             },
898             is_object => 1,
899             }
900             );
901              
902             $meta->add_type(
903             {
904             name => "StrMatch",
905             parent => $_str,
906             constraint_generator => LazyLoad( StrMatch => 'constraint_generator' ),
907             inline_generator => LazyLoad( StrMatch => 'inline_generator' ),
908             }
909             );
910              
911             $meta->add_type(
912             {
913             name => "OptList",
914             parent => $_arr,
915             constraint => sub {
916             for my $inner ( @$_ ) {
917             return unless ref( $inner ) eq q(ARRAY);
918             return unless @$inner == 2;
919             return unless is_Str( $inner->[0] );
920             }
921             return !!1;
922             },
923             inlined => sub {
924             my ( $self, $var ) = @_;
925             my $Str_check = Str()->inline_check( '$inner->[0]' );
926             my @code = 'do { my $ok = 1; ';
927             push @code, sprintf( 'for my $inner (@{%s}) { no warnings; ', $var );
928             push @code,
929             sprintf(
930             '($ok=0) && last unless ref($inner) eq q(ARRAY) && @$inner == 2 && (%s); ',
931             $Str_check
932             );
933             push @code, '} ';
934             push @code, '$ok }';
935             return ( undef, join( q( ), @code ) );
936             },
937             type_default => sub { return [] },
938             }
939             );
940              
941             $meta->add_type(
942             {
943             name => "Tied",
944             parent => $_ref,
945             constraint => sub {
946             !!tied(
947             Scalar::Util::reftype( $_ ) eq 'HASH' ? %{$_}
948             : Scalar::Util::reftype( $_ ) eq 'ARRAY' ? @{$_}
949             : Scalar::Util::reftype( $_ ) =~ /^(SCALAR|REF)$/ ? ${$_}
950             : undef
951             );
952             },
953             inlined => sub {
954             my ( $self, $var ) = @_;
955             $maybe_load_modules->(
956             qw/ Scalar::Util /,
957             $self->parent->inline_check( $var )
958             . " and !!tied(Scalar::Util::reftype($var) eq 'HASH' ? \%{$var} : Scalar::Util::reftype($var) eq 'ARRAY' ? \@{$var} : Scalar::Util::reftype($var) =~ /^(SCALAR|REF)\$/ ? \${$var} : undef)"
959             );
960             },
961             name_generator => sub {
962             my $self = shift;
963             my $param = Types::TypeTiny::to_TypeTiny( shift );
964             unless ( Types::TypeTiny::is_TypeTiny( $param ) ) {
965             Types::TypeTiny::is_StringLike( $param )
966             or _croak( "Parameter to Tied[`a] expected to be a class name; got $param" );
967             require B;
968             return sprintf( "%s[%s]", $self, B::perlstring( $param ) );
969             }
970             return sprintf( "%s[%s]", $self, $param );
971             },
972             constraint_generator => LazyLoad( Tied => 'constraint_generator' ),
973             inline_generator => LazyLoad( Tied => 'inline_generator' ),
974             }
975             );
976              
977             $meta->add_type(
978             {
979             name => "InstanceOf",
980             parent => $_obj,
981             constraint_generator => sub {
982             return $meta->get_type( 'InstanceOf' ) unless @_;
983             require Type::Tiny::Class;
984             my @classes = map {
985             Types::TypeTiny::is_TypeTiny( $_ )
986             ? $_
987             : "Type::Tiny::Class"->new(
988             class => $_,
989             display_name => sprintf( 'InstanceOf[%s]', B::perlstring( $_ ) )
990             )
991             } @_;
992             return $classes[0] if @classes == 1;
993            
994             require B;
995             require Type::Tiny::Union;
996             return "Type::Tiny::Union"->new(
997             type_constraints => \@classes,
998             display_name => sprintf(
999             'InstanceOf[%s]', join q[,], map B::perlstring( $_->class ), @classes
1000             ),
1001             );
1002             },
1003             }
1004             );
1005              
1006             $meta->add_type(
1007             {
1008             name => "ConsumerOf",
1009             parent => $_obj,
1010             constraint_generator => sub {
1011             return $meta->get_type( 'ConsumerOf' ) unless @_;
1012             require B;
1013             require Type::Tiny::Role;
1014             my @roles = map {
1015             Types::TypeTiny::is_TypeTiny( $_ )
1016             ? $_
1017             : "Type::Tiny::Role"->new(
1018             role => $_,
1019             display_name => sprintf( 'ConsumerOf[%s]', B::perlstring( $_ ) )
1020             )
1021             } @_;
1022             return $roles[0] if @roles == 1;
1023            
1024             require Type::Tiny::Intersection;
1025             return "Type::Tiny::Intersection"->new(
1026             type_constraints => \@roles,
1027             display_name => sprintf(
1028             'ConsumerOf[%s]', join q[,], map B::perlstring( $_->role ), @roles
1029             ),
1030             );
1031             },
1032             }
1033             );
1034              
1035             $meta->add_type(
1036             {
1037             name => "HasMethods",
1038             parent => $_obj,
1039             constraint_generator => sub {
1040             return $meta->get_type( 'HasMethods' ) unless @_;
1041             require B;
1042             require Type::Tiny::Duck;
1043             return "Type::Tiny::Duck"->new(
1044             methods => \@_,
1045             display_name =>
1046             sprintf( 'HasMethods[%s]', join q[,], map B::perlstring( $_ ), @_ ),
1047             );
1048             },
1049             }
1050             );
1051              
1052             $meta->add_type(
1053             {
1054             name => "Enum",
1055             parent => $_str,
1056             constraint_generator => sub {
1057             return $meta->get_type( 'Enum' ) unless @_;
1058             my $coercion;
1059             if ( ref( $_[0] ) and ref( $_[0] ) eq 'SCALAR' ) {
1060             $coercion = ${ +shift };
1061             }
1062             elsif ( ref( $_[0] ) && !blessed( $_[0] )
1063             or blessed( $_[0] ) && $_[0]->isa( 'Type::Coercion' ) )
1064             {
1065             $coercion = shift;
1066             }
1067             require B;
1068             require Type::Tiny::Enum;
1069             return "Type::Tiny::Enum"->new(
1070             values => \@_,
1071             display_name => sprintf( 'Enum[%s]', join q[,], map B::perlstring( $_ ), @_ ),
1072             $coercion ? ( coercion => $coercion ) : (),
1073             );
1074             },
1075             type_default => undef,
1076             }
1077             );
1078              
1079             $meta->add_coercion(
1080             {
1081             name => "MkOpt",
1082             type_constraint => $meta->get_type( "OptList" ),
1083             type_coercion_map => [
1084             $_arr, q{ Exporter::Tiny::mkopt($_) },
1085             $_hash, q{ Exporter::Tiny::mkopt($_) },
1086             $_undef, q{ [] },
1087             ],
1088             }
1089             );
1090              
1091             $meta->add_coercion(
1092             {
1093             name => "Join",
1094             type_constraint => $_str,
1095             coercion_generator => sub {
1096             my ( $self, $target, $sep ) = @_;
1097             Types::TypeTiny::is_StringLike( $sep )
1098             or _croak( "Parameter to Join[`a] expected to be a string; got $sep" );
1099             require B;
1100             $sep = B::perlstring( $sep );
1101             return ( ArrayRef(), qq{ join($sep, \@\$_) } );
1102             },
1103             }
1104             );
1105              
1106             $meta->add_coercion(
1107             {
1108             name => "Split",
1109             type_constraint => $_arr,
1110             coercion_generator => sub {
1111             my ( $self, $target, $re ) = @_;
1112             ref( $re ) eq q(Regexp)
1113             or _croak(
1114             "Parameter to Split[`a] expected to be a regular expression; got $re" );
1115             my $regexp_string = "$re";
1116             $regexp_string =~ s/\\\//\\\\\//g; # toothpicks
1117             return ( Str(), qq{ [split /$regexp_string/, \$_] } );
1118             },
1119             }
1120             );
1121              
1122             __PACKAGE__->meta->make_immutable;
1123              
1124             1;
1125              
1126             __END__