File Coverage

lib/Types/Standard/Map.pm
Criterion Covered Total %
statement 131 132 100.0
branch 56 74 75.6
condition 30 46 65.2
subroutine 23 23 100.0
pod n/a
total 240 275 87.6


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   1138 use 5.008001;
  8         36  
6 8     8   48 use strict;
  8         15  
  8         255  
7 8     8   35 use warnings;
  8         15  
  8         887  
8              
9             BEGIN {
10 8     8   32 $Types::Standard::Map::AUTHORITY = 'cpan:TOBYINK';
11 8         1453 $Types::Standard::Map::VERSION = '2.010001';
12             }
13              
14             $Types::Standard::Map::VERSION =~ tr/_//d;
15              
16 8     8   50 use Type::Tiny ();
  8         39  
  8         182  
17 8     8   40 use Types::Standard ();
  8         26  
  8         241  
18 8     8   57 use Types::TypeTiny ();
  8         17  
  8         707  
19              
20 3     3   30 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  3         14  
21              
22 8     8   47 use Exporter::Tiny 1.004001 ();
  8         193  
  8         3700  
23             our @ISA = qw( Exporter::Tiny );
24              
25             sub _exporter_fail {
26 2     2   567 my ( $class, $type_name, $values, $globals ) = @_;
27 2         6 my $caller = $globals->{into};
28            
29 2 100       11 my ( $keys, $vals ) = exists( $values->{of} ) ? @{ $values->{of} } : ( $values->{keys}, $values->{values} );
  1         5  
30 2 50       8 defined $keys or _croak( qq{Expected option "keys" for type "$type_name"} );
31 2 50       7 defined $vals or _croak( qq{Expected option "values" for type "$type_name"} );
32            
33 2 100       86 if ( not Types::TypeTiny::is_TypeTiny($keys) ) {
34 1         696 require Type::Utils;
35 1         9 $keys = Type::Utils::dwim_type( $keys, for => $caller );
36             }
37              
38 2 100       82 if ( not Types::TypeTiny::is_TypeTiny($vals) ) {
39 1         13 require Type::Utils;
40 1         4 $vals = Type::Utils::dwim_type( $vals, for => $caller );
41             }
42            
43 2         11 my $type = Types::Standard::Map->of( $keys, $vals );
44             $type = $type->create_child_type(
45             name => $type_name,
46             $type->has_coercion ? ( coercion => 1 ) : (),
47 2 50       10 exists( $values->{where} ) ? ( constraint => $values->{where} ) : (),
    50          
48             );
49            
50             $INC{'Type/Registry.pm'}
51             ? 'Type::Registry'->for_class( $caller )->add_type( $type, $type_name )
52             : ( $Type::Registry::DELAYED{$caller}{$type_name} = $type )
53 2 100 33     32 unless( ref($caller) or $caller eq '-lexical' or $globals->{'lexical'} );
    50 33        
54 2         6 return map +( $_->{name} => $_->{code} ), @{ $type->exportables };
  2         9  
55             }
56              
57             my $meta = Types::Standard->meta;
58              
59 8     8   69 no warnings;
  8         28  
  8         15128  
60              
61             sub __constraint_generator {
62 30 50   30   109 return $meta->get_type( 'Map' ) unless @_;
63            
64 30         154 Type::Tiny::check_parameter_count_for_parameterized_type( 'Types::Standard', 'Map', \@_, 2, 2 );
65 28         83 my ( $keys, $values ) = @_;
66 28 100       676 Types::TypeTiny::is_TypeTiny( $keys )
67             or _croak(
68             "First parameter to Map[`k,`v] expected to be a type constraint; got $keys" );
69 26 100       554 Types::TypeTiny::is_TypeTiny( $values )
70             or _croak(
71             "Second parameter to Map[`k,`v] expected to be a type constraint; got $values"
72             );
73            
74 25         60 my @xsub;
75 25         38 if ( Type::Tiny::_USE_XS ) {
76             my @known = map {
77 25         66 my $known = Type::Tiny::XS::is_known( $_->compiled_check );
  50         170  
78 50 100       511 defined( $known ) ? $known : ();
79             } ( $keys, $values );
80            
81 25 100       91 if ( @known == 2 ) {
82 18         797 my $xsub = Type::Tiny::XS::get_coderef_for( sprintf "Map[%s,%s]", @known );
83 18 50       1113 push @xsub, $xsub if $xsub;
84             }
85             } #/ if ( Type::Tiny::_USE_XS)
86            
87             sub {
88 25     25   66 my $hash = shift;
89 25   100     148 $keys->check( $_ ) || return for keys %$hash;
90 21   100     86 $values->check( $_ ) || return for values %$hash;
91 15         87 return !!1;
92 25         240 }, @xsub;
93             } #/ sub __constraint_generator
94              
95             sub __inline_generator {
96 25     25   68 my ( $k, $v ) = @_;
97 25 50 33     129 return unless $k->can_be_inlined && $v->can_be_inlined;
98            
99 25         53 my $xsubname;
100 25         41 if ( Type::Tiny::_USE_XS ) {
101             my @known = map {
102 25         62 my $known = Type::Tiny::XS::is_known( $_->compiled_check );
  50         127  
103 50 100       376 defined( $known ) ? $known : ();
104             } ( $k, $v );
105            
106 25 100       87 if ( @known == 2 ) {
107 18         117 $xsubname = Type::Tiny::XS::get_subname_for( sprintf "Map[%s,%s]", @known );
108             }
109             } #/ if ( Type::Tiny::_USE_XS)
110            
111             return sub {
112 328     328   604 my $h = $_[1];
113 328 100 100     1711 return "$xsubname\($h\)" if $xsubname && !$Type::Tiny::AvoidCallbacks;
114 69         283 my $p = Types::Standard::HashRef->inline_check( $h );
115 69         299 my $k_check = $k->inline_check( '$k' );
116 69         235 my $v_check = $v->inline_check( '$v' );
117 69         408 "$p and do { "
118             . "my \$ok = 1; "
119             . "for my \$v (values \%{$h}) { "
120             . "(\$ok = 0, last) unless $v_check " . "}; "
121             . "for my \$k (keys \%{$h}) { "
122             . "(\$ok = 0, last) unless $k_check " . "}; " . "\$ok " . "}";
123 25         439 };
124             } #/ sub __inline_generator
125              
126             sub __deep_explanation {
127 2     2   15 require B;
128 2         6 my ( $type, $value, $varname ) = @_;
129 2         20 my ( $kparam, $vparam ) = @{ $type->parameters };
  2         9  
130            
131 2         12 for my $k ( sort keys %$value ) {
132 3 100       16 unless ( $kparam->check( $k ) ) {
133             return [
134             sprintf( '"%s" constrains each key in the hash with "%s"', $type, $kparam ),
135             @{
136 1         5 $kparam->validate_explain(
  1         9  
137             $k, sprintf( 'key %s->{%s}', $varname, B::perlstring( $k ) )
138             )
139             },
140             ];
141             } #/ unless ( $kparam->check( $k...))
142            
143 2 100       8 unless ( $vparam->check( $value->{$k} ) ) {
144             return [
145             sprintf( '"%s" constrains each value in the hash with "%s"', $type, $vparam ),
146             @{
147 1         6 $vparam->validate_explain(
148 1         32 $value->{$k}, sprintf( '%s->{%s}', $varname, B::perlstring( $k ) )
149             )
150             },
151             ];
152             } #/ unless ( $vparam->check( $value...))
153             } #/ for my $k ( sort keys %$value)
154            
155             # This should never happen...
156 0         0 return; # uncoverable statement
157             } #/ sub __deep_explanation
158              
159             sub __coercion_generator {
160 16     16   67 my ( $parent, $child, $kparam, $vparam ) = @_;
161 16 100 100     72 return unless $kparam->has_coercion || $vparam->has_coercion;
162            
163 6 100       32 my $kcoercable_item =
164             $kparam->has_coercion
165             ? $kparam->coercion->_source_type_union
166             : $kparam;
167 6 50       23 my $vcoercable_item =
168             $vparam->has_coercion
169             ? $vparam->coercion->_source_type_union
170             : $vparam;
171 6         57 my $C = "Type::Coercion"->new( type_constraint => $child );
172            
173 6 100 100     23 if ( ( !$kparam->has_coercion or $kparam->coercion->can_be_inlined )
      66        
      100        
      66        
      66        
174             and ( !$vparam->has_coercion or $vparam->coercion->can_be_inlined )
175             and $kcoercable_item->can_be_inlined
176             and $vcoercable_item->can_be_inlined )
177             {
178             $C->add_type_coercions(
179             $parent => Types::Standard::Stringable {
180 3     3   7 my @code;
181 3         9 push @code, 'do { my ($orig, $return_orig, %new) = ($_, 0);';
182 3         7 push @code, 'for (keys %$orig) {';
183 3         39 push @code,
184             sprintf(
185             '++$return_orig && last unless (%s);',
186             $kcoercable_item->inline_check( '$_' )
187             );
188 3         13 push @code,
189             sprintf(
190             '++$return_orig && last unless (%s);',
191             $vcoercable_item->inline_check( '$orig->{$_}' )
192             );
193 3 50       13 push @code, sprintf(
    50          
194             '$new{(%s)} = (%s);',
195             $kparam->has_coercion ? $kparam->coercion->inline_coercion( '$_' ) : '$_',
196             $vparam->has_coercion
197             ? $vparam->coercion->inline_coercion( '$orig->{$_}' )
198             : '$orig->{$_}',
199             );
200 3         14 push @code, '}';
201 3         9 push @code, '$return_orig ? $orig : \\%new';
202 3         8 push @code, '}';
203 3         60 "@code";
204             }
205 4         60 );
206             } #/ if ( ( !$kparam->has_coercion...))
207             else {
208             $C->add_type_coercions(
209             $parent => sub {
210 3 50   3   38 my $value = @_ ? $_[0] : $_;
211 3         4 my %new;
212 3         10 for my $k ( keys %$value ) {
213             return $value
214             unless $kcoercable_item->check( $k )
215 6 100 66     68 && $vcoercable_item->check( $value->{$k} );
216             $new{ $kparam->has_coercion ? $kparam->coerce( $k ) : $k } =
217             $vparam->has_coercion
218             ? $vparam->coerce( $value->{$k} )
219 5 50       32 : $value->{$k};
    50          
220             }
221 2         32 return \%new;
222             },
223 2         17 );
224             } #/ else [ if ( ( !$kparam->has_coercion...))]
225            
226 6         26 return $C;
227             } #/ sub __coercion_generator
228              
229             sub __hashref_allows_key {
230 45     45   119 my $self = shift;
231 45         125 my ( $key ) = @_;
232            
233 45 100       259 return Types::Standard::is_Str( $key ) if $self == Types::Standard::Map();
234            
235             my $map = $self->find_parent(
236 39 50   43   357 sub { $_->has_parent && $_->parent == Types::Standard::Map() } );
  43         168  
237 39         267 my ( $kcheck, $vcheck ) = @{ $map->parameters };
  39         143  
238            
239 39   33     128 ( $kcheck or Types::Standard::Any() )->check( $key );
240             } #/ sub __hashref_allows_key
241              
242             sub __hashref_allows_value {
243 10     10   35 my $self = shift;
244 10         32 my ( $key, $value ) = @_;
245            
246 10 100       59 return !!0 unless $self->my_hashref_allows_key( $key );
247 7 50       31 return !!1 if $self == Types::Standard::Map();
248            
249             my $map = $self->find_parent(
250 7 50   7   66 sub { $_->has_parent && $_->parent == Types::Standard::Map() } );
  7         27  
251 7         33 my ( $kcheck, $vcheck ) = @{ $map->parameters };
  7         31  
252            
253 7 50 33     21 ( $kcheck or Types::Standard::Any() )->check( $key )
      33        
254             and ( $vcheck or Types::Standard::Any() )->check( $value );
255             } #/ sub __hashref_allows_value
256              
257             1;
258              
259             __END__