File Coverage

lib/Types/Standard/Map.pm
Criterion Covered Total %
statement 110 111 100.0
branch 44 56 78.5
condition 28 40 70.0
subroutine 21 21 100.0
pod n/a
total 203 228 89.4


line stmt bran cond sub pod time code
1             # INTERNAL MODULE: guts for Map type from Types::Standard.
2              
3             package Types::Standard::Map;
4              
5 8     8   215 use 5.008001;
  8         30  
6 8     8   88 use strict;
  8         16  
  8         218  
7 8     8   40 use warnings;
  8         20  
  8         378  
8              
9             BEGIN {
10 8     8   42 $Types::Standard::Map::AUTHORITY = 'cpan:TOBYINK';
11 8         373 $Types::Standard::Map::VERSION = '2.003_000';
12             }
13              
14             $Types::Standard::Map::VERSION =~ tr/_//d;
15              
16 8     8   63 use Type::Tiny ();
  8         15  
  8         166  
17 8     8   44 use Types::Standard ();
  8         16  
  8         153  
18 8     8   51 use Types::TypeTiny ();
  8         22  
  8         858  
19              
20 3     3   41 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  3         15  
21              
22             my $meta = Types::Standard->meta;
23              
24 8     8   53 no warnings;
  8         177  
  8         12253  
25              
26             sub __constraint_generator {
27 29 50   29   115 return $meta->get_type( 'Map' ) unless @_;
28            
29 29         79 my ( $keys, $values ) = @_;
30 29 100       533 Types::TypeTiny::is_TypeTiny( $keys )
31             or _croak(
32             "First parameter to Map[`k,`v] expected to be a type constraint; got $keys" );
33 27 100       450 Types::TypeTiny::is_TypeTiny( $values )
34             or _croak(
35             "Second parameter to Map[`k,`v] expected to be a type constraint; got $values"
36             );
37            
38 26         91 my @xsub;
39 26         57 if ( Type::Tiny::_USE_XS ) {
40             my @known = map {
41 26         67 my $known = Type::Tiny::XS::is_known( $_->compiled_check );
  52         138  
42 52 100       435 defined( $known ) ? $known : ();
43             } ( $keys, $values );
44            
45 26 100       115 if ( @known == 2 ) {
46 19         140 my $xsub = Type::Tiny::XS::get_coderef_for( sprintf "Map[%s,%s]", @known );
47 19 50       1007 push @xsub, $xsub if $xsub;
48             }
49             } #/ if ( Type::Tiny::_USE_XS)
50            
51             sub {
52 25     25   49 my $hash = shift;
53 25   100     99 $keys->check( $_ ) || return for keys %$hash;
54 21   100     69 $values->check( $_ ) || return for values %$hash;
55 15         51 return !!1;
56 26         257 }, @xsub;
57             } #/ sub __constraint_generator
58              
59             sub __inline_generator {
60 26     26   76 my ( $k, $v ) = @_;
61 26 50 33     91 return unless $k->can_be_inlined && $v->can_be_inlined;
62            
63 26         77 my $xsubname;
64 26         50 if ( Type::Tiny::_USE_XS ) {
65             my @known = map {
66 26         66 my $known = Type::Tiny::XS::is_known( $_->compiled_check );
  52         129  
67 52 100       389 defined( $known ) ? $known : ();
68             } ( $k, $v );
69            
70 26 100       94 if ( @known == 2 ) {
71 19         122 $xsubname = Type::Tiny::XS::get_subname_for( sprintf "Map[%s,%s]", @known );
72             }
73             } #/ if ( Type::Tiny::_USE_XS)
74            
75             return sub {
76 341     341   624 my $h = $_[1];
77 341 100 100     1674 return "$xsubname\($h\)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
78 69         210 my $p = Types::Standard::HashRef->inline_check( $h );
79 69         189 my $k_check = $k->inline_check( '$k' );
80 69         189 my $v_check = $v->inline_check( '$v' );
81 69         466 "$p and do { "
82             . "my \$ok = 1; "
83             . "for my \$v (values \%{$h}) { "
84             . "(\$ok = 0, last) unless $v_check " . "}; "
85             . "for my \$k (keys \%{$h}) { "
86             . "(\$ok = 0, last) unless $k_check " . "}; " . "\$ok " . "}";
87 26         364 };
88             } #/ sub __inline_generator
89              
90             sub __deep_explanation {
91 2     2   10 require B;
92 2         7 my ( $type, $value, $varname ) = @_;
93 2         4 my ( $kparam, $vparam ) = @{ $type->parameters };
  2         4  
94            
95 2         9 for my $k ( sort keys %$value ) {
96 3 100       51 unless ( $kparam->check( $k ) ) {
97             return [
98             sprintf( '"%s" constrains each key in the hash with "%s"', $type, $kparam ),
99             @{
100 1         4 $kparam->validate_explain(
  1         6  
101             $k, sprintf( 'key %s->{%s}', $varname, B::perlstring( $k ) )
102             )
103             },
104             ];
105             } #/ unless ( $kparam->check( $k...))
106            
107 2 100       7 unless ( $vparam->check( $value->{$k} ) ) {
108             return [
109             sprintf( '"%s" constrains each value in the hash with "%s"', $type, $vparam ),
110             @{
111 1         8 $vparam->validate_explain(
112 1         8 $value->{$k}, sprintf( '%s->{%s}', $varname, B::perlstring( $k ) )
113             )
114             },
115             ];
116             } #/ unless ( $vparam->check( $value...))
117             } #/ for my $k ( sort keys %$value)
118            
119             # This should never happen...
120 0         0 return; # uncoverable statement
121             } #/ sub __deep_explanation
122              
123             sub __coercion_generator {
124 17     17   57 my ( $parent, $child, $kparam, $vparam ) = @_;
125 17 100 100     114 return unless $kparam->has_coercion || $vparam->has_coercion;
126            
127 7 100       24 my $kcoercable_item =
128             $kparam->has_coercion
129             ? $kparam->coercion->_source_type_union
130             : $kparam;
131 7 50       35 my $vcoercable_item =
132             $vparam->has_coercion
133             ? $vparam->coercion->_source_type_union
134             : $vparam;
135 7         29 my $C = "Type::Coercion"->new( type_constraint => $child );
136            
137 7 100 100     21 if ( ( !$kparam->has_coercion or $kparam->coercion->can_be_inlined )
      66        
      100        
      66        
      66        
138             and ( !$vparam->has_coercion or $vparam->coercion->can_be_inlined )
139             and $kcoercable_item->can_be_inlined
140             and $vcoercable_item->can_be_inlined )
141             {
142             $C->add_type_coercions(
143             $parent => Types::Standard::Stringable {
144 4     4   11 my @code;
145 4         10 push @code, 'do { my ($orig, $return_orig, %new) = ($_, 0);';
146 4         11 push @code, 'for (keys %$orig) {';
147 4         18 push @code,
148             sprintf(
149             '++$return_orig && last unless (%s);',
150             $kcoercable_item->inline_check( '$_' )
151             );
152 4         54 push @code,
153             sprintf(
154             '++$return_orig && last unless (%s);',
155             $vcoercable_item->inline_check( '$orig->{$_}' )
156             );
157 4 100       30 push @code, sprintf(
    50          
158             '$new{(%s)} = (%s);',
159             $kparam->has_coercion ? $kparam->coercion->inline_coercion( '$_' ) : '$_',
160             $vparam->has_coercion
161             ? $vparam->coercion->inline_coercion( '$orig->{$_}' )
162             : '$orig->{$_}',
163             );
164 4         31 push @code, '}';
165 4         16 push @code, '$return_orig ? $orig : \\%new';
166 4         13 push @code, '}';
167 4         74 "@code";
168             }
169 5         46 );
170             } #/ if ( ( !$kparam->has_coercion...))
171             else {
172             $C->add_type_coercions(
173             $parent => sub {
174 3 50   3   36 my $value = @_ ? $_[0] : $_;
175 3         7 my %new;
176 3         16 for my $k ( keys %$value ) {
177             return $value
178             unless $kcoercable_item->check( $k )
179 6 100 66     74 && $vcoercable_item->check( $value->{$k} );
180             $new{ $kparam->has_coercion ? $kparam->coerce( $k ) : $k } =
181             $vparam->has_coercion
182             ? $vparam->coerce( $value->{$k} )
183 5 50       52 : $value->{$k};
    50          
184             }
185 2         42 return \%new;
186             },
187 2         29 );
188             } #/ else [ if ( ( !$kparam->has_coercion...))]
189            
190 7         29 return $C;
191             } #/ sub __coercion_generator
192              
193             sub __hashref_allows_key {
194 45     45   104 my $self = shift;
195 45         97 my ( $key ) = @_;
196            
197 45 100       151 return Types::Standard::is_Str( $key ) if $self == Types::Standard::Map();
198            
199             my $map = $self->find_parent(
200 39 50   43   273 sub { $_->has_parent && $_->parent == Types::Standard::Map() } );
  43         135  
201 39         164 my ( $kcheck, $vcheck ) = @{ $map->parameters };
  39         121  
202            
203 39   33     130 ( $kcheck or Types::Standard::Any() )->check( $key );
204             } #/ sub __hashref_allows_key
205              
206             sub __hashref_allows_value {
207 10     10   30 my $self = shift;
208 10         40 my ( $key, $value ) = @_;
209            
210 10 100       77 return !!0 unless $self->my_hashref_allows_key( $key );
211 7 50       39 return !!1 if $self == Types::Standard::Map();
212            
213             my $map = $self->find_parent(
214 7 50   7   65 sub { $_->has_parent && $_->parent == Types::Standard::Map() } );
  7         39  
215 7         38 my ( $kcheck, $vcheck ) = @{ $map->parameters };
  7         23  
216            
217 7 50 33     26 ( $kcheck or Types::Standard::Any() )->check( $key )
      33        
218             and ( $vcheck or Types::Standard::Any() )->check( $value );
219             } #/ sub __hashref_allows_value
220              
221             1;