File Coverage

blib/lib/Type/Params/Signature.pm
Criterion Covered Total %
statement 587 613 95.7
branch 266 314 84.7
condition 125 179 69.8
subroutine 88 90 97.7
pod 41 45 91.1
total 1107 1241 89.2


line stmt bran cond sub pod time code
1             package Type::Params::Signature;
2              
3 75     75   2597 use 5.008001;
  75         312  
4 75     75   874 use strict;
  75         222  
  75         2148  
5 75     75   2135 use warnings;
  75         236  
  75         7000  
6              
7             BEGIN {
8 75 50   75   5636 if ( $] < 5.010 ) { require Devel::TypeTiny::Perl58Compat }
  11         99  
9             }
10              
11             BEGIN {
12 75     75   324 $Type::Params::Signature::AUTHORITY = 'cpan:TOBYINK';
13 75         5416 $Type::Params::Signature::VERSION = '2.010001';
14             }
15              
16             $Type::Params::Signature::VERSION =~ tr/_//d;
17              
18 75     73   582 use B ();
  75         453  
  75         3307  
19 73     73   40184 use Eval::TypeTiny::CodeAccumulator;
  73         255  
  73         3575  
20 73     73   716 use Types::Standard qw( -is -types -assert );
  73         200  
  73         2940  
21 73     73   14436 use Types::TypeTiny qw( -is -types to_TypeTiny );
  73         268  
  73         2706  
22 73     73   190627 use Type::Params::Parameter;
  73         338  
  73         70097  
23              
24             my $Attrs = Enum[ qw/
25             caller_level package subname description _is_signature_for ID
26             method head tail parameters slurpy
27             message on_die next fallback strictness is_named allow_dash method_invocant
28             bless class constructor named_to_list list_to_named oo_trace
29             class_prefix class_attributes
30             returns_scalar returns_list
31             want_details want_object want_source can_shortcut coderef
32             quux mite_signature is_wrapper
33             / ]; # quux for reasons
34              
35             sub _croak {
36 18     18   152 require Error::TypeTiny;
37 18         121 return Error::TypeTiny::croak( pop );
38             }
39              
40             sub _new_parameter {
41 801     801   1974 shift;
42 801         4293 'Type::Params::Parameter'->new( @_ );
43             }
44              
45             sub _new_code_accumulator {
46 412     412   891 shift;
47 412         4433 'Eval::TypeTiny::CodeAccumulator'->new( @_ );
48             }
49              
50             sub new {
51 336     336 1 850 my $class = shift;
52 336 50       4806 my %self = @_ == 1 ? %{$_[0]} : @_;
  5         1104  
53 336         1034 my $self = bless \%self, $class;
54 336   50     1760 $self->{parameters} ||= [];
55 336   50     3568 $self->{class_prefix} ||= 'Type::Params::OO::Klass';
56 336 100 33     1224 $self->{next} ||= delete $self->{goto_next} if exists $self->{goto_next};
57 336         1587 $self->BUILD;
58 329 100       6272 $Attrs->all( sort keys %$self ) or do {
59 6         39 require Carp;
60 6         16 require Type::Utils;
61 6         146 my @bad = ( ~ $Attrs )->grep( sort keys %$self );
62 6 100       42 Carp::carp( sprintf(
63             "Warning: unrecognized signature %s: %s, continuing anyway",
64             @bad == 1 ? 'option' : 'options',
65             Type::Utils::english_list( @bad ),
66             ) );
67             };
68 327         1362 return $self;
69             }
70              
71             {
72             my $klass_id;
73             my %klass_cache;
74             sub BUILD {
75 334     334 1 1306 my $self = shift;
76              
77 334 100 100     3525 if ( $self->{named_to_list} and not is_ArrayRef $self->{named_to_list} ) {
78 15         35 $self->{named_to_list} = [ map $_->name, @{ $self->{parameters} } ];
  15         742  
79             }
80              
81 334 50       1261 if ( delete $self->{rationalize_slurpies} ) {
82 334         1315 $self->_rationalize_slurpies;
83             }
84              
85 329 100       4953 if ( $self->{method} ) {
86 41         141 my $type = $self->{method};
87             $type =
88             is_Int($type) ? Defined :
89 41 0       316 is_Str($type) ? do { require Type::Utils; Type::Utils::dwim_type( $type, $self->{package} ? ( for => $self->{package} ) : () ) } :
  3 50       410  
  3 100       24  
90             to_TypeTiny( $type );
91 41   50     208 unshift @{ $self->{head} ||= [] }, $self->_new_parameter(
  41         595  
92             name => 'invocant',
93             type => $type,
94             );
95             }
96              
97 329         1733 $self->_rationalize_returns;
98              
99 329 100 100     8127 if ( defined $self->{bless} and is_BoolLike $self->{bless} and $self->{bless} and not $self->{named_to_list} ) {
      100        
      100        
100 52         1645 my $klass_key = $self->_klass_key;
101 52   66     3425 $self->{bless} = ( $klass_cache{$klass_key} ||= sprintf( '%s%d', $self->{class_prefix}, ++$klass_id ) );
102 52 100       272 $self->{oo_trace} = 1 unless exists $self->{oo_trace};
103 52         749 $self->make_class;
104             }
105 327 100       5430 if ( is_ArrayRef $self->{class} ) {
106 11         39 $self->{constructor} = $self->{class}->[1];
107 11         658 $self->{class} = $self->{class}->[0];
108             }
109             }
110             }
111              
112             sub _klass_key {
113 52     52   124 my $self = shift;
114              
115 52         121 my @parameters = @{ $self->parameters };
  52         567  
116 51 100       223 if ( $self->has_slurpy ) {
117 3         6 push @parameters, $self->slurpy;
118             }
119              
120 73     69   2730 no warnings 'uninitialized';
  73         379  
  73         615351  
121             join(
122             '|',
123             map sprintf( '%s*%s*%s', $_->name, $_->getter, $_->predicate ),
124 51         363 sort { $a->{name} cmp $b->{name} } @parameters
  62         366  
125             );
126             }
127              
128             sub _rationalize_slurpies {
129 333     334   782 my $self = shift;
130              
131 333         1424 my $parameters = $self->parameters;
132              
133 333 100       1224 if ( $self->is_named ) {
    100          
134 179         420 my ( @slurpy, @rest );
135              
136 179         843 for my $parameter ( @$parameters ) {
137 424 100       1817 if ( $parameter->type->is_strictly_a_type_of( Slurpy ) ) {
    100          
138 28         113 push @slurpy, $parameter;
139             }
140             elsif ( $parameter->{slurpy} ) {
141 3         342 $parameter->{type} = Slurpy[ $parameter->type ];
142 3         16 push @slurpy, $parameter;
143             }
144             else {
145 397         1742 push @rest, $parameter;
146             }
147             }
148              
149 179 100       1228 if ( @slurpy == 1 ) {
    100          
150 25         124 my $constraint = $slurpy[0]->type;
151 25 100 66     138 if ( $constraint->type_parameter && $constraint->type_parameter->{uniq} == Any->{uniq} or $constraint->my_slurp_into eq 'HASH' ) {
      100        
152 24         133 $self->{slurpy} = $slurpy[0];
153 24         118 @$parameters = @rest;
154             }
155             else {
156 1         6 $self->_croak( 'Signatures with named parameters can only have slurpy parameters which are a subtype of HashRef' );
157             }
158             }
159             elsif ( @slurpy ) {
160 1         6 $self->_croak( 'Found multiple slurpy parameters! There can be only one' );
161             }
162             }
163             elsif ( @$parameters ) {
164 151 100       770 if ( $parameters->[-1]->type->is_strictly_a_type_of( Slurpy ) ) {
    100          
165 40         206 $self->{slurpy} = pop @$parameters;
166             }
167             elsif ( $parameters->[-1]{slurpy} ) {
168 7         44 $self->{slurpy} = pop @$parameters;
169 7         45 $self->{slurpy}{type} = Slurpy[ $self->{slurpy}{type} ];
170             }
171              
172 151         604 for my $parameter ( @$parameters ) {
173 214 100 66     977 if ( $parameter->type->is_strictly_a_type_of( Slurpy ) or $parameter->{slurpy} ) {
174 3         17 $self->_croak( 'Parameter following slurpy parameter' );
175             }
176             }
177             }
178              
179 326 100 100     1896 if ( $self->{slurpy} and $self->{slurpy}->has_default ) {
180 1         6 require Carp;
181 1         3 our @CARP_NOT = ( __PACKAGE__, 'Type::Params' );
182 1         166 Carp::carp( "Warning: the default for the slurpy parameter will be ignored, continuing anyway" );
183 1         8 delete $self->{slurpy}{default};
184             }
185            
186 326 100 100     2012 if ( $self->{slurpy} and $self->{slurpy}->optional ) {
187 1         10 require Carp;
188 1         5 our @CARP_NOT = ( __PACKAGE__, 'Type::Params' );
189 1         267 Carp::carp( "Warning: the optional for the slurpy parameter will be ignored, continuing anyway" );
190 1         14 delete $self->{slurpy}{optional};
191             }
192             }
193              
194             sub _rationalize_returns {
195 348     351   893 my $self = shift;
196            
197             my $typify = sub {
198 131     134   272 my $ref = shift;
199 131 100       406 if ( is_Str $$ref ) {
200 1         9 require Type::Utils;
201 1 50       37 $$ref = Type::Utils::dwim_type( $$ref, $self->{package} ? ( for => $self->{package} ) : () );
202             }
203             else {
204 130         449 $$ref = to_TypeTiny( $$ref );
205             }
206 348         2694 };
207            
208 348 100       1644 if ( my $r = delete $self->{returns} ) {
209 7         43 $typify->( \ $r );
210 7   33     90 $self->{returns_scalar} ||= $r;
211 7   33     74 $self->{returns_list} ||= ArrayRef->of( $r );
212             }
213              
214             exists $self->{$_} && $typify->( \ $self->{$_} )
215 348   66     2415 for qw/ returns_scalar returns_list /;
216            
217 348         2673 return $self;
218             }
219              
220             sub _parameters_from_list {
221 370     373   1975 my ( $class, $style, $list, %opts ) = @_;
222 370         744 my @return;
223 370         869 my $is_named = ( $style eq 'named' );
224              
225 370         1256 while ( @$list ) {
226 758         1476 my ( $type, %param_opts );
227 758 100       2254 if ( $is_named ) {
228 422         1822 $param_opts{name} = assert_Str( shift( @$list ) );
229             }
230 758 100 66     7972 if ( is_HashRef $list->[0] and exists $list->[0]{slurpy} and not is_Bool $list->[0]{slurpy} ) {
      33        
231 2         4 my %new_opts = %{ shift( @$list ) };
  2         9  
232 2         7 $type = delete $new_opts{slurpy};
233 2         6 %param_opts = ( %param_opts, %new_opts, slurpy => 1 );
234             }
235             else {
236 756         1687 $type = shift( @$list );
237             }
238 758 100       3365 if ( is_HashRef( $list->[0] ) ) {
239 74 100 100     364 unless ( exists $list->[0]{slurpy} and not is_Bool $list->[0]{slurpy} ) {
240 72         197 %param_opts = ( %param_opts, %{ +shift( @$list ) } );
  72         331  
241             }
242             }
243             $param_opts{type} =
244 4         13 is_Int($type) ? ( $type ? Any : do { $param_opts{optional} = !!1; Any; } ) :
  4         17  
245 758 100       5787 is_Str($type) ? do { require Type::Utils; Type::Utils::dwim_type( $type, $opts{package} ? ( for => $opts{package} ) : () ) } :
  2 50       37  
  2 100       20  
    100          
246             to_TypeTiny( $type );
247 758         3738 my $parameter = $class->_new_parameter( %param_opts );
248 758         4099 push @return, $parameter;
249             }
250              
251 370         2182 return \@return;
252             }
253              
254             sub new_from_compile {
255 331     334 1 449302 my $class = shift;
256 331         762 my $style = shift;
257 331         832 my $is_named = ( $style eq 'named' );
258              
259 331         811 my %opts = ();
260 331   66     3014 while ( is_HashRef $_[0] and not exists $_[0]{slurpy} ) {
261 423         1060 %opts = ( %opts, %{ +shift } );
  423         7274  
262             }
263              
264 331         1001 for my $pos ( qw/ head tail / ) {
265 662 100       6288 next unless defined $opts{$pos};
266 39 100       156 if ( is_Int( $opts{$pos} ) ) {
267 6         29 $opts{$pos} = [ ( Any ) x $opts{$pos} ];
268             }
269 39         230 $opts{$pos} = $class->_parameters_from_list( positional => $opts{$pos}, %opts );
270             }
271              
272 331         1270 my $list = [ @_ ];
273 331         1136 $opts{is_named} = $is_named;
274 331         1886 $opts{parameters} = $class->_parameters_from_list( $style => $list, %opts );
275              
276 331         2242 my $self = $class->new( %opts, rationalize_slurpies => 1 );
277 324         3122 return $self;
278             }
279              
280             sub new_from_v2api {
281 356     359 1 1175 my ( $class, $opts ) = @_;
282              
283 356   100     2237 my $positional = delete( $opts->{positional} ) || delete( $opts->{pos} );
284 356         981 my $named = delete( $opts->{named} );
285 356   100     2225 my $multiple = delete( $opts->{multiple} ) || delete( $opts->{multi} );
286              
287 356 100 100     2387 $class->_croak( "Signature must be positional, named, or multiple" )
      100        
288             unless $positional || $named || $multiple;
289              
290 354 100       1248 if ( $multiple ) {
291 22 100       187 if ( is_HashRef $multiple ) {
    100          
292 1         4 my @tmp;
293 1         8 while ( my ( $name, $alt ) = each %$multiple ) {
294 6 50       50 push @tmp,
    50          
    100          
295             is_HashRef($alt) ? { ID => $name, %$alt } :
296             is_ArrayRef($alt) ? { ID => $name, pos => $alt } :
297             is_CodeRef($alt) ? { ID => $name, closure => $alt } :
298             $class->_croak( "Bad alternative in multiple signature" );
299             }
300 1         9 $multiple = \@tmp;
301             }
302             elsif ( not is_ArrayRef $multiple ) {
303 2         7 $multiple = [];
304             }
305 22 100       100 unshift @$multiple, { positional => $positional } if $positional;
306 22 100       67 unshift @$multiple, { named => $named } if $named;
307 22         4407 require Type::Params::Alternatives;
308 22         226 return 'Type::Params::Alternatives'->new(
309             base_options => $opts,
310             alternatives => $multiple,
311             sig_class => $class,
312             );
313             }
314              
315 332         980 my ( $sig_kind, $args ) = ( pos => $positional );
316 332 100       1135 if ( $named ) {
317 178 100       663 $opts->{bless} = 1 unless exists $opts->{bless};
318 178         447 ( $sig_kind, $args ) = ( named => $named );
319 178 100       633 $class->_croak( "Signature cannot have both positional and named arguments" )
320             if $positional;
321             }
322              
323 330         1671 return $class->new_from_compile( $sig_kind, $opts, @$args );
324             }
325              
326 683     686 1 4556 sub package { $_[0]{package} }
327 685     688 1 5784 sub subname { $_[0]{subname} }
328 344     346 1 2298 sub description { $_[0]{description} } sub has_description { exists $_[0]{description} }
  0     2 1 0  
329 344     346 1 1529 sub method { $_[0]{method} }
330 1575     1577 1 5718 sub head { $_[0]{head} } sub has_head { exists $_[0]{head} }
  387     389 1 2956  
331 1361     1361 1 4114 sub tail { $_[0]{tail} } sub has_tail { exists $_[0]{tail} }
  64     64 1 176  
332 1     1 1 426 sub parameters { $_[0]{parameters} } sub has_parameters { exists $_[0]{parameters} }
  1288     1288 1 9378  
333 876     876 1 3414 sub slurpy { $_[0]{slurpy} } sub has_slurpy { exists $_[0]{slurpy} }
  244     244 1 1598  
334 1959     1959 1 13944 sub on_die { $_[0]{on_die} } sub has_on_die { exists $_[0]{on_die} }
  7     7 1 32  
335 1386     1386 1 4581 sub strictness { $_[0]{strictness} } sub has_strictness { exists $_[0]{strictness} }
  949     949 1 5295  
336 712     712 1 3715 sub next { $_[0]{next} }
337 0     0 1 0 sub goto_next { $_[0]{next} }
338 2207     2207 1 8678 sub is_named { $_[0]{is_named} }
339 590     590 1 1231 sub allow_dash { $_[0]{allow_dash} }
340 710     710 1 3683 sub bless { $_[0]{bless} }
341 182     182 1 714 sub class { $_[0]{class} }
342 24     24 1 149 sub constructor { $_[0]{constructor} }
343 209     209 1 1077 sub named_to_list { $_[0]{named_to_list} }
344 907     907 1 3703 sub list_to_named { $_[0]{list_to_named} }
345 66     66 1 291 sub oo_trace { $_[0]{oo_trace} }
346 94     94 1 862 sub returns_scalar{ $_[0]{returns_scalar} } sub has_returns_scalar{ defined $_[0]{returns_scalar} }
  16     16 0 81  
347 102     102 1 442 sub returns_list { $_[0]{returns_list} } sub has_returns_list { defined $_[0]{returns_list} }
  16     16 0 108  
348              
349 53 100   53 0 455 sub method_invocant { $_[0]{method_invocant} = defined( $_[0]{method_invocant} ) ? $_[0]{method_invocant} : 'undef' }
350              
351             sub can_shortcut {
352             return $_[0]{can_shortcut}
353 508 100   508 1 2162 if exists $_[0]{can_shortcut};
354             $_[0]{can_shortcut} = !(
355             $_[0]->slurpy or
356 171   100     655 grep $_->might_supply_new_value, @{ $_[0]->parameters }
357             );
358             }
359              
360             sub coderef {
361 344   66 344 1 2544 $_[0]{coderef} ||= $_[0]->_build_coderef;
362             }
363              
364             sub _build_coderef {
365 344     344   788 my $self = shift;
366 344   66     1384 my $coderef = $self->_new_code_accumulator(
367             description => $self->description
368             || sprintf( q{parameter validation for '%s::%s'}, $self->package || '', $self->subname || '__ANON__' )
369             );
370              
371 344         1852 $self->_coderef_start( $coderef );
372 342 100       998 $self->_coderef_head( $coderef ) if $self->has_head;
373 342 100       1054 $self->_coderef_tail( $coderef ) if $self->has_tail;
374 342         1796 $self->_coderef_parameters( $coderef );
375 341 100       1087 if ( $self->has_slurpy ) {
    100          
376 70         289 $self->_coderef_slurpy( $coderef );
377             }
378             elsif ( $self->is_named ) {
379 148         661 $self->_coderef_extra_names( $coderef );
380             }
381 341         1780 $self->_coderef_end( $coderef );
382              
383 341         1813 return $coderef;
384             }
385              
386             sub _coderef_start {
387 344     344   1077 my ( $self, $coderef ) = ( shift, @_ );
388              
389 344         1657 $coderef->add_line( 'sub {' );
390 344         1138 $coderef->{indent} .= "\t";
391              
392 344 100       1359 if ( my $next = $self->next ) {
393 67 100       381 if ( is_CodeLike $next ) {
394 66         424 $coderef->add_variable( '$__NEXT__', \$next );
395             }
396             else {
397 1         6 $coderef->add_line( 'my $__NEXT__ = shift;' );
398 1         5 $coderef->add_gap;
399             }
400             }
401              
402 344 100       1522 if ( $self->method ) {
403             # Passed to parameter defaults
404 48         161 $self->{method_invocant} = '$__INVOCANT__';
405 48         203 $coderef->add_line( sprintf 'my %s = $_[0];', $self->method_invocant );
406 48         222 $coderef->add_gap;
407             }
408              
409 344         1579 $self->_coderef_start_extra( $coderef );
410              
411 343         754 my $extravars = '';
412 343 100       1254 if ( $self->has_head ) {
413 60         153 $extravars .= ', @head';
414             }
415 343 100       1235 if ( $self->has_tail ) {
416 16         51 $extravars .= ', @tail';
417             }
418              
419 343 100       1063 if ( $self->is_named ) {
    100          
420 172         1349 $coderef->add_line( "my ( \%out, \%in, \%tmp, \$tmp, \$dtmp$extravars );" );
421             }
422             elsif ( $self->can_shortcut ) {
423 102         595 $coderef->add_line( "my ( \%tmp, \$tmp$extravars );" );
424             }
425             else {
426 69         453 $coderef->add_line( "my ( \@out, \%tmp, \$tmp, \$dtmp$extravars );" );
427             }
428              
429 343 100       1310 if ( $self->has_on_die ) {
430 7         26 $coderef->add_variable( '$__ON_DIE__', \ $self->on_die );
431             }
432              
433 343         1389 $coderef->add_gap;
434              
435 343         1536 $self->_coderef_check_count( $coderef );
436              
437 342         1410 $coderef->add_gap;
438              
439 342         783 $self;
440             }
441              
442       322     sub _coderef_start_extra {}
443              
444             sub _coderef_check_count {
445 322     322   971 my ( $self, $coderef ) = ( shift, @_ );
446              
447 322         745 my $strictness_test = '';
448 322 100 100     1009 if ( defined $self->strictness and $self->strictness eq 1 ) {
    100          
    100          
449 1         3 $strictness_test = '';
450             }
451             elsif ( $self->strictness ) {
452 3         8 $strictness_test = sprintf '( not %s ) or ', $self->strictness;
453             }
454             elsif ( $self->has_strictness ) {
455 1         4 return $self;
456             }
457              
458 321         788 my $headtail = 0;
459 321 100       964 $headtail += @{ $self->head } if $self->has_head;
  60         297  
460 321 100       1001 $headtail += @{ $self->tail } if $self->has_tail;
  16         41  
461              
462 321         962 my $is_named = $self->is_named;
463 321         703 my $min_args = 0;
464 321         726 my $max_args = 0;
465 321         684 my $seen_optional = 0;
466 321         638 for my $parameter ( @{ $self->parameters } ) {
  321         941  
467 600 100       2311 if ( $parameter->optional ) {
468 131         2635 ++$seen_optional;
469 131         346 ++$max_args;
470             }
471             else {
472 469 100 100     28232 $seen_optional and !$is_named and $self->_croak(
473             'Non-Optional parameter following Optional parameter',
474             );
475 468         902 ++$max_args;
476 468         1074 ++$min_args;
477             }
478             }
479              
480 320 100       1224 undef $max_args if $self->has_slurpy;
481              
482             # Note: code related to $max_args_if_hash is currently commented out
483             # because it handles this badly:
484             #
485             # my %opts = ( x => 1, y => 1 );
486             # your_func( %opts, y => 2 ); # override y
487             #
488              
489 320 100 100     2250 if ( $is_named and $self->list_to_named ) {
    100          
490 5         41 require List::Util;
491 5         14 my $args_if_hashref = $headtail + 1;
492 5 100       11 my $min_args_if_list = $headtail + List::Util::sum( 0, map { $_->optional ? 0 : $_->in_list ? 1 : 2 } @{ $self->parameters } );
  10 50       41  
  5         27  
493 5         34 $self->{min_args} = List::Util::min( $args_if_hashref, $min_args_if_list );
494            
495             $coderef->add_line( $strictness_test . sprintf(
496             "\@_ >= %d\n\tor %s;",
497             $self->{min_args},
498 5         36 $self->_make_count_fail(
499             coderef => $coderef,
500             got => 'scalar( @_ )',
501             ),
502             ) );
503             }
504             elsif ( $is_named ) {
505 167         461 my $args_if_hashref = $headtail + 1;
506 167 100       297 my $hashref_index = @{ $self->head || [] };
  167         875  
507 167         465 my $arity_if_hash = $headtail % 2;
508 167         440 my $min_args_if_hash = $headtail + ( 2 * $min_args );
509             #my $max_args_if_hash = defined( $max_args )
510             # ? ( $headtail + ( 2 * $max_args ) )
511             # : undef;
512              
513 167         1421 require List::Util;
514 167         1090 $self->{min_args} = List::Util::min( $args_if_hashref, $min_args_if_hash );
515             #if ( defined $max_args_if_hash ) {
516             # $self->{max_args} = List::Util::max( $args_if_hashref, $max_args_if_hash );
517             #}
518              
519 167         380 my $extra_conditions = '';
520             #if ( defined $max_args_if_hash and $min_args_if_hash==$max_args_if_hash ) {
521             # $extra_conditions .= " && \@_ == $min_args_if_hash"
522             #}
523             #else {
524 167 100       684 $extra_conditions .= " && \@_ >= $min_args_if_hash"
525             if $min_args_if_hash;
526             # $extra_conditions .= " && \@_ <= $max_args_if_hash"
527             # if defined $max_args_if_hash;
528             #}
529              
530 167         1038 $coderef->add_line( $strictness_test . sprintf(
531             "\@_ == %d && %s\n\tor \@_ %% 2 == %d%s\n\tor %s;",
532             $args_if_hashref,
533             HashRef->inline_check( sprintf '$_[%d]', $hashref_index ),
534             $arity_if_hash,
535             $extra_conditions,
536             $self->_make_count_fail(
537             coderef => $coderef,
538             got => 'scalar( @_ )',
539             ),
540             ) );
541             }
542             else {
543 148         376 $min_args += $headtail;
544 148 100       548 $max_args += $headtail if defined $max_args;
545              
546 148         506 $self->{min_args} = $min_args;
547 148         436 $self->{max_args} = $max_args;
548              
549 148 100 100     1145 if ( defined $max_args and $min_args == $max_args ) {
    100 100        
550 81         445 $coderef->add_line( $strictness_test . sprintf(
551             "\@_ == %d\n\tor %s;",
552             $min_args,
553             $self->_make_count_fail(
554             coderef => $coderef,
555             minimum => $min_args,
556             maximum => $max_args,
557             got => 'scalar( @_ )',
558             ),
559             ) );
560             }
561             elsif ( $min_args and defined $max_args ) {
562 11         70 $coderef->add_line( $strictness_test . sprintf(
563             "\@_ >= %d && \@_ <= %d\n\tor %s;",
564             $min_args,
565             $max_args,
566             $self->_make_count_fail(
567             coderef => $coderef,
568             minimum => $min_args,
569             maximum => $max_args,
570             got => 'scalar( @_ )',
571             ),
572             ) );
573             }
574             else {
575 56   100     527 $coderef->add_line( $strictness_test . sprintf(
      100        
576             "\@_ >= %d\n\tor %s;",
577             $min_args || 0,
578             $self->_make_count_fail(
579             coderef => $coderef,
580             minimum => $min_args || 0,
581             got => 'scalar( @_ )',
582             ),
583             ) );
584             }
585             }
586             }
587              
588             sub _coderef_head {
589 60     60   184 my ( $self, $coderef ) = ( shift, @_ );
590 60 50       211 $self->has_head or return;
591              
592 60         140 my $size = @{ $self->head };
  60         177  
593 60         350 $coderef->add_line( sprintf(
594             '@head = splice( @_, 0, %d );',
595             $size,
596             ) );
597              
598 60         207 $coderef->add_gap;
599              
600 60         114 my $i = 0;
601 60         144 for my $parameter ( @{ $self->head } ) {
  60         172  
602 68         724 $parameter->_make_code(
603             signature => $self,
604             coderef => $coderef,
605             input_slot => sprintf( '$head[%d]', $i ),
606             input_var => '@head',
607             output_slot => sprintf( '$head[%d]', $i ),
608             output_var => undef,
609             index => $i,
610             type => 'head',
611             display_var => sprintf( '$_[%d]', $i ),
612             );
613 68         243 ++$i;
614             }
615              
616 60         151 $self;
617             }
618              
619             sub _coderef_tail {
620 16     16   51 my ( $self, $coderef ) = ( shift, @_ );
621 16 50       38 $self->has_tail or return;
622              
623 16         33 my $size = @{ $self->tail };
  16         39  
624 16         115 $coderef->add_line( sprintf(
625             '@tail = splice( @_, -%d );',
626             $size,
627             ) );
628              
629 16         91 $coderef->add_gap;
630              
631 16         29 my $i = 0;
632 16         27 my $n = @{ $self->tail };
  16         42  
633 16         31 for my $parameter ( @{ $self->tail } ) {
  16         43  
634 42         325 $parameter->_make_code(
635             signature => $self,
636             coderef => $coderef,
637             input_slot => sprintf( '$tail[%d]', $i ),
638             input_var => '@tail',
639             output_slot => sprintf( '$tail[%d]', $i ),
640             output_var => undef,
641             index => $i,
642             type => 'tail',
643             display_var => sprintf( '$_[-%d]', $n - $i ),
644             );
645 42         164 ++$i;
646             }
647              
648 16         43 $self;
649             }
650              
651             sub _coderef_parameters {
652 342     342   1023 my ( $self, $coderef ) = ( shift, @_ );
653              
654 342 100       1118 if ( $self->is_named ) {
655            
656 172 100       533 if ( $self->list_to_named ) {
657 5         38 require Type::Tiny::Enum;
658 5         15 my $Keys = Type::Tiny::Enum->new( values => [ map { $_->name, $_->_all_aliases($self) } @{ $self->parameters } ] );
  10         33  
  5         14  
659 5         40 $coderef->addf( 'my @positional;' );
660 5         21 $coderef->addf( '{' );
661 5         21 $coderef->increase_indent;
662 5         16 $coderef->addf( 'last if ( @_ == 0 );' );
663 5         30 $coderef->addf( 'last if ( @_ == 1 and %s );', HashRef->inline_check( '$_[0]' ) );
664 5         31 $coderef->addf( 'last if ( @_ %% 2 == 0 and %s );', $Keys->inline_check( '$_[0]' ) );
665 5         23 $coderef->addf( 'push @positional, shift @_;' );
666 5         21 $coderef->addf( 'redo;' );
667 5         24 $coderef->decrease_indent;
668 5         17 $coderef->addf( '}' );
669 5         16 $coderef->add_gap;
670             }
671              
672 172         815 $coderef->add_line( sprintf(
673             '%%in = ( @_ == 1 and %s ) ? %%{ $_[0] } : @_;',
674             HashRef->inline_check( '$_[0]' ),
675             ) );
676 172         713 $coderef->add_gap;
677              
678 172         315 for my $parameter ( @{ $self->parameters } ) {
  172         544  
679 391         13075 my $qname = B::perlstring( $parameter->name );
680 391         1860 $parameter->_make_code(
681             signature => $self,
682             coderef => $coderef,
683             is_named => 1,
684             input_slot => sprintf( '$in{%s}', $qname ),
685             output_slot => sprintf( '$out{%s}', $qname ),
686             display_var => sprintf( '$_{%s}', $qname ),
687             key => $parameter->name,
688             type => 'named_arg',
689             );
690             }
691            
692 172 100       1572 if ( $self->list_to_named ) {
693 5         21 $coderef->add_line( sprintf(
694             '@positional and %s;',
695             $self->_make_general_fail(
696             coderef => $coderef,
697             message => q{'Superfluous positional arguments'},
698             ),
699             ) );
700             }
701             }
702             else {
703 170         742 my $can_shortcut = $self->can_shortcut;
704 170 100       500 my $head_size = $self->has_head ? @{ $self->head } : 0;
  36         114  
705              
706 170         371 my $i = 0;
707 170         382 for my $parameter ( @{ $self->parameters } ) {
  170         453  
708 209 100       2390 $parameter->_make_code(
    100          
709             signature => $self,
710             coderef => $coderef,
711             is_named => 0,
712             input_slot => sprintf( '$_[%d]', $i ),
713             input_var => '@_',
714             output_slot => ( $can_shortcut ? undef : sprintf( '$_[%d]', $i ) ),
715             output_var => ( $can_shortcut ? undef : '@out' ),
716             index => $i,
717             display_var => sprintf( '$_[%d]', $i + $head_size ),
718             );
719 208         806 ++$i;
720             }
721             }
722             }
723              
724             sub _coderef_slurpy {
725 70     70   240 my ( $self, $coderef ) = ( shift, @_ );
726 70 50       195 return unless $self->has_slurpy;
727              
728 70         210 my $parameter = $self->slurpy;
729 70         282 my $constraint = $parameter->type;
730 70         717 my $slurp_into = $constraint->my_slurp_into;
731 70         648 my $real_type = $constraint->my_unslurpy;
732              
733 70 100 66     302 if ( $self->is_named ) {
    100          
    100          
734 24         106 $coderef->add_line( 'my $SLURPY = \\%in;' );
735             }
736             elsif ( $real_type and $real_type->{uniq} == Any->{uniq} ) {
737              
738             $coderef->add_line( sprintf(
739             'my $SLURPY = [ @_[ %d .. $#_ ] ];',
740 1         8 scalar( @{ $self->parameters } ),
  1         3  
741             ) );
742             }
743             elsif ( $slurp_into eq 'HASH' ) {
744              
745 29         253 my $index = scalar( @{ $self->parameters } );
  29         91  
746 29   33     118 $coderef->add_line( sprintf(
747             'my $SLURPY = ( $#_ == %d and ( %s ) ) ? { %%{ $_[%d] } } : ( ( $#_ - %d ) %% 2 ) ? { @_[ %d .. $#_ ] } : %s;',
748             $index,
749             HashRef->inline_check("\$_[$index]"),
750             $index,
751             $index,
752             $index,
753             $self->_make_general_fail(
754             coderef => $coderef,
755             message => sprintf(
756             qq{sprintf( "Odd number of elements in %%s", %s )},
757             B::perlstring( ( $real_type or $constraint )->display_name ),
758             ),
759             ),
760             ) );
761             }
762             else {
763            
764             $coderef->add_line( sprintf(
765             'my $SLURPY = [ @_[ %d .. $#_ ] ];',
766 16         152 scalar( @{ $self->parameters } ),
  16         59  
767             ) );
768             }
769              
770 70         312 $coderef->add_gap;
771              
772 70 100       248 $parameter->_make_code(
773             signature => $self,
774             coderef => $coderef,
775             input_slot => '$SLURPY',
776             display_var => '$SLURPY',
777             index => 0,
778             is_slurpy => 1,
779             $self->is_named
780             ? ( output_slot => sprintf( '$out{%s}', B::perlstring( $parameter->name ) ) )
781             : ( output_var => '@out' )
782             );
783             }
784              
785             sub _coderef_extra_names {
786 148     148   449 my ( $self, $coderef ) = ( shift, @_ );
787              
788 148 50 33     426 return $self if $self->has_strictness && ! $self->strictness;
789              
790 148         11199 require Type::Utils;
791 148         470 my $english_list = 'Type::Utils::english_list';
792 148 100       466 if ( $Type::Tiny::AvoidCallbacks ) {
793 8         23 $english_list = 'join q{, } => ';
794             }
795              
796 148         634 $coderef->add_line( '# Unrecognized parameters' );
797 148 50 33     742 $coderef->add_line( sprintf(
798             '%s if %skeys %%in;',
799             $self->_make_general_fail(
800             coderef => $coderef,
801             message => "sprintf( q{Unrecognized parameter%s: %s}, keys( %in ) > 1 ? q{s} : q{}, $english_list( sort keys %in ) )",
802             ),
803             defined( $self->strictness ) && $self->strictness ne 1
804             ? sprintf( '%s && ', $self->strictness )
805             : ''
806             ) );
807 148         479 $coderef->add_gap;
808             }
809              
810             sub _coderef_end {
811 341     341   951 my ( $self, $coderef ) = ( shift, @_ );
812              
813 341 100 100     1601 if ( $self->{_is_signature_for} and $self->next ) {
814 47 100       212 $coderef->add_variable( '$return_check_for_scalar', \ $self->returns_scalar->compiled_check )
815             if $self->has_returns_scalar;
816 47 100       220 $coderef->add_variable( '$return_check_for_list', \ $self->returns_list->compiled_check )
817             if $self->has_returns_list;
818             }
819              
820 341 100 100     1202 if ( $self->bless and $self->oo_trace ) {
821 44         144 my $package = $self->package;
822 44         133 my $subname = $self->subname;
823 44 50 33     240 if ( defined $package and defined $subname ) {
824 44         488 $coderef->add_line( sprintf(
825             '$out{"~~caller"} = %s;',
826             B::perlstring( "$package\::$subname" ),
827             ) );
828 44         135 $coderef->add_gap;
829             }
830             }
831              
832 341         1361 $self->_coderef_end_extra( $coderef );
833 341         1610 $coderef->add_line( $self->_make_return_expression( is_early => 0, allow_full_statements => 1 ) . ';' );
834 341         2405 $coderef->{indent} =~ s/\t$//;
835 341         1263 $coderef->add_line( '}' );
836              
837 341         745 $self;
838             }
839              
840       320     sub _coderef_end_extra {}
841              
842             sub _make_return_list {
843 339     339   695 my $self = shift;
844              
845 339         682 my @return_list;
846 339 100       1347 if ( $self->has_head ) {
847 60         188 push @return_list, '@head';
848             }
849              
850 339 100       1085 if ( not $self->is_named ) {
    100          
    100          
    100          
851 167 100       591 push @return_list, $self->can_shortcut ? '@_' : '@out';
852             }
853             elsif ( $self->named_to_list ) {
854             push @return_list, map(
855             sprintf( '$out{%s}', B::perlstring( $_ ) ),
856 14         35 @{ $self->named_to_list },
  14         41  
857             );
858             }
859             elsif ( $self->class ) {
860 24   100     81 push @return_list, sprintf(
861             '%s->%s( \%%out )',
862             B::perlstring( $self->class ),
863             $self->constructor || 'new',
864             );
865             }
866             elsif ( $self->bless ) {
867 55         149 push @return_list, sprintf(
868             'bless( \%%out, %s )',
869             B::perlstring( $self->bless ),
870             );
871             }
872             else {
873 79         256 push @return_list, '\%out';
874             }
875              
876 339 100       1051 if ( $self->has_tail ) {
877 16         42 push @return_list, '@tail';
878             }
879              
880 339         1341 return @return_list;
881             }
882              
883             sub _make_return_expression {
884 360     360   1616 my ( $self, %args ) = @_;
885              
886 360         1448 my $list = join q{, }, $self->_make_return_list;
887              
888 360 100 66     1083 if ( $self->next ) {
    100          
889 67 100 66     640 if ( $self->{_is_signature_for} and ( $self->has_returns_list or $self->has_returns_scalar ) ) {
    100 100        
    50 33        
      33        
890 8         21 my $call = sprintf '$__NEXT__->( %s )', $list;
891 8         37 return $self->_make_typed_return_expression( $call );
892             }
893             elsif ( $list eq '@_' ) {
894 8         71 return sprintf 'goto( $__NEXT__ )';
895             }
896             elsif ( $args{allow_full_statements} and not ( $args{is_early} or not exists $args{is_early} ) ) {
897             # We are allowed to return full statements, not
898             # forced to use do {...} to make an expression.
899 51         409 return sprintf '@_ = ( %s ); goto $__NEXT__', $list;
900             }
901             else {
902 0         0 return sprintf 'do { @_ = ( %s ); goto $__NEXT__ }', $list;
903             }
904             }
905             elsif ( $args{is_early} or not exists $args{is_early} ) {
906 19         123 return sprintf 'return( %s )', $list;
907             }
908             else {
909 274         1822 return sprintf '( %s )', $list;
910             }
911             }
912              
913             sub _make_typed_return_expression {
914 8     8   33 my ( $self, $expr ) = @_;
915              
916 8 50       27 return sprintf 'wantarray ? %s : defined( wantarray ) ? %s : do { %s; undef; }',
    50          
917             $self->has_returns_list ? $self->_make_typed_list_return_expression( $expr, $self->returns_list ) : $expr,
918             $self->has_returns_scalar ? $self->_make_typed_scalar_return_expression( $expr, $self->returns_scalar ) : $expr,
919             $expr;
920             }
921              
922             sub _make_typed_scalar_return_expression {
923 8     8   29 my ( $self, $expr, $constraint ) = @_;
924              
925 8 50       42 if ( $constraint->{uniq} == Any->{uniq} ) {
    100          
926 0         0 return $expr;
927             }
928             elsif ( $constraint->can_be_inlined ) {
929 7         28 return sprintf 'do { my $__RETURN__ = %s; ( %s ) ? $__RETURN__ : %s }',
930             $expr,
931             $constraint->inline_check( '$__RETURN__' ),
932             $self->_make_constraint_fail( constraint => $constraint, varname => '$__RETURN__' );
933             }
934             else {
935 1         4 return sprintf 'do { my $__RETURN__ = %s; $return_check_for_scalar->( $__RETURN__ ) ? $__RETURN__ : %s }',
936             $expr,
937             $self->_make_constraint_fail( constraint => $constraint, varname => '$__RETURN__' );
938             }
939             }
940              
941             sub _make_typed_list_return_expression {
942 8     8   29 my ( $self, $expr, $constraint ) = @_;
943              
944 8         46 my $slurp_into = Slurpy->of( $constraint )->my_slurp_into;
945 8 100       63 my $varname = $slurp_into eq 'HASH' ? '%__RETURN__' : '@__RETURN__';
946              
947 8 50       59 if ( $constraint->{uniq} == Any->{uniq} ) {
    100          
948 0         0 return $expr;
949             }
950             elsif ( $constraint->can_be_inlined ) {
951 7         34 return sprintf 'do { my %s = %s; my $__RETURN__ = \ %s; ( %s ) ? %s : %s }',
952             $varname,
953             $expr,
954             $varname,
955             $constraint->inline_check( '$__RETURN__' ),
956             $varname,
957             $self->_make_constraint_fail( constraint => $constraint, varname => '$__RETURN__', display_var => "\\$varname" );
958             }
959             else {
960 1         9 return sprintf 'do { my %s = %s; my $__RETURN__ = \ %s; $return_check_for_list->( $__RETURN__ ) ? %s : %s }',
961             $varname,
962             $expr,
963             $varname,
964             $varname,
965             $self->_make_constraint_fail( constraint => $constraint, varname => '$__RETURN__', display_var => "\\$varname" );
966             }
967             }
968              
969             sub _make_general_fail {
970 519     519   2039 my ( $self, %args ) = ( shift, @_ );
971              
972             return sprintf(
973             $self->has_on_die
974             ? q{return( "Error::TypeTiny"->throw_cb( $__ON_DIE__, message => %s ) )}
975             : q{"Error::TypeTiny"->throw( message => %s )},
976             $args{message},
977 519 100       1346 );
978             }
979              
980             sub _make_constraint_fail {
981 777     777   5096 my ( $self, %args ) = ( shift, @_ );
982              
983             return sprintf(
984             $self->has_on_die
985             ? q{return( Type::Tiny::_failed_check( %d, %s, %s, varname => %s, on_die => $__ON_DIE__ ) )}
986             : q{Type::Tiny::_failed_check( %d, %s, %s, varname => %s )},
987             $args{constraint}{uniq},
988             B::perlstring( $args{constraint}->display_name ),
989             $args{varname},
990 777 100 66     2275 B::perlstring( $args{display_var} || $args{varname} ),
991             );
992             }
993              
994             sub _make_count_fail {
995 320     320   2070 my ( $self, %args ) = ( shift, @_ );
996              
997 320         789 my @counts;
998 320 50       1347 if ( $args{got} ) {
999             push @counts, sprintf(
1000             'got => %s',
1001             $args{got},
1002 320         1181 );
1003             }
1004 320         2731 for my $c ( qw/ minimum maximum / ) {
1005 640 100       3511 is_Int( $args{$c} ) or next;
1006             push @counts, sprintf(
1007             '%s => %s',
1008             $c,
1009 240         1053 $args{$c},
1010             );
1011             }
1012              
1013 320 50 33     1129 if ( my $package = $self->package and my $subname = $self->subname ) {
1014 320 100 100     2698 push @counts, sprintf(
1015             'target => %s',
1016             B::perlstring( "$package\::$subname" ),
1017             ) if $package ne '__ANON__' && $subname ne '__ANON__';
1018             }
1019              
1020 320 100       1061 return sprintf(
1021             $self->has_on_die
1022             ? q{return( "Error::TypeTiny::WrongNumberOfParameters"->throw_cb( $__ON_DIE__, %s ) )}
1023             : q{"Error::TypeTiny::WrongNumberOfParameters"->throw( %s )},
1024             join( q{, }, @counts ),
1025             );
1026             }
1027              
1028             sub class_attributes {
1029 65     65 1 128 my $self = shift;
1030 65   66     354 $self->{class_attributes} ||= $self->_build_class_attributes;
1031             }
1032              
1033             sub _build_class_attributes {
1034 49     49   104 my $self = shift;
1035 49         150 my %predicates;
1036             my %getters;
1037              
1038 49         101 my @parameters = @{ $self->parameters };
  49         492  
1039 49 100       170 if ( $self->has_slurpy ) {
1040 1         2 push @parameters, $self->slurpy;
1041             }
1042              
1043 49         180 for my $parameter ( @parameters ) {
1044              
1045 98         354 my $name = $parameter->name;
1046 98 100       285 if ( my $predicate = $parameter->predicate ) {
1047 31 50       162 $predicate =~ /^[^0-9\W]\w*$/
1048             or $self->_croak( "Bad accessor name: \"$predicate\"" );
1049 31         87 $predicates{$predicate} = $name;
1050             }
1051 98 50       255 if ( my $getter = $parameter->getter ) {
1052 98 100       493 $getter =~ /^[^0-9\W]\w*$/
1053             or $self->_croak( "Bad accessor name: \"$getter\"" );
1054 96         337 $getters{$getter} = $name;
1055             }
1056             }
1057              
1058             return {
1059 47         364 exists_predicates => \%predicates,
1060             getters => \%getters,
1061             };
1062             }
1063              
1064             sub make_class {
1065 49     49 1 135 my $self = shift;
1066            
1067 49   50     436 my $env = uc( $ENV{PERL_TYPE_PARAMS_XS} || 'XS' );
1068 49 50 33     428 if ( $env eq 'PP' or $ENV{PERL_ONLY} ) {
1069 0         0 $self->make_class_pp;
1070             }
1071              
1072 49         161 $self->make_class_xs;
1073             }
1074              
1075             sub make_class_xs {
1076 49     49 1 100 my $self = shift;
1077              
1078 49 50       171 eval {
1079 49         8728 require Class::XSAccessor;
1080 49         44002 'Class::XSAccessor'->VERSION( '1.17' );
1081 49         370 1;
1082             } or return $self->make_class_pp;
1083              
1084 49         248 my $attr = $self->class_attributes;
1085              
1086 47         214 'Class::XSAccessor'->import(
1087             class => $self->bless,
1088             replace => 1,
1089             %$attr,
1090             );
1091            
1092 47         12347 $self->make_extra_methods;
1093             }
1094              
1095             sub make_class_pp {
1096 0     0 1 0 my $self = shift;
1097              
1098 0         0 my $code = $self->make_class_pp_code;
1099 0         0 do {
1100 0         0 local $@;
1101 0 0       0 eval( $code ) or die( $@ );
1102             };
1103            
1104 0         0 $self->make_extra_methods;
1105             }
1106              
1107             sub make_class_pp_code {
1108 58     58 1 127 my $self = shift;
1109              
1110 58 100 66     150 return ''
      100        
1111             unless $self->is_named && $self->bless && !$self->named_to_list;
1112              
1113 16         63 my $coderef = $self->_new_code_accumulator;
1114 16         81 my $attr = $self->class_attributes;
1115              
1116 16         59 $coderef->add_line( '{' );
1117 16         38 $coderef->{indent} = "\t";
1118 16         53 $coderef->add_line( sprintf( 'package %s;', $self->bless ) );
1119 16         49 $coderef->add_line( 'use strict;' );
1120 16         47 $coderef->add_line( 'no warnings;' );
1121              
1122 16         28 for my $function ( sort keys %{ $attr->{getters} } ) {
  16         124  
1123 34         68 my $slot = $attr->{getters}{$function};
1124 34         156 $coderef->add_line( sprintf(
1125             'sub %s { $_[0]{%s} }',
1126             $function,
1127             B::perlstring( $slot ),
1128             ) );
1129             }
1130              
1131 16         36 for my $function ( sort keys %{ $attr->{exists_predicates} } ) {
  16         47  
1132 12         18 my $slot = $attr->{exists_predicates}{$function};
1133 12         38 $coderef->add_line( sprintf(
1134             'sub %s { exists $_[0]{%s} }',
1135             $function,
1136             B::perlstring( $slot ),
1137             ) );
1138             }
1139            
1140 16         52 $coderef->add_line( '1;' );
1141 16         37 $coderef->{indent} = "";
1142 16         48 $coderef->add_line( '}' );
1143              
1144 16         43 return $coderef->code;
1145             }
1146              
1147             sub make_extra_methods {
1148 47     47 0 111 my $self = shift;
1149              
1150 47         96 my @parameters = @{ $self->parameters };
  47         164  
1151 47 100       136 if ( $self->has_slurpy ) {
1152 1         3 push @parameters, $self->slurpy;
1153             }
1154              
1155 47         263 my $coderef = $self->_new_code_accumulator;
1156 47         253 $coderef->add_line( '{' );
1157 47         130 $coderef->{indent} = "\t";
1158 47         180 $coderef->add_line( sprintf( 'package %s;', $self->bless ) );
1159 47         175 $coderef->add_line( 'use strict;' );
1160 47         198 $coderef->add_line( 'no warnings;' );
1161            
1162 47         754 $coderef->add_line( 'my @FIELDS = (' );
1163 47         130 for my $p ( @parameters ) {
1164 96         306 $coderef->add_line( "\t" . B::perlstring( $p->name ) . "," )
1165             }
1166 47         172 $coderef->add_line( ');' );
1167            
1168 47         88 my @enum;
1169 47         164 $coderef->add_line( 'my %FIELDS = (' );
1170 47         157 for my $p ( @parameters ) {
1171 96         309 $coderef->add_line( "\t" . B::perlstring( $p->name ) . " => " . B::perlstring( $p->name ) . "," );
1172 96         349 for my $p2 ( $p->_all_aliases($self) ) {
1173 15         59 $coderef->add_line( "\t" . B::perlstring( $p2 ) . " => " . B::perlstring( $p->name ) . "," );
1174             }
1175 96         272 push @enum, $p->name, $p->_all_aliases($self);
1176             }
1177 47         241 $coderef->add_line( ');' );
1178 47         279 my $enum = ArrayRef[ Enum[ @enum ] ];
1179            
1180 47         523 $coderef->add_line( 'sub __TO_LIST__ {' );
1181 47         1127 $coderef->add_line( "\t" . 'my ( $arg, $fields ) = @_;' );
1182 47         164 $coderef->add_line( "\t" . 'return map $arg->{$_}, @FIELDS if not defined $fields;' );
1183 47 50 33     197 if ( ( defined $self->strictness and $self->strictness eq 1 ) or not $self->has_strictness ){
    0 33        
1184 47         272 $coderef->add_line( "\t" . $enum->inline_assert( '$fields' ) );
1185             }
1186             elsif ( $self->strictness ) {
1187 0         0 $coderef->add_line( "\t" . sprintf( 'if ( %s ) { %s }', $self->strictness, $enum->inline_assert( '$fields' ) ) );
1188             }
1189 47         229 $coderef->add_line( "\t" . 'return map $arg->{$FIELDS{$_}}, @$fields;' );
1190 47         170 $coderef->add_line( '}' );
1191              
1192 47         157 $coderef->add_line( 'sub __TO_ARRAYREF__ {' );
1193 47         184 $coderef->add_line( "\t" . 'my ( $arg, $fields ) = @_;' );
1194 47         163 $coderef->add_line( "\t" . 'return [ map $arg->{$_}, @FIELDS ] if not defined $fields;' );
1195 47 50 33     158 if ( ( defined $self->strictness and $self->strictness eq 1 ) or not $self->has_strictness ){
    0 33        
1196 47         181 $coderef->add_line( "\t" . $enum->inline_assert( '$fields' ) );
1197             }
1198             elsif ( $self->strictness ) {
1199 0         0 $coderef->add_line( "\t" . sprintf( 'if ( %s ) { %s }', $self->strictness, $enum->inline_assert( '$fields' ) ) );
1200             }
1201 47         196 $coderef->add_line( "\t" . 'return [ map $arg->{$FIELDS{$_}}, @$fields ];' );
1202 47         149 $coderef->add_line( '}' );
1203              
1204 47         164 $coderef->add_line( 'sub __TO_HASHREF__ {' );
1205 47         189 $coderef->add_line( "\t" . 'my ( $arg, $fields ) = @_;' );
1206 47         161 $coderef->add_line( "\t" . 'return +{ map { ; $_ => $arg->{$_} } @FIELDS } if not defined $fields;' );
1207 47 50 33     150 if ( ( defined $self->strictness and $self->strictness eq 1 ) or not $self->has_strictness ){
    0 33        
1208 47         175 $coderef->add_line( "\t" . $enum->inline_assert( '$fields' ) );
1209             }
1210             elsif ( $self->strictness ) {
1211 0         0 $coderef->add_line( "\t" . sprintf( 'if ( %s ) { %s }', $self->strictness, $enum->inline_assert( '$fields' ) ) );
1212             }
1213 47         189 $coderef->add_line( "\t" . 'return +{ map { ; $_ => $arg->{$FIELDS{$_}} } @$fields };' );
1214 47         147 $coderef->add_line( '}' );
1215            
1216 47         146 $coderef->add_line( '1;' );
1217 47         121 $coderef->{indent} = "";
1218 47         153 $coderef->add_line( '}' );
1219              
1220 47         534 my $code = $coderef->code;
1221 47         111 local $@;
1222 47 50   19   6223 eval( $code ) or die( $@ );
  20 100   14   119  
  16 100   14   47  
  19 100   14   603  
  19 0   14   106  
  18 0       32  
  18 0       3305  
  24 0       162  
  19         712  
  19         2982  
  18         114  
  18         52  
  17         2976  
  17         121  
  14         43  
  14         2015  
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
1223            
1224             Type::Tiny::_install_overloads(
1225             $self->bless,
1226 0     7   0 'bool' => sub { 1 },
1227 47         267 '@{}' => '__TO_ARRAYREF__',
1228             'fallback' => !!1,
1229             );
1230             }
1231              
1232             sub return_wanted {
1233 311     310 1 1048 my $self = shift;
1234 311         1473 my $coderef = $self->coderef;
1235              
1236 305 100       2069 if ( $self->{want_source} ) {
    100          
    100          
1237 11         90 return $coderef->code;
1238             }
1239             elsif ( $self->{want_object} ) { # undocumented for now
1240 4         15 return $self;
1241             }
1242             elsif ( $self->{want_details} ) {
1243             return {
1244             min_args => $self->{min_args},
1245             max_args => $self->{max_args},
1246             environment => $coderef->{env},
1247 65         339 source => $coderef->code,
1248             closure => $coderef->compile,
1249             named => $self->is_named,
1250             class_definition => $self->make_class_pp_code,
1251             };
1252             }
1253              
1254 237         1472 return $coderef->compile;
1255             }
1256              
1257             1;
1258              
1259             __END__