File Coverage

lib/Types/Standard/ArrayRef.pm
Criterion Covered Total %
statement 125 135 93.3
branch 64 78 82.0
condition 23 44 52.2
subroutine 21 22 95.4
pod n/a
total 233 279 83.8


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 99     99   3033 use 5.008001;
  99         421  
6 99     99   640 use strict;
  99         268  
  99         3357  
7 99     99   564 use warnings;
  99         251  
  99         9858  
8              
9             BEGIN {
10 99     99   436 $Types::Standard::ArrayRef::AUTHORITY = 'cpan:TOBYINK';
11 99         7363 $Types::Standard::ArrayRef::VERSION = '2.010001';
12             }
13              
14             $Types::Standard::ArrayRef::VERSION =~ tr/_//d;
15              
16 99     99   832 use Type::Tiny ();
  99         229  
  99         2144  
17 99     99   554 use Types::Standard ();
  99         246  
  99         2491  
18 99     99   531 use Types::TypeTiny ();
  99         207  
  99         8374  
19              
20 2     2   26 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  2         12  
21              
22 99     99   604 use Exporter::Tiny 1.004001 ();
  99         2411  
  99         44151  
23             our @ISA = qw( Exporter::Tiny );
24              
25             sub _exporter_fail {
26 3     3   620 my ( $class, $type_name, $values, $globals ) = @_;
27 3         10 my $caller = $globals->{into};
28            
29 3 100       14 my $of = exists( $values->{of} ) ? $values->{of} : $values->{type};
30 3 50       12 defined $of or _croak( qq{Expected option "of" for type "$type_name"} );
31 3 100       138 if ( not Types::TypeTiny::is_TypeTiny($of) ) {
32 1         641 require Type::Utils;
33 1         7 $of = Type::Utils::dwim_type( $of, for => $caller );
34             }
35            
36 3         18 my $type = Types::Standard::ArrayRef->of( $of );
37             $type = $type->create_child_type(
38             name => $type_name,
39             $type->has_coercion ? ( coercion => 1 ) : (),
40 3 50       14 exists( $values->{where} ) ? ( constraint => $values->{where} ) : (),
    100          
41             );
42            
43             $INC{'Type/Registry.pm'}
44             ? 'Type::Registry'->for_class( $caller )->add_type( $type, $type_name )
45             : ( $Type::Registry::DELAYED{$caller}{$type_name} = $type )
46 3 100 33     49 unless( ref($caller) or $caller eq '-lexical' or $globals->{'lexical'} );
    50 33        
47 3         19 return map +( $_->{name} => $_->{code} ), @{ $type->exportables };
  3         18  
48             }
49              
50 99     99   797 no warnings;
  99         249  
  99         171620  
51              
52             sub __constraint_generator {
53 186 100   186   837 return Types::Standard::ArrayRef unless @_;
54            
55 184         1133 Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Standard', 'ArrayRef', \@_, 3 );
56 184         484 my $param = shift;
57 184 100       5578 Types::TypeTiny::is_TypeTiny( $param )
58             or _croak(
59             "Parameter to ArrayRef[`a] expected to be a type constraint; got $param" );
60            
61 182         653 my ( $min, $max ) = ( 0, -1 );
62 182 100       681 $min = Types::Standard::assert_Int( shift ) if @_;
63 182 100       1543 $max = Types::Standard::assert_Int( shift ) if @_;
64            
65 182         776 my $param_compiled_check = $param->compiled_check;
66 182         549 my $xsub;
67 182 100 66     1184 if ( Type::Tiny::_USE_XS and $min == 0 and $max == -1 ) {
    50 33        
      33        
      0        
68 173         1066 my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
69 173 100       2183 $xsub = Type::Tiny::XS::get_coderef_for( "ArrayRef[$paramname]" )
70             if $paramname;
71             }
72             elsif ( Type::Tiny::_USE_MOUSE
73             and $param->_has_xsub
74             and $min == 0
75             and $max == -1 )
76             {
77 0         0 require Mouse::Util::TypeConstraints;
78 0         0 my $maker = "Mouse::Util::TypeConstraints"->can( "_parameterize_ArrayRef_for" );
79 0 0       0 $xsub = $maker->( $param ) if $maker;
80             }
81            
82             return (
83             sub {
84 209     209   413 my $array = shift;
85 209   100     892 $param->check( $_ ) || return for @$array;
86 146         471 return !!1;
87             },
88 182 100 66     13597 $xsub,
89             ) if $min == 0 and $max == -1;
90            
91             return sub {
92 22     22   47 my $array = shift;
93 22 100       136 return if @$array < $min;
94 12   100     55 $param->check( $_ ) || return for @$array;
95 9         33 return !!1;
96             }
97 9 100       63 if $max == -1;
98            
99             return sub {
100 0     0   0 my $array = shift;
101 0 0       0 return if @$array > $max;
102 0   0     0 $param->check( $_ ) || return for @$array;
103 0         0 return !!1;
104             }
105 4 50       15 if $min == 0;
106            
107             return sub {
108 10     10   17 my $array = shift;
109 10 100       52 return if @$array < $min;
110 8 100       30 return if @$array > $max;
111 5   100     22 $param->check( $_ ) || return for @$array;
112 3         10 return !!1;
113 4         34 };
114             } #/ sub __constraint_generator
115              
116             sub __inline_generator {
117 182     182   540 my $param = shift;
118 182         487 my ( $min, $max ) = ( 0, -1 );
119 182 100       689 $min = shift if @_;
120 182 100       709 $max = shift if @_;
121            
122 182         665 my $param_compiled_check = $param->compiled_check;
123 182         356 my $xsubname;
124 182 100 66     1319 if ( Type::Tiny::_USE_XS and $min == 0 and $max == -1 ) {
125 173         668 my $paramname = Type::Tiny::XS::is_known( $param_compiled_check );
126 173         1782 $xsubname = Type::Tiny::XS::get_subname_for( "ArrayRef[$paramname]" );
127             }
128            
129 182 100       2788 return unless $param->can_be_inlined;
130            
131             return sub {
132 1401     1401   2940 my $v = $_[1];
133 1401 100 100     8231 return "$xsubname\($v\)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
134 394         1534 my $p = Types::Standard::ArrayRef->inline_check( $v );
135            
136 394 100       2240 if ( $min != 0 ) {
137 106         454 $p .= sprintf( ' and @{%s} >= %d', $v, $min );
138             }
139 394 100       986 if ( $max > 0 ) {
140 36         82 $p .= sprintf( ' and @{%s} <= %d', $v, $max );
141             }
142            
143 394         1271 my $param_check = $param->inline_check( '$i' );
144 394 100       2051 return $p if $param->{uniq} eq Types::Standard::Any->{uniq};
145            
146 390         4286 "$p and do { "
147             . "my \$ok = 1; "
148             . "for my \$i (\@{$v}) { "
149             . "(\$ok = 0, last) unless $param_check " . "}; " . "\$ok " . "}";
150 172         1878 };
151             } #/ sub __inline_generator
152              
153             sub __deep_explanation {
154 3     3   8 my ( $type, $value, $varname ) = @_;
155 3         10 my $param = $type->parameters->[0];
156 3         8 my ( $min, $max ) = ( 0, -1 );
157 3 50       6 $min = $type->parameters->[1] if @{ $type->parameters } > 1;
  3         8  
158 3 50       6 $max = $type->parameters->[2] if @{ $type->parameters } > 2;
  3         7  
159            
160 3 50 33     56 if ( $min != 0 and @$value < $min ) {
161             return [
162 0         0 sprintf( '"%s" constrains array length at least %s', $type, $min ),
163             sprintf( '@{%s} is %d', $varname, scalar @$value ),
164             ];
165             }
166            
167 3 50 33     13 if ( $max > 0 and @$value > $max ) {
168             return [
169 0         0 sprintf( '"%s" constrains array length at most %d', $type, $max ),
170             sprintf( '@{%s} is %d', $varname, scalar @$value ),
171             ];
172             }
173            
174 3         12 for my $i ( 0 .. $#$value ) {
175 7         48 my $item = $value->[$i];
176 7 100       18 next if $param->check( $item );
177             return [
178             sprintf( '"%s" constrains each value in the array with "%s"', $type, $param ),
179 3         17 @{ $param->validate_explain( $item, sprintf( '%s->[%d]', $varname, $i ) ) },
  3         15  
180             ];
181             }
182            
183             # This should never happen...
184 0         0 return; # uncoverable statement
185             } #/ sub __deep_explanation
186              
187             # XXX: min and max need to be handled by coercion?
188             sub __coercion_generator {
189 57     57   195 my ( $parent, $child, $param ) = @_;
190 57 100       236 return unless $param->has_coercion;
191            
192 25         123 my $coercable_item = $param->coercion->_source_type_union;
193 25         137 my $C = "Type::Coercion"->new( type_constraint => $child );
194            
195 25 100 66     100 if ( $param->coercion->can_be_inlined and $coercable_item->can_be_inlined ) {
196             $C->add_type_coercions(
197             $parent => Types::Standard::Stringable {
198 11     11   23 my @code;
199 11         32 push @code, 'do { my ($orig, $return_orig, @new) = ($_, 0);';
200 11         32 push @code, 'for (@$orig) {';
201 11         67 push @code,
202             sprintf(
203             '++$return_orig && last unless (%s);',
204             $coercable_item->inline_check( '$_' )
205             );
206 11         55 push @code,
207             sprintf(
208             'push @new, (%s);',
209             $param->coercion->inline_coercion( '$_' )
210             );
211 11         35 push @code, '}';
212 11         47 push @code, '$return_orig ? $orig : \\@new';
213 11         31 push @code, '}';
214 11         130 "@code";
215             }
216 11         832 );
217             } #/ if ( $param->coercion->...)
218             else {
219             $C->add_type_coercions(
220             $parent => sub {
221 72 50   72   86167 my $value = @_ ? $_[0] : $_;
222 72         205 my @new;
223 72         202 for my $item ( @$value ) {
224 280 100       1982 return $value unless $coercable_item->check( $item );
225 279         1504 push @new, $param->coerce( $item );
226             }
227 71         1247 return \@new;
228             },
229 14         150 );
230             } #/ else [ if ( $param->coercion->...)]
231            
232 25         367 return $C;
233             } #/ sub __coercion_generator
234              
235             1;
236              
237             __END__