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 74     74   1621 use 5.008001;
  74         284  
6 74     74   515 use strict;
  74         175  
  74         2110  
7 74     74   427 use warnings;
  74         211  
  74         3644  
8              
9             BEGIN {
10 74     74   292 $Types::Standard::ArrayRef::AUTHORITY = 'cpan:TOBYINK';
11 74         2760 $Types::Standard::ArrayRef::VERSION = '2.002001';
12             }
13              
14             $Types::Standard::ArrayRef::VERSION =~ tr/_//d;
15              
16 74     74   477 use Type::Tiny ();
  74         168  
  74         1397  
17 74     74   453 use Types::Standard ();
  74         175  
  74         1195  
18 74     74   397 use Types::TypeTiny ();
  74         189  
  74         4541  
19              
20 2     2   815 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  2         12  
21              
22 74     74   470 no warnings;
  74         1599  
  74         98442  
23              
24             sub __constraint_generator {
25 133 100   133   535 return Types::Standard::ArrayRef unless @_;
26            
27 131         288 my $param = shift;
28 131 100       2846 Types::TypeTiny::is_TypeTiny( $param )
29             or _croak(
30             "Parameter to ArrayRef[`a] expected to be a type constraint; got $param" );
31            
32 129         453 my ( $min, $max ) = ( 0, -1 );
33 129 100       614 $min = Types::Standard::assert_Int( shift ) if @_;
34 129 100       599 $max = Types::Standard::assert_Int( shift ) if @_;
35            
36 129         453 my $param_compiled_check = $param->compiled_check;
37 129         304 my $xsub;
38 129 100 66     894 if ( Type::Tiny::_USE_XS and $min == 0 and $max == -1 ) {
    50 33        
      33        
      0        
39 121         568 my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
40 121 100       1572 $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   370 my $array = shift;
56 207   100     636 $param->check( $_ ) || return for @$array;
57 145         465 return !!1;
58             },
59 129 100 66     7099 $xsub,
60             ) if $min == 0 and $max == -1;
61            
62             return sub {
63 22     22   42 my $array = shift;
64 22 100       104 return if @$array < $min;
65 12   100     50 $param->check( $_ ) || return for @$array;
66 9         28 return !!1;
67             }
68 8 100       48 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       37 return if @$array < $min;
81 8 100       34 return if @$array > $max;
82 5   100     18 $param->check( $_ ) || return for @$array;
83 3         11 return !!1;
84 4         45 };
85             } #/ sub __constraint_generator
86              
87             sub __inline_generator {
88 129     129   272 my $param = shift;
89 129         301 my ( $min, $max ) = ( 0, -1 );
90 129 100       504 $min = shift if @_;
91 129 100       405 $max = shift if @_;
92            
93 129         369 my $param_compiled_check = $param->compiled_check;
94 129         255 my $xsubname;
95 129 100 66     742 if ( Type::Tiny::_USE_XS and $min == 0 and $max == -1 ) {
96 121         402 my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
97 121         1119 $xsubname = Type::Tiny::XS::get_subname_for( "ArrayRef[$paramname]" );
98             }
99            
100 129 100       1774 return unless $param->can_be_inlined;
101            
102             return sub {
103 1052     1052   1798 my $v = $_[1];
104 1052 100 100     4690 return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
105 335         915 my $p = Types::Standard::ArrayRef->inline_check( $v );
106            
107 335 100       1315 if ( $min != 0 ) {
108 88         360 $p .= sprintf( ' and @{%s} >= %d', $v, $min );
109             }
110 335 100       836 if ( $max > 0 ) {
111 36         76 $p .= sprintf( ' and @{%s} <= %d', $v, $max );
112             }
113            
114 335         804 my $param_check = $param->inline_check( '$i' );
115 335 100       1247 return $p if $param->{uniq} eq Types::Standard::Any->{uniq};
116            
117 331         2600 "$p and do { "
118             . "my \$ok = 1; "
119             . "for my \$i (\@{$v}) { "
120             . "(\$ok = 0, last) unless $param_check " . "}; " . "\$ok " . "}";
121 120         1028 };
122             } #/ sub __inline_generator
123              
124             sub __deep_explanation {
125 2     2   8 my ( $type, $value, $varname ) = @_;
126 2         7 my $param = $type->parameters->[0];
127 2         6 my ( $min, $max ) = ( 0, -1 );
128 2 50       5 $min = $type->parameters->[1] if @{ $type->parameters } > 1;
  2         5  
129 2 50       4 $max = $type->parameters->[2] if @{ $type->parameters } > 2;
  2         5  
130            
131 2 50 33     8 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     8 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         11 for my $i ( 0 .. $#$value ) {
146 5         9 my $item = $value->[$i];
147 5 100       10 next if $param->check( $item );
148             return [
149             sprintf( '"%s" constrains each value in the array with "%s"', $type, $param ),
150 2         9 @{ $param->validate_explain( $item, sprintf( '%s->[%d]', $varname, $i ) ) },
  2         10  
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   155 my ( $parent, $child, $param ) = @_;
161 48 100       186 return unless $param->has_coercion;
162            
163 25         105 my $coercable_item = $param->coercion->_source_type_union;
164 25         112 my $C = "Type::Coercion"->new( type_constraint => $child );
165            
166 25 100 66     92 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   29 my @code;
170 11         50 push @code, 'do { my ($orig, $return_orig, @new) = ($_, 0);';
171 11         38 push @code, 'for (@$orig) {';
172 11         59 push @code,
173             sprintf(
174             '++$return_orig && last unless (%s);',
175             $coercable_item->inline_check( '$_' )
176             );
177 11         52 push @code,
178             sprintf(
179             'push @new, (%s);',
180             $param->coercion->inline_coercion( '$_' )
181             );
182 11         44 push @code, '}';
183 11         38 push @code, '$return_orig ? $orig : \\@new';
184 11         34 push @code, '}';
185 11         115 "@code";
186             }
187 11         110 );
188             } #/ if ( $param->coercion->...)
189             else {
190             $C->add_type_coercions(
191             $parent => sub {
192 72 50   72   66657 my $value = @_ ? $_[0] : $_;
193 72         150 my @new;
194 72         177 for my $item ( @$value ) {
195 280 100       2007 return $value unless $coercable_item->check( $item );
196 279         1999 push @new, $param->coerce( $item );
197             }
198 71         1178 return \@new;
199             },
200 14         135 );
201             } #/ else [ if ( $param->coercion->...)]
202            
203 25         97 return $C;
204             } #/ sub __coercion_generator
205              
206             1;