File Coverage

lib/Types/Standard/ArrayRef.pm
Criterion Covered Total %
statement 109 119 92.4
branch 53 64 82.8
condition 21 38 55.2
subroutine 19 20 95.0
pod n/a
total 202 241 84.2


line stmt bran cond sub pod time code
1             # INTERNAL MODULE: guts for ArrayRef type from Types::Standard.
2              
3             package Types::Standard::ArrayRef;
4              
5 77     77   1727 use 5.008001;
  77         297  
6 77     77   471 use strict;
  77         195  
  77         1717  
7 77     77   398 use warnings;
  77         171  
  77         3576  
8              
9             BEGIN {
10 77     77   309 $Types::Standard::ArrayRef::AUTHORITY = 'cpan:TOBYINK';
11 77         2665 $Types::Standard::ArrayRef::VERSION = '2.004000';
12             }
13              
14             $Types::Standard::ArrayRef::VERSION =~ tr/_//d;
15              
16 77     77   478 use Type::Tiny ();
  77         185  
  77         1498  
17 77     77   447 use Types::Standard ();
  77         172  
  77         1211  
18 77     77   455 use Types::TypeTiny ();
  77         174  
  77         4385  
19              
20 2     2   54 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  2         16  
21              
22 77     77   482 no warnings;
  77         191  
  77         96394  
23              
24             sub __constraint_generator {
25 136 100   136   601 return Types::Standard::ArrayRef unless @_;
26            
27 134         339 my $param = shift;
28 134 100       2785 Types::TypeTiny::is_TypeTiny( $param )
29             or _croak(
30             "Parameter to ArrayRef[`a] expected to be a type constraint; got $param" );
31            
32 132         440 my ( $min, $max ) = ( 0, -1 );
33 132 100       488 $min = Types::Standard::assert_Int( shift ) if @_;
34 132 100       496 $max = Types::Standard::assert_Int( shift ) if @_;
35            
36 132         463 my $param_compiled_check = $param->compiled_check;
37 132         266 my $xsub;
38 132 100 66     880 if ( Type::Tiny::_USE_XS and $min == 0 and $max == -1 ) {
    50 33        
      33        
      0        
39 124         613 my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
40 124 100       1531 $xsub = Type::Tiny::XS::get_coderef_for( "ArrayRef[$paramname]" )
41             if $paramname;
42             }
43             elsif ( Type::Tiny::_USE_MOUSE
44             and $param->_has_xsub
45             and $min == 0
46             and $max == -1 )
47             {
48 0         0 require Mouse::Util::TypeConstraints;
49 0         0 my $maker = "Mouse::Util::TypeConstraints"->can( "_parameterize_ArrayRef_for" );
50 0 0       0 $xsub = $maker->( $param ) if $maker;
51             }
52            
53             return (
54             sub {
55 207     207   373 my $array = shift;
56 207   100     628 $param->check( $_ ) || return for @$array;
57 145         387 return !!1;
58             },
59 132 100 66     7187 $xsub,
60             ) if $min == 0 and $max == -1;
61            
62             return sub {
63 22     22   46 my $array = shift;
64 22 100       106 return if @$array < $min;
65 12   100     44 $param->check( $_ ) || return for @$array;
66 9         30 return !!1;
67             }
68 8 100       52 if $max == -1;
69            
70             return sub {
71 0     0   0 my $array = shift;
72 0 0       0 return if @$array > $max;
73 0   0     0 $param->check( $_ ) || return for @$array;
74 0         0 return !!1;
75             }
76 4 50       14 if $min == 0;
77            
78             return sub {
79 10     10   19 my $array = shift;
80 10 100       34 return if @$array < $min;
81 8 100       32 return if @$array > $max;
82 5   100     16 $param->check( $_ ) || return for @$array;
83 3         9 return !!1;
84 4         27 };
85             } #/ sub __constraint_generator
86              
87             sub __inline_generator {
88 132     132   303 my $param = shift;
89 132         308 my ( $min, $max ) = ( 0, -1 );
90 132 100       463 $min = shift if @_;
91 132 100       471 $max = shift if @_;
92            
93 132         417 my $param_compiled_check = $param->compiled_check;
94 132         287 my $xsubname;
95 132 100 66     753 if ( Type::Tiny::_USE_XS and $min == 0 and $max == -1 ) {
96 124         403 my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
97 124         1195 $xsubname = Type::Tiny::XS::get_subname_for( "ArrayRef[$paramname]" );
98             }
99            
100 132 100       1848 return unless $param->can_be_inlined;
101            
102             return sub {
103 1119     1119   1898 my $v = $_[1];
104 1119 100 100     5046 return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
105 369         2254 my $p = Types::Standard::ArrayRef->inline_check( $v );
106            
107 369 100       982 if ( $min != 0 ) {
108 88         362 $p .= sprintf( ' and @{%s} >= %d', $v, $min );
109             }
110 369 100       841 if ( $max > 0 ) {
111 36         75 $p .= sprintf( ' and @{%s} <= %d', $v, $max );
112             }
113            
114 369         881 my $param_check = $param->inline_check( '$i' );
115 369 100       1349 return $p if $param->{uniq} eq Types::Standard::Any->{uniq};
116            
117 365         2999 "$p and do { "
118             . "my \$ok = 1; "
119             . "for my \$i (\@{$v}) { "
120             . "(\$ok = 0, last) unless $param_check " . "}; " . "\$ok " . "}";
121 123         983 };
122             } #/ sub __inline_generator
123              
124             sub __deep_explanation {
125 2     2   6 my ( $type, $value, $varname ) = @_;
126 2         7 my $param = $type->parameters->[0];
127 2         7 my ( $min, $max ) = ( 0, -1 );
128 2 50       12 $min = $type->parameters->[1] if @{ $type->parameters } > 1;
  2         6  
129 2 50       4 $max = $type->parameters->[2] if @{ $type->parameters } > 2;
  2         6  
130            
131 2 50 33     9 if ( $min != 0 and @$value < $min ) {
132             return [
133 0         0 sprintf( '"%s" constrains array length at least %s', $type, $min ),
134             sprintf( '@{%s} is %d', $varname, scalar @$value ),
135             ];
136             }
137            
138 2 50 33     41 if ( $max > 0 and @$value > $max ) {
139             return [
140 0         0 sprintf( '"%s" constrains array length at most %d', $type, $max ),
141             sprintf( '@{%s} is %d', $varname, scalar @$value ),
142             ];
143             }
144            
145 2         8 for my $i ( 0 .. $#$value ) {
146 5         8 my $item = $value->[$i];
147 5 100       12 next if $param->check( $item );
148             return [
149             sprintf( '"%s" constrains each value in the array with "%s"', $type, $param ),
150 2         14 @{ $param->validate_explain( $item, sprintf( '%s->[%d]', $varname, $i ) ) },
  2         11  
151             ];
152             }
153            
154             # This should never happen...
155 0         0 return; # uncoverable statement
156             } #/ sub __deep_explanation
157              
158             # XXX: min and max need to be handled by coercion?
159             sub __coercion_generator {
160 48     48   151 my ( $parent, $child, $param ) = @_;
161 48 100       174 return unless $param->has_coercion;
162            
163 25         162 my $coercable_item = $param->coercion->_source_type_union;
164 25         145 my $C = "Type::Coercion"->new( type_constraint => $child );
165            
166 25 100 66     82 if ( $param->coercion->can_be_inlined and $coercable_item->can_be_inlined ) {
167             $C->add_type_coercions(
168             $parent => Types::Standard::Stringable {
169 11     11   24 my @code;
170 11         27 push @code, 'do { my ($orig, $return_orig, @new) = ($_, 0);';
171 11         25 push @code, 'for (@$orig) {';
172 11         52 push @code,
173             sprintf(
174             '++$return_orig && last unless (%s);',
175             $coercable_item->inline_check( '$_' )
176             );
177 11         55 push @code,
178             sprintf(
179             'push @new, (%s);',
180             $param->coercion->inline_coercion( '$_' )
181             );
182 11         40 push @code, '}';
183 11         26 push @code, '$return_orig ? $orig : \\@new';
184 11         36 push @code, '}';
185 11         147 "@code";
186             }
187 11         99 );
188             } #/ if ( $param->coercion->...)
189             else {
190             $C->add_type_coercions(
191             $parent => sub {
192 72 50   72   65994 my $value = @_ ? $_[0] : $_;
193 72         141 my @new;
194 72         179 for my $item ( @$value ) {
195 280 100       2296 return $value unless $coercable_item->check( $item );
196 279         1983 push @new, $param->coerce( $item );
197             }
198 71         1205 return \@new;
199             },
200 14         127 );
201             } #/ else [ if ( $param->coercion->...)]
202            
203 25         94 return $C;
204             } #/ sub __coercion_generator
205              
206             1;