• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tobyink / p5-type-tiny / 2ebf471f5

19 Mar 2025 06:41PM UTC coverage: 99.603% (-0.08%) from 99.682%
2ebf471f5

push

github

3764 of 3779 relevant lines covered (99.6%)

29352.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.72
/lib/Type/Tiny.pm
1
package Type::Tiny;
2

3
use 5.008001;
2,660✔
4
use strict;
2,660✔
5
use warnings;
2,660✔
6

7
BEGIN {
8
        if ( $] < 5.010 ) { require Devel::TypeTiny::Perl58Compat }
2,660✔
9
}
10

11
BEGIN {
12
        $Type::Tiny::AUTHORITY  = 'cpan:TOBYINK';
2,660✔
13
        $Type::Tiny::VERSION    = '2.008002';
2,660✔
14
        $Type::Tiny::XS_VERSION = '0.016';
2,660✔
15
}
16

17
$Type::Tiny::VERSION    =~ tr/_//d;
18
$Type::Tiny::XS_VERSION =~ tr/_//d;
19

20
our @InternalPackages = qw(
21
        Devel::TypeTiny::Perl56Compat
22
        Devel::TypeTiny::Perl58Compat
23
        Error::TypeTiny
24
        Error::TypeTiny::Assertion
25
        Error::TypeTiny::Compilation
26
        Error::TypeTiny::WrongNumberOfParameters
27
        Eval::TypeTiny
28
        Eval::TypeTiny::CodeAccumulator
29
        Eval::TypeTiny::Sandbox
30
        Exporter::Tiny
31
        Reply::Plugin::TypeTiny
32
        Test::TypeTiny
33
        Type::Coercion
34
        Type::Coercion::FromMoose
35
        Type::Coercion::Union
36
        Type::Library
37
        Type::Params
38
        Type::Params::Alternatives
39
        Type::Params::Parameter
40
        Type::Params::Signature
41
        Type::Parser
42
        Type::Parser::AstBuilder
43
        Type::Parser::Token
44
        Type::Parser::TokenStream
45
        Type::Registry
46
        Types::Common
47
        Types::Common::Numeric
48
        Types::Common::String
49
        Types::Standard
50
        Types::Standard::_Stringable
51
        Types::Standard::ArrayRef
52
        Types::Standard::CycleTuple
53
        Types::Standard::Dict
54
        Types::Standard::HashRef
55
        Types::Standard::Map
56
        Types::Standard::ScalarRef
57
        Types::Standard::StrMatch
58
        Types::Standard::Tied
59
        Types::Standard::Tuple
60
        Types::TypeTiny
61
        Type::Tie
62
        Type::Tie::ARRAY
63
        Type::Tie::BASE
64
        Type::Tie::HASH
65
        Type::Tie::SCALAR
66
        Type::Tiny
67
        Type::Tiny::_DeclaredType
68
        Type::Tiny::_HalfOp
69
        Type::Tiny::Class
70
        Type::Tiny::ConsrtainedObject
71
        Type::Tiny::Duck
72
        Type::Tiny::Enum
73
        Type::Tiny::Intersection
74
        Type::Tiny::Role
75
        Type::Tiny::Union
76
        Type::Utils
77
);
78

79
use Scalar::Util qw( blessed );
2,660✔
80
use Types::TypeTiny ();
2,660✔
81

82
our $SafePackage = sprintf 'package %s;', __PACKAGE__;
83

84
sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
128✔
85

86
sub _swap { $_[2] ? @_[ 1, 0 ] : @_[ 0, 1 ] }
161,268✔
87

88
BEGIN {
89
        my $support_smartmatch = 0+ !!( $] >= 5.010001 && $] <= 5.041002 );
2,688✔
90
        eval qq{ sub SUPPORT_SMARTMATCH () { !! $support_smartmatch } };
2,688✔
91
        
92
        my $fixed_precedence = 0+ !!( $] >= 5.014 );
2,688✔
93
        eval qq{ sub _FIXED_PRECEDENCE () { !! $fixed_precedence } };
2,688✔
94
        
95
        my $try_xs =
96
                exists( $ENV{PERL_TYPE_TINY_XS} ) ? !!$ENV{PERL_TYPE_TINY_XS}
97
                : exists( $ENV{PERL_ONLY} )       ? !$ENV{PERL_ONLY}
98
                :                                   1;
2,688✔
99
                
100
        my $use_xs = 0;
2,688✔
101
        $try_xs and eval {
2,688✔
102
                require Type::Tiny::XS;
1,340✔
103
                'Type::Tiny::XS'->VERSION( $Type::Tiny::XS_VERSION );
1,336✔
104
                $use_xs++;
1,336✔
105
        };
106
        
107
        *_USE_XS =
108
                $use_xs
109
                ? sub () { !!1 }
110
                : sub () { !!0 };
2,688✔
111
                
112
        *_USE_MOUSE =
113
                $try_xs
114
                ? sub () { $INC{'Mouse/Util.pm'} and Mouse::Util::MOUSE_XS() }
1,316✔
115
                : sub () { !!0 };
2,688✔
116
        
117
        my $strict_mode = 0;
2,688✔
118
        $ENV{$_} && ++$strict_mode for qw(
2,688✔
119
                EXTENDED_TESTING
120
                AUTHOR_TESTING
121
                RELEASE_TESTING
122
                PERL_STRICT
123
        );
124
        *_STRICT_MODE = $strict_mode ? sub () { !!1 } : sub () { !!0 };
2,688✔
125
} #/ BEGIN
126

127
{
128

129
        sub _install_overloads {
130
                no strict 'refs';
2,688✔
131
                no warnings 'redefine', 'once';
2,688✔
132
                
133
                # Coverage is checked on Perl 5.26
134
                if ( $] < 5.010 ) {    # uncoverable statement
135
                        require overload;             # uncoverable statement
136
                        push @_, fallback => 1;       # uncoverable statement
137
                        goto \&overload::OVERLOAD;    # uncoverable statement
138
                }
139
                
140
                my $class = shift;
18,680✔
141
                *{ $class . '::((' } = sub { };
18,680✔
142
                *{ $class . '::()' } = sub { };
18,680✔
143
                *{ $class . '::()' } = do { my $x = 1; \$x };
18,680✔
144
                while ( @_ ) {
18,680✔
145
                        my $f = shift;
66,800✔
146
                        *{ $class . '::(' . $f } = ref $_[0] ? shift : do {
66,800✔
147
                                my $m = shift;
5,296✔
148
                                sub { shift->$m( @_ ) }
7,776✔
149
                        };
5,296✔
150
                }
151
        } #/ sub _install_overloads
152
}
153

154
__PACKAGE__->_install_overloads(
155
        q("") => sub {
156
                caller =~ m{^(Moo::HandleMoose|Sub::Quote)}
445,630✔
157
                        ? $_[0]->_stringify_no_magic
158
                        : $_[0]->display_name;
159
        },
160
        q(bool) => sub { 1 },
395,204✔
161
        q(&{})  => "_overload_coderef",
162
        q(|)    => sub {
163
                my @tc = _swap @_;
556✔
164
                if ( !_FIXED_PRECEDENCE && $_[2] ) {
556✔
165
                        if ( blessed $tc[0] ) {
166
                                if ( blessed $tc[0] eq "Type::Tiny::_HalfOp" ) {
167
                                        my $type  = $tc[0]->{type};
168
                                        my $param = $tc[0]->{param};
169
                                        my $op    = $tc[0]->{op};
170
                                        require Type::Tiny::Union;
171
                                        return "Type::Tiny::_HalfOp"->new(
172
                                                $op,
173
                                                $param,
174
                                                "Type::Tiny::Union"->new_by_overload( type_constraints => [ $type, $tc[1] ] ),
175
                                        );
176
                                } #/ if ( blessed $tc[0] eq...)
177
                        } #/ if ( blessed $tc[0] )
178
                        elsif ( ref $tc[0] eq 'ARRAY' ) {
179
                                require Type::Tiny::_HalfOp;
180
                                return "Type::Tiny::_HalfOp"->new( '|', @tc );
181
                        }
182
                } #/ if ( !_FIXED_PRECEDENCE...)
183
                require Type::Tiny::Union;
556✔
184
                return "Type::Tiny::Union"->new_by_overload( type_constraints => \@tc );
556✔
185
        },
186
        q(&) => sub {
187
                my @tc = _swap @_;
160,472✔
188
                if ( !_FIXED_PRECEDENCE && $_[2] ) {
160,472✔
189
                        if ( blessed $tc[0] ) {
190
                                if ( blessed $tc[0] eq "Type::Tiny::_HalfOp" ) {
191
                                        my $type  = $tc[0]->{type};
192
                                        my $param = $tc[0]->{param};
193
                                        my $op    = $tc[0]->{op};
194
                                        require Type::Tiny::Intersection;
195
                                        return "Type::Tiny::_HalfOp"->new(
196
                                                $op,
197
                                                $param,
198
                                                "Type::Tiny::Intersection"->new_by_overload( type_constraints => [ $type, $tc[1] ] ),
199
                                        );
200
                                } #/ if ( blessed $tc[0] eq...)
201
                        } #/ if ( blessed $tc[0] )
202
                        elsif ( ref $tc[0] eq 'ARRAY' ) {
203
                                require Type::Tiny::_HalfOp;
204
                                return "Type::Tiny::_HalfOp"->new( '&', @tc );
205
                        }
206
                } #/ if ( !_FIXED_PRECEDENCE...)
207
                require Type::Tiny::Intersection;
160,472✔
208
                "Type::Tiny::Intersection"->new_by_overload( type_constraints => \@tc );
160,472✔
209
        },
210
        q(~)  => sub { shift->complementary_type },
552✔
211
        q(==) => sub { $_[0]->equals( $_[1] ) },
5,752✔
212
        q(!=) => sub { not $_[0]->equals( $_[1] ) },
8✔
213
        q(<)  => sub { my $m = $_[0]->can( 'is_subtype_of' ); $m->( _swap @_ ) },
64✔
214
        q(>)  => sub {
215
                my $m = $_[0]->can( 'is_subtype_of' );
80✔
216
                $m->( reverse _swap @_ );
80✔
217
        },
218
        q(<=) => sub { my $m = $_[0]->can( 'is_a_type_of' ); $m->( _swap @_ ) },
48✔
219
        q(>=) => sub {
220
                my $m = $_[0]->can( 'is_a_type_of' );
48✔
221
                $m->( reverse _swap @_ );
48✔
222
        },
223
        q(eq)  => sub { "$_[0]" eq "$_[1]" },
224✔
224
        q(cmp) => sub { $_[2] ? ( "$_[1]" cmp "$_[0]" ) : ( "$_[0]" cmp "$_[1]" ) },
8✔
225
        q(0+)  => sub { $_[0]{uniq} },
8✔
226
        q(/)   => sub { ( _STRICT_MODE xor $_[2] ) ? $_[0] : $_[1] },
32✔
227
);
228

229
__PACKAGE__->_install_overloads(
230
        q(~~) => sub { $_[0]->check( $_[1] ) },
24✔
231
) if Type::Tiny::SUPPORT_SMARTMATCH;
232

233
# Would be easy to just return sub { $self->assert_return(@_) }
234
# but try to build a more efficient coderef whenever possible.
235
#
236
sub _overload_coderef {
237
        my $self = shift;
126,456✔
238
        
239
        # Bypass generating a coderef if we've already got the best possible one.
240
        #
241
        return $self->{_overload_coderef} if $self->{_overload_coderef_no_rebuild};
126,456✔
242
        
243
        # Subclasses of Type::Tiny might override assert_return to do some kind
244
        # of interesting thing. In that case, we can't rely on it having identical
245
        # behaviour to Type::Tiny::inline_assert.
246
        #
247
        $self->{_overrides_assert_return} =
248
                ( $self->can( 'assert_return' ) != \&assert_return )
249
                unless exists $self->{_overrides_assert_return};
125,984✔
250
                
251
        if ( $self->{_overrides_assert_return} ) {
125,984✔
252
                $self->{_overload_coderef} ||= do {
8✔
253
                        Scalar::Util::weaken( my $weak = $self );
8✔
254
                        sub { $weak->assert_return( @_ ) };
8✔
255
                };
256
                ++$self->{_overload_coderef_no_rebuild};
8✔
257
        }
258
        elsif ( exists( &Sub::Quote::quote_sub ) ) {
259
        
260
                # Use `=` instead of `||=` because we want to overwrite non-Sub::Quote
261
                # coderef if possible.
262
                $self->{_overload_coderef} = $self->can_be_inlined
3,124✔
263
                        ? Sub::Quote::quote_sub(
264
                        $self->inline_assert( '$_[0]' ),
265
                        )
266
                        : Sub::Quote::quote_sub(
267
                        $self->inline_assert( '$_[0]', '$type' ),
268
                        { '$type' => \$self },
269
                        );
270
                ++$self->{_overload_coderef_no_rebuild};
3,124✔
271
        } #/ elsif ( exists( &Sub::Quote::quote_sub...))
272
        else {
273
                require Eval::TypeTiny;
122,852✔
274
                $self->{_overload_coderef} ||= $self->can_be_inlined
122,852✔
275
                        ? Eval::TypeTiny::eval_closure(
276
                        source => sprintf(
277
                                'sub { %s }', $self->inline_assert( '$_[0]', undef, no_wrapper => 1 )
278
                        ),
279
                        description => sprintf( "compiled assertion 'assert_%s'", $self ),
280
                        )
281
                        : Eval::TypeTiny::eval_closure(
282
                        source => sprintf(
283
                                'sub { %s }', $self->inline_assert( '$_[0]', '$type', no_wrapper => 1 )
284
                        ),
285
                        description => sprintf( "compiled assertion 'assert_%s'", $self ),
286
                        environment => { '$type' => \$self },
287
                        );
288
        } #/ else [ if ( $self->{_overrides_assert_return...})]
289
        
290
        $self->{_overload_coderef};
125,984✔
291
} #/ sub _overload_coderef
292

293
our %ALL_TYPES;
294

295
my $QFS;
296
my $uniq = 1;
297

298
sub new {
299
        my $class  = shift;
453,116✔
300
        my %params = ( @_ == 1 ) ? %{ $_[0] } : @_;
453,116✔
301
        
302
        for ( qw/ name display_name library / ) {
453,116✔
303
                $params{$_} = $params{$_} . '' if defined $params{$_};
1,359,348✔
304
        }
305
        
306
        my $level = 0;
453,116✔
307
        while ( not exists $params{definition_context} and $level < 20 ) {
453,116✔
308
                our $_TT_GUTS ||= do {
1,079,292✔
309
                        my $g = join '|', map quotemeta, grep !m{^Types::}, @InternalPackages;
2,632✔
310
                        qr/\A(?:$g)\z/o
2,632✔
311
                };
312
                my $package = caller $level;
1,079,292✔
313
                if ( $package !~ $_TT_GUTS ) {
1,079,292✔
314
                        @{ $params{definition_context} = {} }{ qw/ package file line / } = caller $level;
453,116✔
315
                }
316
                ++$level;
1,079,292✔
317
        }
318
        
319
        if ( exists $params{parent} ) {
453,116✔
320
                $params{parent} =
321
                        ref( $params{parent} ) =~ /^Type::Tiny\b/
322
                        ? $params{parent}
323
                        : Types::TypeTiny::to_TypeTiny( $params{parent} );
107,568✔
324
                        
325
                _croak "Parent must be an instance of %s", __PACKAGE__
326
                        unless blessed( $params{parent} )
327
                        && $params{parent}->isa( __PACKAGE__ );
107,568✔
328
                        
329
                if ( $params{parent}->deprecated and not exists $params{deprecated} ) {
107,568✔
330
                        $params{deprecated} = 1;
24✔
331
                }
332
        } #/ if ( exists $params{parent...})
333
        
334
        if ( exists $params{constraint}
453,116✔
335
                and defined $params{constraint}
336
                and not ref $params{constraint} )
337
        {
338
                require Eval::TypeTiny;
632✔
339
                my $code = $params{constraint};
632✔
340
                $params{constraint} = Eval::TypeTiny::eval_closure(
632✔
341
                        source      => sprintf( 'sub ($) { %s }', $code ),
342
                        description => "anonymous check",
343
                );
344
                $params{inlined} ||= sub {
345
                        my ( $type ) = @_;
1,582✔
346
                        my $inlined  = $_ eq '$_' ? "do { $code }" : "do { local \$_ = $_; $code }";
1,582✔
347
                        $type->has_parent ? ( undef, $inlined ) : $inlined;
1,582✔
348
                        }
349
                        if ( !exists $params{parent} or $params{parent}->can_be_inlined );
632✔
350
        } #/ if ( exists $params{constraint...})
351
        
352
        # canonicalize to a boolean
353
        $params{deprecated} = !!$params{deprecated};
453,116✔
354
        
355
        $params{name} = "__ANON__" unless exists $params{name};
453,116✔
356
        $params{uniq} = $uniq++;
453,116✔
357
        
358
        if ( $params{name} ne "__ANON__" ) {
453,116✔
359
        
360
                # First try a fast ASCII-only expression, but fall back to Unicode
361
                $params{name} =~ /^_{0,2}[A-Z][A-Za-z0-9_]+$/sm
362
                        or eval q( use 5.008; $params{name} =~ /^_{0,2}\p{Lu}[\p{L}0-9_]+$/sm )
363
                        or _croak '"%s" is not a valid type name', $params{name};
113,540✔
364
        }
365
        
366
        if ( exists $params{coercion} and !ref $params{coercion} and $params{coercion} )
453,108✔
367
        {
368
                $params{parent}->has_coercion
369
                        or _croak
48✔
370
                        "coercion => 1 requires type to have a direct parent with a coercion";
371
                        
372
                $params{coercion} = $params{parent}->coercion->type_coercion_map;
48✔
373
        }
374
        
375
        if ( !exists $params{inlined}
453,108✔
376
                and exists $params{constraint}
377
                and ( !exists $params{parent} or $params{parent}->can_be_inlined )
378
                and $QFS ||= "Sub::Quote"->can( "quoted_from_sub" ) )
379
        {
380
                my ( undef, $perlstring, $captures ) = @{ $QFS->( $params{constraint} ) || [] };
80✔
381
                
382
                $params{inlined} = sub {
383
                        my ( $self, $var ) = @_;
144✔
384
                        my $code = Sub::Quote::inlinify(
144✔
385
                                $perlstring,
386
                                $var,
387
                                $var eq q($_) ? '' : "local \$_ = $var;",
388
                                1,
389
                        );
390
                        $code = sprintf( '%s and %s', $self->parent->inline_check( $var ), $code )
144✔
391
                                if $self->has_parent;
392
                        return $code;
144✔
393
                        }
394
                        if $perlstring && !$captures;
80✔
395
        } #/ if ( !exists $params{inlined...})
396
        
397
        my $self = bless \%params, $class;
453,108✔
398
        
399
        unless ( $params{tmp} ) {
453,108✔
400
                my $uniq = $self->{uniq};
452,600✔
401
                
402
                $ALL_TYPES{$uniq} = $self;
452,600✔
403
                Scalar::Util::weaken( $ALL_TYPES{$uniq} );
452,600✔
404
                
405
                my $tmp = $self;
452,600✔
406
                Scalar::Util::weaken( $tmp );
452,600✔
407
                $Moo::HandleMoose::TYPE_MAP{ $self->_stringify_no_magic } = sub { $tmp };
452,600✔
408
        } #/ unless ( $params{tmp} )
409
        
410
        if ( ref( $params{coercion} ) eq q(CODE) ) {
453,108✔
411
                require Types::Standard;
24✔
412
                my $code = delete( $params{coercion} );
24✔
413
                $self->{coercion} = $self->_build_coercion;
24✔
414
                $self->coercion->add_type_coercions( Types::Standard::Any(), $code );
24✔
415
        }
416
        elsif ( ref( $params{coercion} ) eq q(ARRAY) ) {
417
                my $arr = delete( $params{coercion} );
72✔
418
                $self->{coercion} = $self->_build_coercion;
72✔
419
                $self->coercion->add_type_coercions( @$arr );
72✔
420
        }
421
        
422
        # Documenting this here because it's too weird to be in the pod.
423
        # There's a secret attribute called "_build_coercion" which takes a
424
        # coderef. If present, then when $type->coercion is lazy built,
425
        # the blank Type::Coercion object gets passed to the coderef,
426
        # allowing the coderef to manipulate it a little. This is used by
427
        # Types::TypeTiny to allow it to build a coercion for the TypeTiny
428
        # type constraint without needing to load Type::Coercion yet.
429
        
430
        if ( $params{my_methods} ) {
453,108✔
431
                require Eval::TypeTiny;
9,704✔
432
                Scalar::Util::reftype( $params{my_methods}{$_} ) eq 'CODE'
433
                        and /\A[^0-9\W]\w+\z/
434
                        and Eval::TypeTiny::set_subname(
435
                                sprintf( "%s::my_%s", $self->qualified_name, $_ ),
436
                                $params{my_methods}{$_},
437
                        ) for keys %{ $params{my_methods} };
9,704✔
438
        } #/ if ( $params{my_methods...})
439
        
440
        # In general, mutating a type constraint after it's been created
441
        # is a bad idea and will probably not work. However some places are
442
        # especially harmful and can lead to confusing errors, so allow
443
        # subclasses to lock down particular keys.
444
        #
445
        $self->_lockdown( sub {
446
                &Internals::SvREADONLY( $_, !!1 ) for @_;
163,324✔
447
        } );
453,108✔
448
        
449
        return $self;
453,108✔
450
} #/ sub new
451

452
sub _lockdown {}
453

454
sub DESTROY {
455
        my $self = shift;
333,368✔
456
        delete( $ALL_TYPES{ $self->{uniq} } );
333,368✔
457
        delete( $Moo::HandleMoose::TYPE_MAP{ $self->_stringify_no_magic } );
333,368✔
458
        return;
333,368✔
459
}
460

461
sub _clone {
462
        my $self = shift;
860✔
463
        my %opts;
860✔
464
        $opts{$_} = $self->{$_} for qw< name display_name message >;
860✔
465
        $self->create_child_type( %opts );
860✔
466
}
467

468
sub _stringify_no_magic {
469
        sprintf(
786,000✔
470
                '%s=%s(0x%08x)', blessed( $_[0] ), Scalar::Util::reftype( $_[0] ),
471
                Scalar::Util::refaddr( $_[0] )
472
        );
473
}
474

475
our $DD;
476

477
sub _dd {
478
        @_ = $_ unless @_;
30,004✔
479
        my ( $value ) = @_;
30,004✔
480
        
481
        goto $DD if ref( $DD ) eq q(CODE);
30,004✔
482
        
483
        require B;
29,988✔
484
        
485
        !defined $value  ? 'Undef'
486
                : !ref $value ? sprintf( 'Value %s', B::perlstring( $value ) )
487
                : do {
29,988✔
488
                my $N = 0+ ( defined( $DD ) ? $DD : 72 );
17,056✔
489
                require Data::Dumper;
17,056✔
490
                local $Data::Dumper::Indent   = 0;
17,056✔
491
                local $Data::Dumper::Useqq    = 1;
17,056✔
492
                local $Data::Dumper::Terse    = 1;
17,056✔
493
                local $Data::Dumper::Sortkeys = 1;
17,056✔
494
                local $Data::Dumper::Maxdepth = 2;
17,056✔
495
                my $str;
17,056✔
496
                eval {
497
                        $str = Data::Dumper::Dumper( $value );
17,056✔
498
                        $str = substr( $str, 0, $N - 12 ) . '...' . substr( $str, -1, 1 )
17,056✔
499
                                if length( $str ) >= $N;
500
                        1;
17,056✔
501
                } or do { $str = 'which cannot be dumped' };
17,056✔
502
                "Reference $str";
17,056✔
503
        } #/ do
504
} #/ sub _dd
505

506
sub _loose_to_TypeTiny {
507
        my $caller = caller( 1 ); # assumption
226,988✔
508
        map +(
509
                ref( $_ )
510
                ? Types::TypeTiny::to_TypeTiny( $_ )
511
                : do { require Type::Utils; Type::Utils::dwim_type( $_, for => $caller ) }
226,988✔
512
        ), @_;
513
}
514

515
sub name         { $_[0]{name} }
910,644✔
516
sub display_name { $_[0]{display_name} ||= $_[0]->_build_display_name }
458,134✔
517
sub parent       { $_[0]{parent} }
1,012,062✔
518
sub constraint   { $_[0]{constraint} ||= $_[0]->_build_constraint }
2,306,190✔
519

520
sub compiled_check {
521
        $_[0]{compiled_type_constraint} ||= $_[0]->_build_compiled_check;
588,880✔
522
}
523
sub coercion             { $_[0]{coercion} ||= $_[0]->_build_coercion }
163,320✔
524
sub message              { $_[0]{message} }
528✔
525
sub library              { $_[0]{library} }
544✔
526
sub inlined              { $_[0]{inlined} }
386,482✔
527
sub deprecated           { $_[0]{deprecated} }
283,072✔
528
sub constraint_generator { $_[0]{constraint_generator} }
8,952✔
529
sub inline_generator     { $_[0]{inline_generator} }
9,104✔
530
sub name_generator       { $_[0]{name_generator} ||= $_[0]->_build_name_generator }
7,672✔
531
sub coercion_generator   { $_[0]{coercion_generator} }
1,884✔
532
sub parameters           { $_[0]{parameters} }
8,524✔
533
sub moose_type           { $_[0]{moose_type} ||= $_[0]->_build_moose_type }
3,504✔
534
sub mouse_type           { $_[0]{mouse_type} ||= $_[0]->_build_mouse_type }
32✔
535
sub deep_explanation     { $_[0]{deep_explanation} }
828✔
536
sub my_methods           { $_[0]{my_methods} ||= $_[0]->_build_my_methods }
15,712✔
537
sub sorter               { $_[0]{sorter} }
200✔
538
sub exception_class      { $_[0]{exception_class} ||= $_[0]->_build_exception_class }
208,460✔
539

540
sub has_parent               { exists $_[0]{parent} }
3,766,616✔
541
sub has_library              { exists $_[0]{library} }
672✔
542
sub has_inlined              { exists $_[0]{inlined} }
899,300✔
543
sub has_constraint_generator { exists $_[0]{constraint_generator} }
132,240✔
544
sub has_inline_generator     { exists $_[0]{inline_generator} }
6,984✔
545
sub has_coercion_generator   { exists $_[0]{coercion_generator} }
15,608✔
546
sub has_parameters           { exists $_[0]{parameters} }
4,296✔
547
sub has_message              { defined $_[0]{message} }
13,112✔
548
sub has_deep_explanation     { exists $_[0]{deep_explanation} }
844✔
549
sub has_sorter               { exists $_[0]{sorter} }
592✔
550

551
sub _default_message {
552
        $_[0]{_default_message} ||= $_[0]->_build_default_message;
12,016✔
553
}
554

555
sub has_coercion {
556
        $_[0]->coercion if $_[0]{_build_coercion};    # trigger auto build thing
261,529✔
557
        $_[0]{coercion} and !!@{ $_[0]{coercion}->type_coercion_map };
261,529✔
558
}
559

560
sub _assert_coercion {
561
        my $self = shift;
5,618✔
562
        return $self->coercion if $self->{_build_coercion};    # trigger auto build thing
5,618✔
563
        _croak "No coercion for this type constraint"
564
                unless $self->has_coercion
565
                && @{ $self->coercion->type_coercion_map };
4,450✔
566
        $self->coercion;
4,378✔
567
}
568

569
my $null_constraint = sub { !!1 };
570

571
sub _build_display_name {
572
        shift->name;
111,612✔
573
}
574

575
sub _build_constraint {
576
        return $null_constraint;
40,072✔
577
}
578

579
sub _is_null_constraint {
580
        shift->constraint == $null_constraint;
2,139,970✔
581
}
582

583
sub _build_coercion {
584
        require Type::Coercion;
106,704✔
585
        my $self = shift;
106,704✔
586
        my %opts = ( type_constraint => $self );
106,704✔
587
        $opts{display_name} = "to_$self" unless $self->is_anon;
106,704✔
588
        my $coercion = "Type::Coercion"->new( %opts );
106,704✔
589
        $self->{_build_coercion}->( $coercion ) if ref $self->{_build_coercion};
106,704✔
590
        $coercion;
106,704✔
591
}
592

593
sub _build_default_message {
594
        my $self = shift;
2,204✔
595
        $self->{is_using_default_message} = 1;
2,204✔
596
        return sub { sprintf '%s did not pass type constraint', _dd( $_[0] ) }
536✔
597
                if "$self" eq "__ANON__";
2,204✔
598
        my $name = "$self";
1,956✔
599
        return sub {
600
                sprintf '%s did not pass type constraint "%s"', _dd( $_[0] ), $name;
13,740✔
601
        };
1,956✔
602
} #/ sub _build_default_message
603

604
sub _build_name_generator {
605
        my $self = shift;
1,928✔
606
        return sub {
607
                defined && s/[\x00-\x1F]//smg for ( my ( $s, @a ) = @_ );
6,400✔
608
                sprintf( '%s[%s]', $s, join q[,], map !defined() ? 'undef' : !ref() && /\W/ ? B::perlstring($_) : $_, @a );
6,400✔
609
        };
1,928✔
610
}
611

612
sub _build_compiled_check {
613
        my $self = shift;
172,638✔
614
        
615
        local our $AvoidCallbacks = 0;
172,638✔
616
        
617
        if ( $self->_is_null_constraint and $self->has_parent ) {
172,638✔
618
                return $self->parent->compiled_check;
33,948✔
619
        }
620
        
621
        require Eval::TypeTiny;
138,690✔
622
        return Eval::TypeTiny::eval_closure(
138,690✔
623
                source      => sprintf( 'sub ($) { %s }',      $self->inline_check( '$_[0]' ) ),
624
                description => sprintf( "compiled check '%s'", $self ),
625
        ) if $self->can_be_inlined;
626
        
627
        my @constraints;
82,940✔
628
        push @constraints, $self->parent->compiled_check if $self->has_parent;
82,940✔
629
        push @constraints, $self->constraint             if !$self->_is_null_constraint;
82,940✔
630
        return $null_constraint unless @constraints;
82,940✔
631
        
632
        return sub ($) {
633
                local $_ = $_[0];
37,322✔
634
                for my $c ( @constraints ) {
37,322✔
635
                        return unless $c->( @_ );
60,059✔
636
                }
637
                return !!1;
21,366✔
638
        };
82,940✔
639
} #/ sub _build_compiled_check
640

641
sub _build_exception_class {
642
        my $self = shift;
108,508✔
643
        return $self->parent->exception_class if $self->has_parent;
108,508✔
644
        require Error::TypeTiny::Assertion;
10,376✔
645
        return 'Error::TypeTiny::Assertion';
10,376✔
646
}
647

648
sub definition_context {
649
        my $self  = shift;
8✔
650
        my $found = $self->find_parent(sub {
651
                ref $_->{definition_context} and exists $_->{definition_context}{file};
8✔
652
        });
8✔
653
        $found ? $found->{definition_context} : {};
8✔
654
}
655

656
sub find_constraining_type {
657
        my $self = shift;
32,784✔
658
        if ( $self->_is_null_constraint and $self->has_parent ) {
32,784✔
659
                return $self->parent->find_constraining_type;
6,160✔
660
        }
661
        $self;
26,624✔
662
}
663

664
sub type_default {
665
        my ( $self, @args ) = @_;
5,096✔
666
        if ( exists $self->{type_default} ) {
5,096✔
667
                if ( @args ) {
3,912✔
668
                        my $td = $self->{type_default};
8✔
669
                        return sub { local $_ = \@args; &$td; };
8✔
670
                }
671
                return $self->{type_default};
3,904✔
672
        }
673
        if ( my $parent = $self->parent ) {
1,184✔
674
                return $parent->type_default( @args ) if $self->_is_null_constraint;
1,168✔
675
        }
676
        return undef;
504✔
677
}
678

679
our @CMP;
680

681
sub CMP_SUPERTYPE ()  { -1 }
682
sub CMP_EQUAL ()      { 0 }
683
sub CMP_EQUIVALENT () { '0E0' }
684
sub CMP_SUBTYPE ()    { 1 }
685
sub CMP_UNKNOWN ()    { ''; }
686

687
# avoid getting mixed up with cmp operator at compile time
688
*cmp = sub {
689
        my ( $A, $B ) = _loose_to_TypeTiny( $_[0], $_[1] );
12,796✔
690
        return unless blessed( $A ) && $A->isa( "Type::Tiny" );
12,796✔
691
        return unless blessed( $B ) && $B->isa( "Type::Tiny" );
12,796✔
692
        for my $comparator ( @CMP ) {
12,796✔
693
                my $result = $comparator->( $A, $B );
16,404✔
694
                next if $result eq CMP_UNKNOWN;
16,404✔
695
                if ( $result eq CMP_EQUIVALENT ) {
9,904✔
696
                        my $prefer = @_ == 3 ? $_[2] : CMP_EQUAL;
424✔
697
                        return $prefer;
424✔
698
                }
699
                return $result;
9,480✔
700
        }
701
        return CMP_UNKNOWN;
2,892✔
702
};
703

704
push @CMP, sub {
705
        my ( $A, $B ) = @_;
706
        return CMP_EQUAL
707
                if Scalar::Util::refaddr( $A ) == Scalar::Util::refaddr( $B );
708
                
709
        return CMP_EQUIVALENT
710
                if Scalar::Util::refaddr( $A->compiled_check ) ==
711
                Scalar::Util::refaddr( $B->compiled_check );
712
                
713
        my $A_stem = $A->find_constraining_type;
714
        my $B_stem = $B->find_constraining_type;
715
        return CMP_EQUIVALENT
716
                if Scalar::Util::refaddr( $A_stem ) == Scalar::Util::refaddr( $B_stem );
717
        return CMP_EQUIVALENT
718
                if Scalar::Util::refaddr( $A_stem->compiled_check ) ==
719
                Scalar::Util::refaddr( $B_stem->compiled_check );
720
                
721
        if ( $A_stem->can_be_inlined and $B_stem->can_be_inlined ) {
722
                return CMP_EQUIVALENT
723
                        if $A_stem->inline_check( '$WOLFIE' ) eq $B_stem->inline_check( '$WOLFIE' );
724
        }
725
        
726
        A_IS_SUBTYPE: {
727
                my $A_prime = $A_stem;
728
                while ( $A_prime->has_parent ) {
729
                        $A_prime = $A_prime->parent;
730
                        return CMP_SUBTYPE
731
                                if Scalar::Util::refaddr( $A_prime ) == Scalar::Util::refaddr( $B_stem );
732
                        return CMP_SUBTYPE
733
                                if Scalar::Util::refaddr( $A_prime->compiled_check ) ==
734
                                Scalar::Util::refaddr( $B_stem->compiled_check );
735
                        if ( $A_prime->can_be_inlined and $B_stem->can_be_inlined ) {
736
                                return CMP_SUBTYPE
737
                                        if $A_prime->inline_check( '$WOLFIE' ) eq $B_stem->inline_check( '$WOLFIE' );
738
                        }
739
                } #/ while ( $A_prime->has_parent)
740
        } #/ A_IS_SUBTYPE:
741
        
742
        B_IS_SUBTYPE: {
743
                my $B_prime = $B_stem;
744
                while ( $B_prime->has_parent ) {
745
                        $B_prime = $B_prime->parent;
746
                        return CMP_SUPERTYPE
747
                                if Scalar::Util::refaddr( $B_prime ) == Scalar::Util::refaddr( $A_stem );
748
                        return CMP_SUPERTYPE
749
                                if Scalar::Util::refaddr( $B_prime->compiled_check ) ==
750
                                Scalar::Util::refaddr( $A_stem->compiled_check );
751
                        if ( $A_stem->can_be_inlined and $B_prime->can_be_inlined ) {
752
                                return CMP_SUPERTYPE
753
                                        if $B_prime->inline_check( '$WOLFIE' ) eq $A_stem->inline_check( '$WOLFIE' );
754
                        }
755
                } #/ while ( $B_prime->has_parent)
756
        } #/ B_IS_SUBTYPE:
757
        
758
        return CMP_UNKNOWN;
759
};
760

761
sub equals {
762
        my $result = Type::Tiny::cmp( $_[0], $_[1] );
6,248✔
763
        return unless defined $result;
6,248✔
764
        $result eq CMP_EQUAL;
6,248✔
765
}
766

767
sub is_subtype_of {
768
        my $result = Type::Tiny::cmp( $_[0], $_[1], CMP_SUBTYPE );
808✔
769
        return unless defined $result;
808✔
770
        $result eq CMP_SUBTYPE;
808✔
771
}
772

773
sub is_supertype_of {
774
        my $result = Type::Tiny::cmp( $_[0], $_[1], CMP_SUBTYPE );
168✔
775
        return unless defined $result;
168✔
776
        $result eq CMP_SUPERTYPE;
168✔
777
}
778

779
sub is_a_type_of {
780
        my $result = Type::Tiny::cmp( $_[0], $_[1] );
5,220✔
781
        return unless defined $result;
5,220✔
782
        $result eq CMP_SUBTYPE or $result eq CMP_EQUAL or $result eq CMP_EQUIVALENT;
5,220✔
783
}
784

785
sub strictly_equals {
786
        my ( $self, $other ) = _loose_to_TypeTiny( @_ );
100,132✔
787
        return unless blessed( $self )  && $self->isa( "Type::Tiny" );
100,132✔
788
        return unless blessed( $other ) && $other->isa( "Type::Tiny" );
100,132✔
789
        $self->{uniq} == $other->{uniq};
100,132✔
790
}
791

792
sub is_strictly_subtype_of {
793
        my ( $self, $other ) = _loose_to_TypeTiny( @_ );
96,136✔
794
        return unless blessed( $self )  && $self->isa( "Type::Tiny" );
96,136✔
795
        return unless blessed( $other ) && $other->isa( "Type::Tiny" );
96,136✔
796
        
797
        return unless $self->has_parent;
96,136✔
798
        $self->parent->strictly_equals( $other )
82,072✔
799
                or $self->parent->is_strictly_subtype_of( $other );
800
}
801

802
sub is_strictly_supertype_of {
803
        my ( $self, $other ) = _loose_to_TypeTiny( @_ );
16✔
804
        return unless blessed( $self )  && $self->isa( "Type::Tiny" );
16✔
805
        return unless blessed( $other ) && $other->isa( "Type::Tiny" );
16✔
806
        
807
        $other->is_strictly_subtype_of( $self );
16✔
808
}
809

810
sub is_strictly_a_type_of {
811
        my ( $self, $other ) = _loose_to_TypeTiny( @_ );
17,908✔
812
        return unless blessed( $self )  && $self->isa( "Type::Tiny" );
17,908✔
813
        return unless blessed( $other ) && $other->isa( "Type::Tiny" );
17,908✔
814
        
815
        $self->strictly_equals( $other ) or $self->is_strictly_subtype_of( $other );
17,908✔
816
}
817

818
sub qualified_name {
819
        my $self = shift;
125,284✔
820
        ( exists $self->{library} and $self->name ne "__ANON__" )
821
                ? "$self->{library}::$self->{name}"
822
                : $self->{name};
125,284✔
823
}
824

825
sub is_anon {
826
        my $self = shift;
353,920✔
827
        $self->name eq "__ANON__";
353,920✔
828
}
829

830
sub parents {
831
        my $self = shift;
175,728✔
832
        return unless $self->has_parent;
175,728✔
833
        return ( $self->parent, $self->parent->parents );
146,188✔
834
}
835

836
sub find_parent {
837
        my $self = shift;
3,848✔
838
        my ( $test ) = @_;
3,848✔
839
        
840
        local ( $_, $. );
3,848✔
841
        my $type  = $self;
3,848✔
842
        my $count = 0;
3,848✔
843
        while ( $type ) {
3,848✔
844
                if ( $test->( $_ = $type, $. = $count ) ) {
4,712✔
845
                        return wantarray ? ( $type, $count ) : $type;
3,824✔
846
                }
847
                else {
848
                        $type = $type->parent;
888✔
849
                        $count++;
888✔
850
                }
851
        }
852
        
853
        return;
24✔
854
} #/ sub find_parent
855

856
sub check {
857
        my $self = shift;
668,679✔
858
        ( $self->{compiled_type_constraint} ||= $self->_build_compiled_check )->( @_ );
668,679✔
859
}
860

861
sub _strict_check {
862
        my $self = shift;
23,392✔
863
        local $_ = $_[0];
23,392✔
864
        
865
        my @constraints =
866
                reverse
867
                map { $_->constraint }
83,264✔
868
                grep { not $_->_is_null_constraint } ( $self, $self->parents );
23,392✔
869
                
870
        for my $c ( @constraints ) {
23,392✔
871
                return unless $c->( @_ );
64,340✔
872
        }
873
        
874
        return !!1;
6,772✔
875
} #/ sub _strict_check
876

877
sub get_message {
878
        my $self = shift;
11,248✔
879
        local $_ = $_[0];
11,248✔
880
        $self->has_message
11,248✔
881
                ? $self->message->( @_ )
882
                : $self->_default_message->( @_ );
883
}
884

885
sub validate {
886
        my $self = shift;
24✔
887
        
888
        return undef
889
                if ( $self->{compiled_type_constraint} ||= $self->_build_compiled_check )
24✔
890
                ->( @_ );
891
                
892
        local $_ = $_[0];
24✔
893
        return $self->get_message( @_ );
24✔
894
} #/ sub validate
895

896
sub validate_explain {
897
        my $self = shift;
17,288✔
898
        my ( $value, $varname ) = @_;
17,288✔
899
        $varname = '$_' unless defined $varname;
17,288✔
900
        
901
        return undef if $self->check( $value );
17,288✔
902
        
903
        if ( $self->has_parent ) {
13,624✔
904
                my $parent = $self->parent->validate_explain( $value, $varname );
13,552✔
905
                return [
906
                        sprintf( '"%s" is a subtype of "%s"', $self, $self->parent ),
13,552✔
907
                        @$parent
908
                        ]
909
                        if $parent;
910
        }
911
        
912
        my $message = sprintf(
3,736✔
913
                '%s%s',
914
                $self->get_message( $value ),
915
                $varname eq q{$_} ? '' : sprintf( ' (in %s)', $varname ),
916
        );
917
        
918
        if ( $self->is_parameterized and $self->parent->has_deep_explanation ) {
3,736✔
919
                my $deep = $self->parent->deep_explanation->( $self, $value, $varname );
828✔
920
                return [ $message, @$deep ] if $deep;
828✔
921
        }
922

923
        local $SIG{__WARN__} = sub {};
2,908✔
924
        return [
925
                $message,
2,908✔
926
                sprintf( '"%s" is defined as: %s', $self, $self->_perlcode )
927
        ];
928
} #/ sub validate_explain
929

930
my $b;
931

932
sub _perlcode {
933
        my $self = shift;
2,908✔
934
        
935
        local our $AvoidCallbacks = 1;
2,908✔
936
        return $self->inline_check( '$_' )
2,908✔
937
                if $self->can_be_inlined;
938
                
939
        $b ||= do {
104✔
940
                local $@;
64✔
941
                require B::Deparse;
64✔
942
                my $tmp = "B::Deparse"->new;
64✔
943
                $tmp->ambient_pragmas( strict => "all", warnings => "all" )
64✔
944
                        if $tmp->can( 'ambient_pragmas' );
945
                $tmp;
64✔
946
        };
947
        
948
        my $code = $b->coderef2text( $self->constraint );
104✔
949
        $code =~ s/\s+/ /g;
104✔
950
        return "sub $code";
104✔
951
} #/ sub _perlcode
952

953
sub assert_valid {
954
        my $self = shift;
680✔
955
        
956
        return !!1
957
                if ( $self->{compiled_type_constraint} ||= $self->_build_compiled_check )
680✔
958
                ->( @_ );
959
                
960
        local $_ = $_[0];
120✔
961
        $self->_failed_check( "$self", $_ );
120✔
962
} #/ sub assert_valid
963

964
sub assert_return {
965
        my $self = shift;
460,708✔
966
        
967
        return $_[0]
968
                if ( $self->{compiled_type_constraint} ||= $self->_build_compiled_check )
460,708✔
969
                ->( @_ );
970
                
971
        local $_ = $_[0];
8✔
972
        $self->_failed_check( "$self", $_ );
8✔
973
} #/ sub assert_return
974

975
sub can_be_inlined {
976
        my $self = shift;
1,236,568✔
977
        return $self->parent->can_be_inlined
1,236,568✔
978
                if $self->has_parent && $self->_is_null_constraint;
979
        return !!1
1,027,878✔
980
                if !$self->has_parent && $self->_is_null_constraint;
981
        return $self->has_inlined;
920,374✔
982
}
983

984
sub inline_check {
985
        my $self = shift;
517,218✔
986
        _croak 'Cannot inline type constraint check for "%s"', $self
517,218✔
987
                unless $self->can_be_inlined;
988
                
989
        return $self->parent->inline_check( @_ )
517,218✔
990
                if $self->has_parent && $self->_is_null_constraint;
991
        return '(!!1)'
431,790✔
992
                if !$self->has_parent && $self->_is_null_constraint;
993
                
994
        local $_ = $_[0];
397,320✔
995
        my @r = $self->inlined->( $self, @_ );
397,320✔
996
        if ( @r and not defined $r[0] ) {
397,320✔
997
                _croak 'Inlining type constraint check for "%s" returned undef!', $self
46,548✔
998
                        unless $self->has_parent;
999
                $r[0] = $self->parent->inline_check( @_ );
46,548✔
1000
        }
1001
        my $r = join " && " => map {
1002
                /[;{}]/ && !/\Ado \{.+\}\z/
397,320✔
1003
                        ? "do { $SafePackage $_ }"
1004
                        : "($_)"
1005
        } @r;
1006
        return @r == 1 ? $r : "($r)";
397,320✔
1007
} #/ sub inline_check
1008

1009
sub inline_assert {
1010
        require B;
107,376✔
1011
        my $self = shift;
107,376✔
1012
        my ( $varname, $typevarname, %extras ) = @_;
107,376✔
1013
        
1014
        $extras{exception_class} ||= $self->exception_class;
107,376✔
1015
        
1016
        my $inline_check;
107,376✔
1017
        if ( $self->can_be_inlined ) {
107,376✔
1018
                $inline_check = sprintf( '(%s)', $self->inline_check( $varname ) );
106,152✔
1019
        }
1020
        elsif ( $typevarname ) {
1021
                $inline_check = sprintf( '%s->check(%s)', $typevarname, $varname );
1,216✔
1022
        }
1023
        else {
1024
                _croak 'Cannot inline type constraint check for "%s"', $self;
8✔
1025
        }
1026
        
1027
        my $do_wrapper = !delete $extras{no_wrapper};
107,368✔
1028
        
1029
        my $inline_throw;
107,368✔
1030
        if ( $typevarname ) {
107,368✔
1031
                $inline_throw = sprintf(
1032
                        'Type::Tiny::_failed_check(%s, %s, %s, %s)',
1033
                        $typevarname,
1034
                        B::perlstring( "$self" ),
1035
                        $varname,
1036
                        join(
1037
                                ',', map +( B::perlstring( $_ ) => B::perlstring( $extras{$_} ) ),
1,232✔
1038
                                sort keys %extras
1039
                        ),
1040
                );
1041
        } #/ if ( $typevarname )
1042
        else {
1043
                $inline_throw = sprintf(
1044
                        'Type::Tiny::_failed_check(%s, %s, %s, %s)',
1045
                        $self->{uniq},
1046
                        B::perlstring( "$self" ),
1047
                        $varname,
1048
                        join(
1049
                                ',', map +( B::perlstring( $_ ) => B::perlstring( $extras{$_} ) ),
106,136✔
1050
                                sort keys %extras
1051
                        ),
1052
                );
1053
        } #/ else [ if ( $typevarname ) ]
1054
        
1055
        $do_wrapper
107,368✔
1056
                ? qq[do { no warnings "void"; $SafePackage $inline_check or $inline_throw; $varname };]
1057
                : qq[     no warnings "void"; $SafePackage $inline_check or $inline_throw; $varname   ];
1058
} #/ sub inline_assert
1059

1060
sub _failed_check {
1061
        my ( $self, $name, $value, %attrs ) = @_;
3,524✔
1062
        $self = $ALL_TYPES{$self} if defined $self && !ref $self;
3,524✔
1063
        
1064
        my $exception_class = delete( $attrs{exception_class} )
1065
                || ( ref $self ? $self->exception_class : 'Error::TypeTiny::Assertion' );
3,524✔
1066
        my $callback = delete( $attrs{on_die} );
3,524✔
1067

1068
        if ( $self ) {
3,524✔
1069
                return $exception_class->throw_cb(
3,516✔
1070
                        $callback,
1071
                        message => $self->get_message( $value ),
1072
                        type    => $self,
1073
                        value   => $value,
1074
                        %attrs,
1075
                );
1076
        }
1077
        else {
1078
                return $exception_class->throw_cb(
8✔
1079
                        $callback,
1080
                        message => sprintf( '%s did not pass type constraint "%s"', _dd( $value ), $name ),
1081
                        value => $value,
1082
                        %attrs,
1083
                );
1084
        }
1085
} #/ sub _failed_check
1086

1087
sub coerce {
1088
        my $self = shift;
5,042✔
1089
        $self->_assert_coercion->coerce( @_ );
5,042✔
1090
}
1091

1092
sub assert_coerce {
1093
        my $self = shift;
512✔
1094
        $self->_assert_coercion->assert_coerce( @_ );
512✔
1095
}
1096

1097
sub is_parameterizable {
1098
        shift->has_constraint_generator;
132,240✔
1099
}
1100

1101
sub is_parameterized {
1102
        shift->has_parameters;
4,280✔
1103
}
1104

1105
{
1106
        my %seen;
1107
        
1108
        sub ____make_key {
1109
                #<<<
1110
                join ',', map {
1111
                        Types::TypeTiny::is_TypeTiny( $_ )  ? sprintf( '$Type::Tiny::ALL_TYPES{%s}', defined( $_->{uniq} ) ? $_->{uniq} : '____CANNOT_KEY____' ) :
12,212✔
1112
                        ref() eq 'ARRAY'                    ? do { $seen{$_}++ ? '____CANNOT_KEY____' : sprintf( '[%s]', ____make_key( @$_ ) ) } :
56✔
1113
                        ref() eq 'HASH'                     ? do { $seen{$_}++ ? '____CANNOT_KEY____' : sprintf( '{%s}', ____make_key( do { my %h = %$_; map +( $_, $h{$_} ), sort keys %h; } ) ) } :
144✔
1114
                        ref() eq 'SCALAR' || ref() eq 'REF' ? do { $seen{$_}++ ? '____CANNOT_KEY____' : sprintf( '\\(%s)', ____make_key( $$_ ) ) } :
24✔
1115
                        !defined()                          ? 'undef' :
1116
                        !ref()                              ? do { require B; B::perlstring( $_ ) } :
29,952✔
1117
                        '____CANNOT_KEY____';
1118
                } @_;
1119
                #>>>
1120
        } #/ sub ____make_key
1121
        my %param_cache;
1122
        
1123
        sub parameterize {
1124
                my $self = shift;
11,972✔
1125
                
1126
                $self->is_parameterizable
11,972✔
1127
                        or @_
1128
                        ? _croak( "Type '%s' does not accept parameters", "$self" )
1129
                        : return ( $self );
1130
                        
1131
                @_ = map Types::TypeTiny::to_TypeTiny( $_ ), @_;
11,972✔
1132
                
1133
                # Generate a key for caching parameterized type constraints,
1134
                # but only if all the parameters are strings or type constraints.
1135
                %seen = ();
11,972✔
1136
                my $key = $self->____make_key( @_ );
11,972✔
1137
                undef( $key )             if $key =~ /____CANNOT_KEY____/;
11,972✔
1138
                return $param_cache{$key} if defined $key && defined $param_cache{$key};
11,972✔
1139
                
1140
                local $Type::Tiny::parameterize_type = $self;
8,952✔
1141
                local $_                             = $_[0];
8,952✔
1142
                my $P;
8,952✔
1143
                
1144
                my ( $constraint, $compiled ) = $self->constraint_generator->( @_ );
8,952✔
1145
                
1146
                if ( Types::TypeTiny::is_TypeTiny( $constraint ) ) {
8,624✔
1147
                        $P = $constraint;
1,640✔
1148
                }
1149
                else {
1150
                        my %options = (
6,984✔
1151
                                constraint   => $constraint,
1152
                                display_name => $self->name_generator->( $self, @_ ),
1153
                                parameters   => [@_],
1154
                        );
1155
                        $options{compiled_type_constraint} = $compiled
6,984✔
1156
                                if $compiled;
1157
                        $options{inlined} = $self->inline_generator->( @_ )
6,984✔
1158
                                if $self->has_inline_generator;
1159
                        $options{type_default} = $self->{type_default_generator}->( @_ )
1160
                                if exists $self->{type_default_generator}; # undocumented
6,984✔
1161
                        exists $options{$_} && !defined $options{$_} && delete $options{$_}
1162
                                for keys %options;
6,984✔
1163
                        
1164
                        $P = $self->create_child_type( %options );
6,984✔
1165
                        
1166
                        if ( $self->has_coercion_generator ) {
6,984✔
1167
                                my @args = @_;
3,704✔
1168
                                $P->{_build_coercion} = sub {
1169
                                        my $coercion = shift;
1,884✔
1170
                                        my $built    = $self->coercion_generator->( $self, $P, @args );
1,884✔
1171
                                        $coercion->add_type_coercions( @{ $built->type_coercion_map } ) if $built;
1,884✔
1172
                                        $coercion->freeze;
1,884✔
1173
                                };
3,704✔
1174
                        }
1175
                } #/ else [ if ( Types::TypeTiny::is_TypeTiny...)]
1176
                
1177
                if ( defined $key ) {
8,624✔
1178
                        $param_cache{$key} = $P;
8,336✔
1179
                        Scalar::Util::weaken( $param_cache{$key} );
8,336✔
1180
                }
1181
                
1182
                $P->coercion->freeze unless $self->has_coercion_generator;
8,624✔
1183
                
1184
                return $P;
8,624✔
1185
        } #/ sub parameterize
1186
}
1187

1188
sub check_parameter_count_for_parameterized_type {
1189
        my ( $library, $type_name, $args, $max_args, $min_args ) = @_;
6,592✔
1190
        $args = @$args if ref $args;
6,592✔
1191
        
1192
        if ( ( defined $max_args and $args > $max_args ) or ( defined $min_args and $args < $min_args ) ) {
6,592✔
1193
                require Error::TypeTiny::WrongNumberOfParameters;
×
1194
                Error::TypeTiny::WrongNumberOfParameters->throw(
×
1195
                        target => "$library\::$type_name\[]",
1196
                        ( defined $min_args ) ? ( minimum => $min_args ) : (),
1197
                        ( defined $max_args ) ? ( maximum => $max_args ) : (),
1198
                        got => $args,
1199
                );
1200
        }
1201
        
6,592✔
1202
        return;
1203
}
1204

1205
sub child_type_class {
12,272✔
1206
        __PACKAGE__;
1207
}
1208

1209
sub create_child_type {
12,272✔
1210
        my $self = shift;
12,272✔
1211
        my %moreopts;
12,272✔
1212
        $moreopts{is_object} = 1 if $self->{is_object};
12,272✔
1213
        return $self->child_type_class->new( parent => $self, %moreopts, @_ );
1214
}
1215

1216
sub complementary_type {
720✔
1217
        my $self = shift;
720✔
1218
        my $r    = ( $self->{complementary_type} ||= $self->_build_complementary_type );
1219
        Scalar::Util::weaken( $self->{complementary_type} )
720✔
1220
                unless Scalar::Util::isweak( $self->{complementary_type} );
720✔
1221
        return $r;
1222
}
1223

1224
sub _build_complementary_type {
624✔
1225
        my $self = shift;
1226
        my %opts = (
488✔
1227
                constraint   => sub { not $self->check( $_ ) },
624✔
1228
                display_name => sprintf( "~%s", $self ),
1229
        );
624✔
1230
        $opts{display_name} =~ s/^\~{2}//;
1,820✔
1231
        $opts{inlined} = sub { shift; "not(" . $self->inline_check( @_ ) . ")" }
624✔
1232
                if $self->can_be_inlined;
1233
        $opts{display_name} = $opts{name} = $self->{complement_name}
624✔
1234
                if $self->{complement_name};
624✔
1235
        return "Type::Tiny"->new( %opts );
1236
} #/ sub _build_complementary_type
1237

1238
sub _instantiate_moose_type {
608✔
1239
        my $self = shift;
608✔
1240
        my %opts = @_;
608✔
1241
        require Moose::Meta::TypeConstraint;
608✔
1242
        return "Moose::Meta::TypeConstraint"->new( %opts );
1243
}
1244

1245
sub _build_moose_type {
1,388✔
1246
        my $self = shift;
1247
        
1,388✔
1248
        my $r;
1,388✔
1249
        if ( $self->{_is_core} ) {
740✔
1250
                require Moose::Util::TypeConstraints;
740✔
1251
                $r = Moose::Util::TypeConstraints::find_type_constraint( $self->name );
740✔
1252
                $r->{"Types::TypeTiny::to_TypeTiny"} = $self;
740✔
1253
                Scalar::Util::weaken( $r->{"Types::TypeTiny::to_TypeTiny"} );
1254
        }
1255
        else {
1256
                # Type::Tiny is more flexible than Moose, allowing
1257
                # inlined to return a list. So we need to wrap the
1258
                # inlined coderef to make sure Moose gets a single
1259
                # string.
1260
                #
1261
                my $wrapped_inlined = sub {
380✔
1262
                        shift;
380✔
1263
                        $self->inline_check( @_ );
648✔
1264
                };
1265
                
648✔
1266
                my %opts;
648✔
1267
                $opts{name}   = $self->qualified_name if $self->has_library && !$self->is_anon;
648✔
1268
                $opts{parent} = $self->parent->moose_type if $self->has_parent;
648✔
1269
                $opts{constraint} = $self->constraint unless $self->_is_null_constraint;
648✔
1270
                $opts{message}    = $self->message   if $self->has_message;
648✔
1271
                $opts{inlined}    = $wrapped_inlined if $self->has_inlined;
1272
                
648✔
1273
                $r                                   = $self->_instantiate_moose_type( %opts );
648✔
1274
                $r->{"Types::TypeTiny::to_TypeTiny"} = $self;
648✔
1275
                $self->{moose_type}                  = $r;                                     # prevent recursion
648✔
1276
                $r->coercion( $self->coercion->moose_coercion ) if $self->has_coercion;
1277
        } #/ else [ if ( $self->{_is_core})]
1278
        
1,388✔
1279
        return $r;
1280
} #/ sub _build_moose_type
1281

1282
sub _build_mouse_type {
24✔
1283
        my $self = shift;
1284
        
24✔
1285
        my %options;
24✔
1286
        $options{name} = $self->qualified_name if $self->has_library && !$self->is_anon;
24✔
1287
        $options{parent}     = $self->parent->mouse_type if $self->has_parent;
24✔
1288
        $options{constraint} = $self->constraint unless $self->_is_null_constraint;
24✔
1289
        $options{message}    = $self->message if $self->has_message;
1290
        
24✔
1291
        require Mouse::Meta::TypeConstraint;
24✔
1292
        my $r = "Mouse::Meta::TypeConstraint"->new( %options );
1293
        
24✔
1294
        $self->{mouse_type} = $r;    # prevent recursion
24✔
1295
        $r->_add_type_coercions(
1296
                $self->coercion->freeze->_codelike_type_coercion_map( 'mouse_type' ) )
1297
                if $self->has_coercion;
1298
                
24✔
1299
        return $r;
1300
} #/ sub _build_mouse_type
1301

1302
sub exportables {
124,600✔
1303
        my ( $self, $base_name, $tag ) = ( shift, @_ ); # $tag is undocumented
124,600✔
1304
        if ( not $self->is_anon ) {
124,592✔
1305
                $base_name ||= $self->name;
1306
        }
124,600✔
1307
        $tag ||= 0;
1308

124,600✔
1309
        my @exportables;
124,600✔
1310
        return \@exportables if ! $base_name;
1311

124,600✔
1312
        require Eval::TypeTiny;
1313

124,600✔
1314
        push @exportables, {
1315
                name => $base_name,
1316
                code => Eval::TypeTiny::type_to_coderef( $self ),
1317
                tags => [ 'types' ],
1318
        } if $tag eq 'types' || !$tag;
1319

124,600✔
1320
        push @exportables, {
1321
                name => sprintf( 'is_%s', $base_name ),
1322
                code => $self->compiled_check,
1323
                tags => [ 'is' ],
1324
        } if $tag eq 'is' || !$tag;
1325

124,600✔
1326
        push @exportables, {
1327
                name => sprintf( 'assert_%s', $base_name ),
1328
                code => $self->_overload_coderef,
1329
                tags => [ 'assert' ],
1330
        } if $tag eq 'assert' || !$tag;
1331

1332
        push @exportables, {
1333
                name => sprintf( 'to_%s', $base_name ),
1334
                code => $self->has_coercion && $self->coercion->frozen
1335
                        ? $self->coercion->compiled_coercion
72✔
1336
                        : sub ($) { $self->coerce( $_[0] ) },
124,600✔
1337
                tags => [ 'to' ],
1338
        } if $tag eq 'to' || !$tag;
1339

124,600✔
1340
        return \@exportables;
1341
}
1342

1343
sub exportables_by_tag {
5,560✔
1344
        my ( $self, $tag, $base_name ) = ( shift, @_ );
1345
        my @matched = grep {
5,560✔
1346
                my $e = $_;
5,560✔
1347
                grep $_ eq $tag, @{ $e->{tags} || [] };
5,560✔
1348
        } @{ $self->exportables( $base_name, $tag ) };
5,560✔
1349
        return @matched if wantarray;
8✔
1350
        _croak( 'Expected to find one exportable tagged "%s", found %d', $tag, scalar @matched )
1351
                unless @matched == 1;
8✔
1352
        return $matched[0];
1353
}
1354

1355
sub _process_coercion_list {
812✔
1356
        my $self = shift;
1357
        
812✔
1358
        my @pairs;
812✔
1359
        while ( @_ ) {
876✔
1360
                my $next = shift;
876✔
1361
                if ( blessed( $next )
1362
                        and $next->isa( 'Type::Coercion' )
1363
                        and $next->is_parameterized )
1364
                {
64✔
1365
                        push @pairs => ( @{ $next->_reparameterize( $self )->type_coercion_map } );
1366
                }
1367
                elsif ( blessed( $next ) and $next->can( 'type_coercion_map' ) ) {
1368
                        push @pairs => (
72✔
1369
                                @{ $next->type_coercion_map },
1370
                        );
1371
                }
1372
                elsif ( ref( $next ) eq q(ARRAY) ) {
24✔
1373
                        unshift @_, @$next;
1374
                }
1375
                else {
716✔
1376
                        push @pairs => (
1377
                                Types::TypeTiny::to_TypeTiny( $next ),
1378
                                shift,
1379
                        );
1380
                }
1381
        } #/ while ( @_ )
1382
        
812✔
1383
        return @pairs;
1384
} #/ sub _process_coercion_list
1385

1386
sub plus_coercions {
788✔
1387
        my $self = shift;
788✔
1388
        my $new  = $self->_clone;
1389
        $new->coercion->add_type_coercions(
1390
                $self->_process_coercion_list( @_ ),
788✔
1391
                @{ $self->coercion->type_coercion_map },
1392
        );
788✔
1393
        $new->coercion->freeze;
788✔
1394
        return $new;
1395
} #/ sub plus_coercions
1396

1397
sub plus_fallback_coercions {
16✔
1398
        my $self = shift;
1399
        
16✔
1400
        my $new = $self->_clone;
1401
        $new->coercion->add_type_coercions(
16✔
1402
                @{ $self->coercion->type_coercion_map },
1403
                $self->_process_coercion_list( @_ ),
1404
        );
16✔
1405
        $new->coercion->freeze;
16✔
1406
        return $new;
1407
} #/ sub plus_fallback_coercions
1408

1409
sub minus_coercions {
8✔
1410
        my $self = shift;
1411
        
8✔
1412
        my $new = $self->_clone;
8✔
1413
        my @not = grep Types::TypeTiny::is_TypeTiny( $_ ),
1414
                $self->_process_coercion_list( $new, @_ );
1415
                
8✔
1416
        my @keep;
8✔
1417
        my $c = $self->coercion->type_coercion_map;
8✔
1418
        for ( my $i = 0 ; $i <= $#$c ; $i += 2 ) {
32✔
1419
                my $keep_this = 1;
32✔
1420
                NOT: for my $n ( @not ) {
88✔
1421
                        if ( $c->[$i] == $n ) {
16✔
1422
                                $keep_this = 0;
16✔
1423
                                last NOT;
1424
                        }
1425
                }
1426
                
32✔
1427
                push @keep, $c->[$i], $c->[ $i + 1 ] if $keep_this;
1428
        } #/ for ( my $i = 0 ; $i <=...)
1429
        
8✔
1430
        $new->coercion->add_type_coercions( @keep );
8✔
1431
        $new->coercion->freeze;
8✔
1432
        return $new;
1433
} #/ sub minus_coercions
1434

1435
sub no_coercions {
48✔
1436
        my $new = shift->_clone;
48✔
1437
        $new->coercion->freeze;
48✔
1438
        $new;
1439
}
1440

1441
sub coercibles {
128✔
1442
        my $self = shift;
128✔
1443
        $self->has_coercion ? $self->coercion->_source_type_union : $self;
1444
}
1445

1446
sub isa {
1,434,364✔
1447
        my $self = shift;
1448
        
1,434,364✔
1449
        if ( $INC{"Moose/Meta/TypeConstraint.pm"}
1450
                and ref( $self )
1451
                and $_[0] =~ /^(?:Class::MOP|MooseX?::Meta)::(.+)$/ )
1452
        {
744✔
1453
                my $meta = $1;
1454
                
744✔
1455
                return !!1                       if $meta eq 'TypeConstraint';
264✔
1456
                return $self->is_parameterized   if $meta eq 'TypeConstraint::Parameterized';
32✔
1457
                return $self->is_parameterizable if $meta eq 'TypeConstraint::Parameterizable';
24✔
1458
                return $self->isa( 'Type::Tiny::Union' ) if $meta eq 'TypeConstraint::Union';
1459
                
8✔
1460
                my $inflate = $self->moose_type;
8✔
1461
                return $inflate->isa( @_ );
1462
        } #/ if ( $INC{"Moose/Meta/TypeConstraint.pm"} ...)
1463
        
1,433,620✔
1464
        if ( $INC{"Mouse.pm"}
1465
                and ref( $self )
1466
                and $_[0] eq 'Mouse::Meta::TypeConstraint' )
1467
        {
8✔
1468
                return !!1;
1469
        }
1470
        
1,433,612✔
1471
        $self->SUPER::isa( @_ );
1472
} #/ sub isa
1473

1474
sub _build_my_methods {
1,240✔
1475
        return {};
1476
}
1477

1478
sub _lookup_my_method {
10,608✔
1479
        my $self = shift;
10,608✔
1480
        my ( $name ) = @_;
1481
        
10,608✔
1482
        if ( $self->my_methods->{$name} ) {
5,104✔
1483
                return $self->my_methods->{$name};
1484
        }
1485
        
5,504✔
1486
        if ( $self->has_parent ) {
5,488✔
1487
                return $self->parent->_lookup_my_method( @_ );
1488
        }
1489
        
16✔
1490
        return;
1491
} #/ sub _lookup_my_method
1492

1493
my %object_methods = (
1494
        with_attribute_values => 1, stringifies_to => 1,
1495
        numifies_to           => 1
1496
);
1497

1498
sub can {
438,324✔
1499
        my $self = shift;
1500
        
438,324✔
1501
        return !!0
1502
                if $_[0] eq 'type_parameter'
1503
                && blessed( $_[0] )
1504
                && $_[0]->has_parameters;
1505
                
438,324✔
1506
        my $can = $self->SUPER::can( @_ );
438,324✔
1507
        return $can if $can;
1508
        
181,304✔
1509
        if ( ref( $self ) ) {
181,296✔
1510
                if ( $INC{"Moose/Meta/TypeConstraint.pm"} ) {
2,552✔
1511
                        my $method = $self->moose_type->can( @_ );
8✔
1512
                        return sub { shift->moose_type->$method( @_ ) }
2,552✔
1513
                                if $method;
1514
                }
181,216✔
1515
                if ( $_[0] =~ /\Amy_(.+)\z/ ) {
32✔
1516
                        my $method = $self->_lookup_my_method( $1 );
32✔
1517
                        return $method if $method;
1518
                }
181,200✔
1519
                if ( $self->{is_object} && $object_methods{ $_[0] } ) {
8✔
1520
                        require Type::Tiny::ConstrainedObject;
8✔
1521
                        return Type::Tiny::ConstrainedObject->can( $_[0] );
1522
                }
181,192✔
1523
                for my $util ( qw/ grep map sort rsort first any all assert_any assert_all / ) {
1,629,576✔
1524
                        if ( $_[0] eq $util ) {
288✔
1525
                                $self->{'_util'}{$util} ||= eval { $self->_build_util( $util ) };
288✔
1526
                                return unless $self->{'_util'}{$util};
272✔
1527
                                return sub { my $s = shift; $s->{'_util'}{$util}( @_ ) };
1528
                        }
1529
                }
1530
        } #/ if ( ref( $self ) )
1531
        
180,912✔
1532
        return;
1533
} #/ sub can
1534

1535
sub AUTOLOAD {
5,684✔
1536
        my $self = shift;
5,684✔
1537
        my ( $m ) = ( our $AUTOLOAD =~ /::(\w+)$/ );
5,684✔
1538
        return if $m eq 'DESTROY';
1539
        
5,684✔
1540
        if ( ref( $self ) ) {
5,684✔
1541
                if ( $INC{"Moose/Meta/TypeConstraint.pm"} ) {
24✔
1542
                        my $method = $self->moose_type->can( $m );
24✔
1543
                        return $self->moose_type->$method( @_ ) if $method;
1544
                }
5,668✔
1545
                if ( $m =~ /\Amy_(.+)\z/ ) {
5,088✔
1546
                        my $method = $self->_lookup_my_method( $1 );
5,088✔
1547
                        return &$method( $self, @_ ) if $method;
1548
                }
580✔
1549
                if ( $self->{is_object} && $object_methods{$m} ) {
24✔
1550
                        require Type::Tiny::ConstrainedObject;
24✔
1551
                        unshift @_, $self;
2,688✔
1552
                        no strict 'refs';
24✔
1553
                        goto \&{"Type::Tiny::ConstrainedObject::$m"};
1554
                }
556✔
1555
                for my $util ( qw/ grep map sort rsort first any all assert_any assert_all / ) {
3,012✔
1556
                        if ( $m eq $util ) {
540✔
1557
                                return ( $self->{'_util'}{$util} ||= $self->_build_util( $util ) )->( @_ );
1558
                        }
1559
                }
1560
        } #/ if ( ref( $self ) )
1561
        
16✔
1562
        _croak q[Can't locate object method "%s" via package "%s"], $m,
1563
                ref( $self ) || $self;
1564
} #/ sub AUTOLOAD
1565

1566
sub DOES {
216✔
1567
        my $self = shift;
1568
        
216✔
1569
        return !!1
1570
                if ref( $self )
1571
                && $_[0] =~ m{^ Type::API::Constraint (?: ::Coercible | ::Inlinable )? $}x;
216✔
1572
        return !!1 if !ref( $self ) && $_[0] eq 'Type::API::Constraint::Constructor';
1573
        
216✔
1574
        "UNIVERSAL"->can( "DOES" ) ? $self->SUPER::DOES( @_ ) : $self->isa( @_ );
1575
} #/ sub DOES
1576

1577
sub _has_xsub {
8✔
1578
        require B;
8✔
1579
        !!B::svref_2object( shift->compiled_check )->XSUB;
1580
}
1581

1582
sub _build_util {
652✔
1583
        my ( $self, $func ) = @_;
652✔
1584
        Scalar::Util::weaken( my $type = $self );
1585
        
652✔
1586
        if ( $func eq 'grep'
1587
                || $func eq 'first'
1588
                || $func eq 'any'
1589
                || $func eq 'all'
1590
                || $func eq 'assert_any'
1591
                || $func eq 'assert_all' )
1592
        {
340✔
1593
                my ( $inline, $compiled );
1594
                
340✔
1595
                if ( $self->can_be_inlined ) {
100✔
1596
                        $inline = $self->inline_check( '$_' );
1597
                }
1598
                else {
240✔
1599
                        $compiled = $self->compiled_check;
240✔
1600
                        $inline   = '$compiled->($_)';
1601
                }
1602
                
340✔
1603
                if ( $func eq 'grep' ) {
40✔
1604
                        return eval "sub { grep { $inline } \@_ }";
1605
                }
1606
                elsif ( $func eq 'first' ) {
40✔
1607
                        return eval "sub { for (\@_) { return \$_ if ($inline) }; undef; }";
1608
                }
1609
                elsif ( $func eq 'any' ) {
64✔
1610
                        return eval "sub { for (\@_) { return !!1 if ($inline) }; !!0; }";
1611
                }
1612
                elsif ( $func eq 'assert_any' ) {
64✔
1613
                        my $qname = B::perlstring( $self->name );
1614
                        return
1615
                                eval
64✔
1616
                                "sub { for (\@_) { return \@_ if ($inline) }; Type::Tiny::_failed_check(\$type, $qname, \@_ ? \$_[-1] : undef); }";
1617
                }
1618
                elsif ( $func eq 'all' ) {
68✔
1619
                        return eval "sub { for (\@_) { return !!0 unless ($inline) }; !!1; }";
1620
                }
1621
                elsif ( $func eq 'assert_all' ) {
64✔
1622
                        my $qname = B::perlstring( $self->name );
1623
                        return
1624
                                eval
64✔
1625
                                "sub { my \$idx = 0; for (\@_) { Type::Tiny::_failed_check(\$type, $qname, \$_, varname => sprintf('\$_[%d]', \$idx)) unless ($inline); ++\$idx }; \@_; }";
1626
                }
1627
        } #/ if ( $func eq 'grep' ||...)
1628
        
312✔
1629
        if ( $func eq 'map' ) {
64✔
1630
                my ( $inline, $compiled );
64✔
1631
                my $c = $self->_assert_coercion;
1632
                
32✔
1633
                if ( $c->can_be_inlined ) {
8✔
1634
                        $inline = $c->inline_coercion( '$_' );
1635
                }
1636
                else {
24✔
1637
                        $compiled = $c->compiled_coercion;
24✔
1638
                        $inline   = '$compiled->($_)';
1639
                }
1640
                
32✔
1641
                return eval "sub { map { $inline } \@_ }";
1642
        } #/ if ( $func eq 'map' )
1643
        
248✔
1644
        if ( $func eq 'sort' || $func eq 'rsort' ) {
232✔
1645
                my ( $inline, $compiled );
1646
                
232✔
1647
                my $ptype = $self->find_parent( sub { $_->has_sorter } );
232✔
1648
                _croak "No sorter for this type constraint" unless $ptype;
1649
                
216✔
1650
                my $sorter = $ptype->sorter;
1651
                
1652
                # Schwarzian transformation
216✔
1653
                if ( ref( $sorter ) eq 'ARRAY' ) {
48✔
1654
                        my $sort_key;
48✔
1655
                        ( $sorter, $sort_key ) = @$sorter;
1656
                        
48✔
1657
                        if ( $func eq 'sort' ) {
1658
                                return
1659
                                        eval
32✔
1660
                                        "our (\$a, \$b); sub { map \$_->[0], sort { \$sorter->(\$a->[1],\$b->[1]) } map [\$_,\$sort_key->(\$_)], \@_ }";
1661
                        }
1662
                        elsif ( $func eq 'rsort' ) {
1663
                                return
1664
                                        eval
16✔
1665
                                        "our (\$a, \$b); sub { map \$_->[0], sort { \$sorter->(\$b->[1],\$a->[1]) } map [\$_,\$sort_key->(\$_)], \@_ }";
1666
                        }
1667
                } #/ if ( ref( $sorter ) eq...)
1668
                
1669
                # Simple sort
1670
                else {
168✔
1671
                        if ( $func eq 'sort' ) {
96✔
1672
                                return eval "our (\$a, \$b); sub { sort { \$sorter->(\$a,\$b) } \@_ }";
1673
                        }
1674
                        elsif ( $func eq 'rsort' ) {
72✔
1675
                                return eval "our (\$a, \$b); sub { sort { \$sorter->(\$b,\$a) } \@_ }";
1676
                        }
1677
                }
1678
        } #/ if ( $func eq 'sort' ||...)
1679
        
16✔
1680
        die "Unknown function: $func";
1681
} #/ sub _build_util
1682

2,520✔
1683
sub of    { shift->parameterize( @_ ) }
1,112✔
1684
sub where { shift->create_child_type( constraint => @_ ) }
1685

1686
# fill out Moose-compatible API
1,416✔
1687
sub inline_environment        { +{} }
732✔
1688
sub _inline_check             { shift->inline_check( @_ ) }
500✔
1689
sub _compiled_type_constraint { shift->compiled_check( @_ ) }
8✔
1690
sub meta { _croak( "Not really a Moose::Meta::TypeConstraint. Sorry!" ) }
16✔
1691
sub compile_type_constraint           { shift->compiled_check }
16✔
1692
sub _actually_compile_type_constraint { shift->_build_compiled_check }
8✔
1693
sub hand_optimized_type_constraint { shift->{hand_optimized_type_constraint} }
1694

1695
sub has_hand_optimized_type_constraint {
8✔
1696
        exists( shift->{hand_optimized_type_constraint} );
1697
}
2,496✔
1698
sub type_parameter { ( shift->parameters || [] )->[0] }
1699

1700
sub parameterized_from {
40✔
1701
        $_[0]->is_parameterized ? shift->parent : _croak( "Not a parameterized type" );
1702
}
16✔
1703
sub has_parameterized_from { $_[0]->is_parameterized }
1704

1705
# some stuff for Mouse-compatible API
16✔
1706
sub __is_parameterized      { shift->is_parameterized( @_ ) }
8✔
1707
sub _add_type_coercions     { shift->coercion->add_type_coercions( @_ ) }
8✔
1708
sub _as_string              { shift->qualified_name( @_ ) }
8✔
1709
sub _compiled_type_coercion { shift->coercion->compiled_coercion( @_ ) }
16✔
1710
sub _identity               { Scalar::Util::refaddr( shift ) }
1711

1712
sub _unite {
8✔
1713
        require Type::Tiny::Union;
8✔
1714
        "Type::Tiny::Union"->new( type_constraints => \@_ );
1715
}
1716

1717
# Hooks for Type::Tie
1718
sub TIESCALAR {
24✔
1719
        require Type::Tie;
24✔
1720
        unshift @_, 'Type::Tie::SCALAR';
24✔
1721
        goto \&Type::Tie::SCALAR::TIESCALAR;
1722
}
1723

1724
sub TIEARRAY {
16✔
1725
        require Type::Tie;
16✔
1726
        unshift @_, 'Type::Tie::ARRAY';
16✔
1727
        goto \&Type::Tie::ARRAY::TIEARRAY;
1728
}
1729

1730
sub TIEHASH {
16✔
1731
        require Type::Tie;
16✔
1732
        unshift @_, 'Type::Tie::HASH';
16✔
1733
        goto \&Type::Tie::HASH::TIEHASH;
1734
}
1735

1736
1;
1737

1738
__END__
1739

1740
=pod
1741

1742
=encoding utf-8
1743

1744
=for stopwords Moo(se)-compatible MooseX MouseX MooX Moose-compat invocant
1745

1746
=head1 NAME
1747

1748
Type::Tiny - tiny, yet Moo(se)-compatible type constraint
1749

1750
=head1 SYNOPSIS
1751

1752
  use v5.36;
1753
  
1754
  package Horse {
1755
    use Moo;
1756
    use Types::Standard qw( Str Int Enum ArrayRef Object );
1757
    use Type::Params qw( signature_for );
1758
    use namespace::autoclean;
1759
    
1760
    has name => (
1761
      is       => 'ro',
1762
      isa      => Str,
1763
      required => 1,
1764
    );
1765
    
1766
    has gender => (
1767
      is       => 'ro',
1768
      isa      => Enum[qw( f m )],
1769
    );
1770
    
1771
    has age => (
1772
      is       => 'rw',
1773
      isa      => Int->where( '$_ >= 0' ),
1774
    );
1775
    
1776
    has children => (
1777
      is       => 'ro',
1778
      isa      => ArrayRef[Object],
1779
      default  => sub { return [] },
1780
    );
1781
    
1782
    # method signature
1783
    signature_for add_child => (
1784
      method     => Object,
1785
      positional => [ Object ],
1786
    );
1787
    
1788
    sub add_child ( $self, $child ) {
1789
      push $self->children->@*, $child;
1790
      return $self;
1791
    }
1792
  }
1793
  
1794
  package main;
1795
  
1796
  my $boldruler = Horse->new(
1797
    name    => "Bold Ruler",
1798
    gender  => 'm',
1799
    age     => 16,
1800
  );
1801
  
1802
  my $secretariat = Horse->new(
1803
    name    => "Secretariat",
1804
    gender  => 'm',
1805
    age     => 0,
1806
  );
1807
  
1808
  $boldruler->add_child( $secretariat );
1809

1810
=head1 STATUS
1811

1812
This module is covered by the
1813
L<Type-Tiny stability policy|Type::Tiny::Manual::Policies/"STABILITY">.
1814

1815
=head1 DESCRIPTION
1816

1817
This documents the internals of the L<Type::Tiny> class. L<Type::Tiny::Manual>
1818
is a better starting place if you're new.
1819

1820
L<Type::Tiny> is a small class for creating Moose-like type constraint
1821
objects which are compatible with Moo, Moose and Mouse.
1822

1823
   use Scalar::Util qw(looks_like_number);
1824
   use Type::Tiny;
1825
   
1826
   my $NUM = "Type::Tiny"->new(
1827
      name       => "Number",
1828
      constraint => sub { looks_like_number($_) },
1829
      message    => sub { "$_ ain't a number" },
1830
   );
1831
   
1832
   package Ermintrude {
1833
      use Moo;
1834
      has favourite_number => (is => "ro", isa => $NUM);
1835
   }
1836
   
1837
   package Bullwinkle {
1838
      use Moose;
1839
      has favourite_number => (is => "ro", isa => $NUM);
1840
   }
1841
   
1842
   package Maisy {
1843
      use Mouse;
1844
      has favourite_number => (is => "ro", isa => $NUM);
1845
   }
1846

1847
Type::Tiny conforms to L<Type::API::Constraint>,
1848
L<Type::API::Constraint::Coercible>,
1849
L<Type::API::Constraint::Constructor>, and
1850
L<Type::API::Constraint::Inlinable>.
1851

1852
Maybe now we won't need to have separate MooseX, MouseX and MooX versions
1853
of everything? We can but hope...
1854

1855
=head2 Constructor
1856

1857
=over
1858

1859
=item C<< new(%attributes) >>
1860

1861
Moose-style constructor function.
1862

1863
=back
1864

1865
=head2 Attributes
1866

1867
Attributes are named values that may be passed to the constructor. For
1868
each attribute, there is a corresponding reader method. For example:
1869

1870
   my $type = Type::Tiny->new( name => "Foo" );
1871
   print $type->name, "\n";   # says "Foo"
1872

1873
=head3 Important attributes
1874

1875
These are the attributes you are likely to be most interested in
1876
providing when creating your own type constraints, and most interested
1877
in reading when dealing with type constraint objects.
1878

1879
=over
1880

1881
=item C<< constraint >>
1882

1883
Coderef to validate a value (C<< $_ >>) against the type constraint.
1884
The coderef will not be called unless the value is known to pass any
1885
parent type constraint (see C<parent> below).
1886

1887
Alternatively, a string of Perl code checking C<< $_ >> can be passed
1888
as a parameter to the constructor, and will be converted to a coderef.
1889

1890
Defaults to C<< sub { 1 } >> - i.e. a coderef that passes all values.
1891

1892
=item C<< parent >>
1893

1894
Optional attribute; parent type constraint. For example, an "Integer"
1895
type constraint might have a parent "Number".
1896

1897
If provided, must be a Type::Tiny object.
1898

1899
=item C<< inlined >>
1900

1901
A coderef which returns a string of Perl code suitable for inlining this
1902
type. Optional.
1903

1904
(The coderef will be called in list context and can actually return
1905
a list of strings which will be joined with C<< && >>. If the first item
1906
on the list is undef, it will be substituted with the type's parent's
1907
inline check.)
1908

1909
If C<constraint> (above) is a coderef generated via L<Sub::Quote>, then
1910
Type::Tiny I<may> be able to automatically generate C<inlined> for you.
1911
If C<constraint> (above) is a string, it will be able to.
1912

1913
=item C<< name >>
1914

1915
The name of the type constraint. These need to conform to certain naming
1916
rules (they must begin with an uppercase letter and continue using only
1917
letters, digits 0-9 and underscores).
1918

1919
Optional; if not supplied will be an anonymous type constraint.
1920

1921
=item C<< display_name >>
1922

1923
A name to display for the type constraint when stringified. These don't
1924
have to conform to any naming rules. Optional; a default name will be
1925
calculated from the C<name>.
1926

1927
=item C<< library >>
1928

1929
The package name of the type library this type is associated with.
1930
Optional. Informational only: setting this attribute does not install
1931
the type into the package.
1932

1933
=item C<< deprecated >>
1934

1935
Optional boolean indicating whether a type constraint is deprecated.
1936
L<Type::Library> will issue a warning if you attempt to import a deprecated
1937
type constraint, but otherwise the type will continue to function as normal.
1938
There will not be deprecation warnings every time you validate a value, for
1939
instance. If omitted, defaults to the parent's deprecation status (or false
1940
if there's no parent).
1941

1942
=item C<< message >>
1943

1944
Coderef that returns an error message when C<< $_ >> does not validate
1945
against the type constraint. Optional (there's a vaguely sensible default.)
1946

1947
=item C<< coercion >>
1948

1949
A L<Type::Coercion> object associated with this type.
1950

1951
Generally speaking this attribute should not be passed to the constructor;
1952
you should rely on the default lazily-built coercion object.
1953

1954
You may pass C<< coercion => 1 >> to the constructor to inherit coercions
1955
from the constraint's parent. (This requires the parent constraint to have
1956
a coercion.)
1957

1958
If an arrayref is passed to the constructor (C<< coercion => [ ... ] >>),
1959
then the coercion object will be lazily built and this array will be fed to
1960
its C<add_type_coercions> method. If a coderef is passed to the constructor
1961
(C<< coercion => sub { ... } >>), then the coercion object will be lazily built
1962
and this code will be used as a coercion from B<Any>.
1963

1964
=item C<< sorter >>
1965

1966
A coderef which can be passed two values conforming to this type constraint
1967
and returns -1, 0, or 1 to put them in order. Alternatively an arrayref
1968
containing a pair of coderefs — a sorter and a pre-processor for the
1969
Schwarzian transform. Optional.
1970

1971
The idea is to allow for:
1972

1973
  @sorted = Int->sort( 2, 1, 11 );    # => 1, 2, 11
1974
  @sorted = Str->sort( 2, 1, 11 );    # => 1, 11, 2 
1975

1976
=item C<< type_default >>
1977

1978
A coderef which returns a sensible default value for this type. For example,
1979
for a B<Counter> type, a sensible default might be "0":
1980

1981
  my $Size = Type::Tiny->new(
1982
    name          => 'Size',
1983
    parent        => Types::Standard::Enum[ qw( XS S M L XL ) ],
1984
    type_default  => sub { return 'M'; },
1985
  );
1986
  
1987
  package Tshirt {
1988
    use Moo;
1989
    has size => (
1990
      is       => 'ro',
1991
      isa      => $Size,
1992
      default  => $Size->type_default,
1993
    );
1994
  }
1995

1996
Child types will inherit a type default from their parent unless the child
1997
has a C<constraint>. If a type neither has nor inherits a type default, then
1998
calling C<type_default> will return undef.
1999

2000
As a special case, this:
2001

2002
  $type->type_default( @args )
2003

2004
Will return:
2005

2006
  sub {
2007
    local $_ = \@args;
2008
    $type->type_default->( @_ );
2009
  }
2010

2011
Many of the types defined in L<Types::Standard> and other bundled type
2012
libraries have type defaults, but discovering them is left as an exercise
2013
for the reader.
2014

2015
=item C<< my_methods >>
2016

2017
Experimental hashref of additional methods that can be called on the type
2018
constraint object.
2019

2020
=item C<< exception_class >>
2021

2022
The class used to throw an exception when a value fails its type check.
2023
Defaults to "Error::TypeTiny::Assertion", which is usually good. This class
2024
is expected to provide a C<throw_cb> method compatible with the method of
2025
that name in L<Error::TypeTiny>.
2026

2027
If a parent type constraint has a custom C<exception_class>, then this
2028
will be "inherited" by its children.
2029

2030
=back
2031

2032
=head3 Attributes related to parameterizable and parameterized types
2033

2034
The following additional attributes are used for parameterizable (e.g.
2035
C<ArrayRef>) and parameterized (e.g. C<< ArrayRef[Int] >>) type
2036
constraints. Unlike Moose, these aren't handled by separate subclasses.
2037

2038
=over
2039

2040
=item C<< constraint_generator >>
2041

2042
Coderef that is called when a type constraint is parameterized. When called,
2043
it is passed the list of parameters, though any parameter which looks like a
2044
foreign type constraint (Moose type constraints, Mouse type constraints, etc,
2045
I<< and coderefs(!!!) >>) is first coerced to a native Type::Tiny object.
2046

2047
Note that for compatibility with the Moose API, the base type is I<not>
2048
passed to the constraint generator, but can be found in the package variable
2049
C<< $Type::Tiny::parameterize_type >>. The first parameter is also available
2050
as C<< $_ >>.
2051

2052
Types I<can> be parameterized with an empty parameter list. For example,
2053
in L<Types::Standard>, C<Tuple> is just an alias for C<ArrayRef> but
2054
C<< Tuple[] >> will only allow zero-length arrayrefs to pass the constraint.
2055
If you wish C<< YourType >> and C<< YourType[] >> to mean the same thing,
2056
then do:
2057

2058
 return $Type::Tiny::parameterize_type unless @_;
2059

2060
The constraint generator should generate and return a new constraint coderef
2061
based on the parameters. Alternatively, the constraint generator can return a
2062
fully-formed Type::Tiny object, in which case the C<name_generator>,
2063
C<inline_generator>, and C<coercion_generator> attributes documented below
2064
are ignored.
2065

2066
Optional; providing a generator makes this type into a parameterizable
2067
type constraint. If there is no generator, attempting to parameterize the
2068
type constraint will throw an exception.
2069

2070
=item C<< name_generator >>
2071

2072
A coderef which generates a new display_name based on parameters. Called with
2073
the same parameters and package variables as the C<constraint_generator>.
2074
Expected to return a string.
2075

2076
Optional; the default is reasonable.
2077

2078
=item C<< inline_generator >>
2079

2080
A coderef which generates a new inlining coderef based on parameters. Called
2081
with the same parameters and package variables as the C<constraint_generator>.
2082
Expected to return a coderef.
2083

2084
Optional.
2085

2086
=item C<< coercion_generator >>
2087

2088
A coderef which generates a new L<Type::Coercion> object based on parameters.
2089
It is passed the parent type, child type, and list of parameters. It should
2090
have access to the same package variables as the C<constraint_generator>.
2091
Expected to return a blessed object.
2092

2093
Optional.
2094

2095
=item C<< deep_explanation >>
2096

2097
This API is not finalized. Coderef used by L<Error::TypeTiny::Assertion> to
2098
peek inside parameterized types and figure out why a value doesn't pass the
2099
constraint.
2100

2101
=item C<< parameters >>
2102

2103
In parameterized types, returns an arrayref of the parameters.
2104

2105
=back
2106

2107
=head3 Lazy generated attributes
2108

2109
The following attributes should not be usually passed to the constructor;
2110
unless you're doing something especially unusual, you should rely on the
2111
default lazily-built return values.
2112

2113
=over
2114

2115
=item C<< compiled_check >>
2116

2117
Coderef to validate a value (C<< $_[0] >>) against the type constraint.
2118
This coderef is expected to also handle all validation for the parent
2119
type constraints.
2120

2121
=item C<< definition_context >>
2122

2123
Hashref of information indicating where the type constraint was originally
2124
defined. Type::Tiny will generate this based on C<caller> if you do not
2125
supply it. The hashref will ordinarily contain keys C<"package">, C<"file">,
2126
and C<"line">.
2127

2128
For parameterized types and compound types (e.g. unions and intersections),
2129
this may not be especially meaningful information.
2130

2131
=item C<< complementary_type >>
2132

2133
A complementary type for this type. For example, the complementary type
2134
for an integer type would be all things that are not integers, including
2135
floating point numbers, but also alphabetic strings, arrayrefs, filehandles,
2136
etc.
2137

2138
=item C<< moose_type >>, C<< mouse_type >>
2139

2140
Objects equivalent to this type constraint, but as a
2141
L<Moose::Meta::TypeConstraint> or L<Mouse::Meta::TypeConstraint>.
2142

2143
It should rarely be necessary to obtain a L<Moose::Meta::TypeConstraint>
2144
object from L<Type::Tiny> because the L<Type::Tiny> object itself should
2145
be usable pretty much anywhere a L<Moose::Meta::TypeConstraint> is expected.
2146

2147
=back
2148

2149
=head2 Methods
2150

2151
=head3 Predicate methods
2152

2153
These methods return booleans indicating information about the type
2154
constraint. They are each tightly associated with a particular attribute.
2155
(See L</"Attributes">.)
2156

2157
=over
2158

2159
=item C<has_parent>, C<has_library>, C<has_inlined>, C<has_constraint_generator>, C<has_inline_generator>, C<has_coercion_generator>, C<has_parameters>, C<has_message>, C<has_deep_explanation>, C<has_sorter>
2160

2161
Simple Moose-style predicate methods indicating the presence or
2162
absence of an attribute.
2163

2164
=item C<has_coercion>
2165

2166
Predicate method with a little extra DWIM. Returns false if the coercion is
2167
a no-op.
2168

2169
=item C<< is_anon >>
2170

2171
Returns true iff the type constraint does not have a C<name>.
2172

2173
=item C<< is_parameterized >>, C<< is_parameterizable >>
2174

2175
Indicates whether a type has been parameterized (e.g. C<< ArrayRef[Int] >>)
2176
or could potentially be (e.g. C<< ArrayRef >>).
2177

2178
=item C<< has_parameterized_from >>
2179

2180
Useless alias for C<is_parameterized>.
2181

2182
=back
2183

2184
=head3 Validation and coercion
2185

2186
The following methods are used for coercing and validating values
2187
against a type constraint:
2188

2189
=over
2190

2191
=item C<< check($value) >>
2192

2193
Returns true iff the value passes the type constraint.
2194

2195
=item C<< validate($value) >>
2196

2197
Returns the error message for the value; returns an explicit undef if the
2198
value passes the type constraint.
2199

2200
=item C<< assert_valid($value) >>
2201

2202
Like C<< check($value) >> but dies if the value does not pass the type
2203
constraint.
2204

2205
Yes, that's three very similar methods. Blame L<Moose::Meta::TypeConstraint>
2206
whose API I'm attempting to emulate. :-)
2207

2208
=item C<< assert_return($value) >>
2209

2210
Like C<< assert_valid($value) >> but returns the value if it passes the type
2211
constraint.
2212

2213
This seems a more useful behaviour than C<< assert_valid($value) >>. I would
2214
have just changed C<< assert_valid($value) >> to do this, except that there
2215
are edge cases where it could break Moose compatibility.
2216

2217
=item C<< get_message($value) >>
2218

2219
Returns the error message for the value; even if the value passes the type
2220
constraint.
2221

2222
=item C<< validate_explain($value, $varname) >>
2223

2224
Like C<validate> but instead of a string error message, returns an arrayref
2225
of strings explaining the reasoning why the value does not meet the type
2226
constraint, examining parent types, etc.
2227

2228
The C<< $varname >> is an optional string like C<< '$foo' >> indicating the
2229
name of the variable being checked.
2230

2231
=item C<< coerce($value) >>
2232

2233
Attempt to coerce C<< $value >> to this type.
2234

2235
=item C<< assert_coerce($value) >>
2236

2237
Attempt to coerce C<< $value >> to this type. Throws an exception if this is
2238
not possible.
2239

2240
=back
2241

2242
=head3 Child type constraint creation and parameterization
2243

2244
These methods generate new type constraint objects that inherit from the
2245
constraint they are called upon:
2246

2247
=over
2248

2249
=item C<< create_child_type(%attributes) >>
2250

2251
Construct a new Type::Tiny object with this object as its parent.
2252

2253
=item C<< where($coderef) >>
2254

2255
Shortcut for creating an anonymous child type constraint. Use it like
2256
C<< HashRef->where(sub { exists($_->{name}) }) >>. That said, you can
2257
get a similar result using overloaded C<< & >>:
2258

2259
   HashRef & sub { exists($_->{name}) }
2260

2261
Like the C<< constraint >> attribute, this will accept a string of Perl
2262
code:
2263

2264
   HashRef->where('exists($_->{name})')
2265

2266
=item C<< child_type_class >>
2267

2268
The class that create_child_type will construct by default.
2269

2270
=item C<< parameterize(@parameters) >>
2271

2272
Creates a new parameterized type; throws an exception if called on a
2273
non-parameterizable type.
2274

2275
=item C<< of(@parameters) >>
2276

2277
A cute alias for C<parameterize>. Use it like C<< ArrayRef->of(Int) >>.
2278

2279
=item C<< plus_coercions($type1, $code1, ...) >>
2280

2281
Shorthand for creating a new child type constraint with the same coercions
2282
as this one, but then adding some extra coercions (at a higher priority than
2283
the existing ones).
2284

2285
=item C<< plus_fallback_coercions($type1, $code1, ...) >>
2286

2287
Like C<plus_coercions>, but added at a lower priority.
2288

2289
=item C<< minus_coercions($type1, ...) >>
2290

2291
Shorthand for creating a new child type constraint with fewer type coercions.
2292

2293
=item C<< no_coercions >>
2294

2295
Shorthand for creating a new child type constraint with no coercions at all.
2296

2297
=back
2298

2299
=head3 Type relationship introspection methods
2300

2301
These methods allow you to determine a type constraint's relationship to
2302
other type constraints in an organised hierarchy:
2303

2304
=over
2305

2306
=item C<< equals($other) >>, C<< is_subtype_of($other) >>, C<< is_supertype_of($other) >>, C<< is_a_type_of($other) >>
2307

2308
Compare two types. See L<Moose::Meta::TypeConstraint> for what these all mean.
2309
(OK, Moose doesn't define C<is_supertype_of>, but you get the idea, right?)
2310

2311
Note that these have a slightly DWIM side to them. If you create two
2312
L<Type::Tiny::Class> objects which test the same class, they're considered
2313
equal. And:
2314

2315
   my $subtype_of_Num = Types::Standard::Num->create_child_type;
2316
   my $subtype_of_Int = Types::Standard::Int->create_child_type;
2317
   $subtype_of_Int->is_subtype_of( $subtype_of_Num );  # true
2318

2319
=item C<< strictly_equals($other) >>, C<< is_strictly_subtype_of($other) >>, C<< is_strictly_supertype_of($other) >>, C<< is_strictly_a_type_of($other) >>
2320

2321
Stricter versions of the type comparison functions. These only care about
2322
explicit inheritance via C<parent>.
2323

2324
   my $subtype_of_Num = Types::Standard::Num->create_child_type;
2325
   my $subtype_of_Int = Types::Standard::Int->create_child_type;
2326
   $subtype_of_Int->is_strictly_subtype_of( $subtype_of_Num );  # false
2327

2328
=item C<< parents >>
2329

2330
Returns a list of all this type constraint's ancestor constraints. For
2331
example, if called on the C<Str> type constraint would return the list
2332
C<< (Value, Defined, Item, Any) >>.
2333

2334
I<< Due to a historical misunderstanding, this differs from the Moose
2335
implementation of the C<parents> method. In Moose, C<parents> only returns the
2336
immediate parent type constraints, and because type constraints only have
2337
one immediate parent, this is effectively an alias for C<parent>. The
2338
extension module L<MooseX::Meta::TypeConstraint::Intersection> is the only
2339
place where multiple type constraints are returned; and they are returned
2340
as an arrayref in violation of the base class' documentation. I'm keeping
2341
my behaviour as it seems more useful. >>
2342

2343
=item C<< find_parent($coderef) >>
2344

2345
Loops through the parent type constraints I<< including the invocant
2346
itself >> and returns the nearest ancestor type constraint where the
2347
coderef evaluates to true. Within the coderef the ancestor currently
2348
being checked is C<< $_ >>. Returns undef if there is no match.
2349

2350
In list context also returns the number of type constraints which had
2351
been looped through before the matching constraint was found.
2352

2353
=item C<< find_constraining_type >>
2354

2355
Finds the nearest ancestor type constraint (including the type itself)
2356
which has a C<constraint> coderef.
2357

2358
Equivalent to:
2359

2360
   $type->find_parent(sub { not $_->_is_null_constraint })
2361

2362
=item C<< coercibles >>
2363

2364
Return a type constraint which is the union of type constraints that can be
2365
coerced to this one (including this one). If this type constraint has no
2366
coercions, returns itself.
2367

2368
=item C<< type_parameter >>
2369

2370
In parameterized type constraints, returns the first item on the list of
2371
parameters; otherwise returns undef. For example:
2372

2373
   ( ArrayRef[Int] )->type_parameter;    # returns Int
2374
   ( ArrayRef[Int] )->parent;            # returns ArrayRef
2375

2376
Note that parameterizable type constraints can perfectly legitimately take
2377
multiple parameters (several of the parameterizable type constraints in
2378
L<Types::Standard> do). This method only returns the first such parameter.
2379
L</"Attributes related to parameterizable and parameterized types">
2380
documents the C<parameters> attribute, which returns an arrayref of all
2381
the parameters.
2382

2383
=item C<< parameterized_from >>
2384

2385
Harder to spell alias for C<parent> that only works for parameterized
2386
types.
2387

2388
=back
2389

2390
I<< Hint for people subclassing Type::Tiny: >>
2391
Since version 1.006000, the methods for determining subtype, supertype, and
2392
type equality should I<not> be overridden in subclasses of Type::Tiny. This
2393
is because of the problem of diamond inheritance. If X and Y are both
2394
subclasses of Type::Tiny, they I<both> need to be consulted to figure out
2395
how type constraints are related; not just one of them should be overriding
2396
these methods. See the source code for L<Type::Tiny::Enum> for an example of
2397
how subclasses can give hints about type relationships to Type::Tiny.
2398
Summary: push a coderef onto C<< @Type::Tiny::CMP >>. This coderef will be
2399
passed two type constraints. It should then return one of the constants
2400
Type::Tiny::CMP_SUBTYPE (first type is a subtype of second type),
2401
Type::Tiny::CMP_SUPERTYPE (second type is a subtype of first type),
2402
Type::Tiny::CMP_EQUAL (the two types are exactly the same),
2403
Type::Tiny::CMP_EQUIVALENT (the two types are effectively the same), or
2404
Type::Tiny::CMP_UNKNOWN (your coderef couldn't establish any relationship).
2405

2406
=head3 Type relationship introspection function
2407

2408
=over
2409

2410
=item C<< Type::Tiny::cmp($type1, $type2) >>
2411

2412
The subtype/supertype relationship between types results in a partial
2413
ordering of type constraints.
2414

2415
This function will return one of the constants:
2416
Type::Tiny::CMP_SUBTYPE (first type is a subtype of second type),
2417
Type::Tiny::CMP_SUPERTYPE (second type is a subtype of first type),
2418
Type::Tiny::CMP_EQUAL (the two types are exactly the same),
2419
Type::Tiny::CMP_EQUIVALENT (the two types are effectively the same), or
2420
Type::Tiny::CMP_UNKNOWN (couldn't establish any relationship).
2421
In numeric contexts, these evaluate to -1, 1, 0, 0, and 0, making it
2422
potentially usable with C<sort> (though you may need to silence warnings
2423
about treating the empty string as a numeric value).
2424

2425
=back
2426

2427
=head3 List processing methods
2428

2429
=over
2430

2431
=item C<< grep(@list) >>
2432

2433
Filters a list to return just the items that pass the type check.
2434

2435
  @integers = Int->grep(@list);
2436

2437
=item C<< first(@list) >>
2438

2439
Filters the list to return the first item on the list that passes
2440
the type check, or undef if none do.
2441

2442
  $first_lady = Woman->first(@people);
2443

2444
=item C<< map(@list) >>
2445

2446
Coerces a list of items. Only works on types which have a coercion.
2447

2448
  @truths = Bool->map(@list);
2449

2450
=item C<< sort(@list) >>
2451

2452
Sorts a list of items according to the type's preferred sorting mechanism,
2453
or if the type doesn't have a sorter coderef, uses the parent type. If no
2454
ancestor type constraint has a sorter, throws an exception. The C<Str>,
2455
C<StrictNum>, C<LaxNum>, and C<Enum> type constraints include sorters.
2456

2457
  @sorted_numbers = Num->sort( Num->grep(@list) );
2458

2459
=item C<< rsort(@list) >>
2460

2461
Like C<sort> but backwards.
2462

2463
=item C<< any(@list) >>
2464

2465
Returns true if any of the list match the type.
2466

2467
  if ( Int->any(@numbers) ) {
2468
    say "there was at least one integer";
2469
  }
2470

2471
=item C<< all(@list) >>
2472

2473
Returns true if all of the list match the type.
2474

2475
  if ( Int->all(@numbers) ) {
2476
    say "they were all integers";
2477
  }
2478

2479
=item C<< assert_any(@list) >>
2480

2481
Like C<any> but instead of returning a boolean, returns the entire original
2482
list if any item on it matches the type, and dies if none does.
2483

2484
=item C<< assert_all(@list) >>
2485

2486
Like C<all> but instead of returning a boolean, returns the original list if
2487
all items on it match the type, but dies as soon as it finds one that does
2488
not.
2489

2490
=back
2491

2492
=head3 Inlining methods
2493

2494
=for stopwords uated
2495

2496
The following methods are used to generate strings of Perl code which
2497
may be pasted into stringy C<eval>uated subs to perform type checks:
2498

2499
=over
2500

2501
=item C<< can_be_inlined >>
2502

2503
Returns boolean indicating if this type can be inlined.
2504

2505
=item C<< inline_check($varname) >>
2506

2507
Creates a type constraint check for a particular variable as a string of
2508
Perl code. For example:
2509

2510
   print( Types::Standard::Num->inline_check('$foo') );
2511

2512
prints the following output:
2513

2514
   (!ref($foo) && Scalar::Util::looks_like_number($foo))
2515

2516
For Moose-compat, there is an alias C<< _inline_check >> for this method.
2517

2518
=item C<< inline_assert($varname) >>
2519

2520
Much like C<inline_check> but outputs a statement of the form:
2521

2522
   ... or die ...;
2523

2524
Can also be called line C<< inline_assert($varname, $typevarname, %extras) >>.
2525
In this case, it will generate a string of code that may include
2526
C<< $typevarname >> which is supposed to be the name of a variable holding
2527
the type itself. (This is kinda complicated, but it allows a useful string
2528
to still be produced if the type is not inlineable.) The C<< %extras >> are
2529
additional options to be passed to L<Error::TypeTiny::Assertion>'s constructor
2530
and must be key-value pairs of strings only, no references or undefs.
2531

2532
=back
2533

2534
=head3 Other methods
2535

2536
=over
2537

2538
=item C<< qualified_name >>
2539

2540
For non-anonymous type constraints that have a library, returns a qualified
2541
C<< "MyLib::MyType" >> sort of name. Otherwise, returns the same as C<name>.
2542

2543
=item C<< isa($class) >>, C<< can($method) >>, C<< AUTOLOAD(@args) >>
2544

2545
If Moose is loaded, then the combination of these methods is used to mock
2546
a Moose::Meta::TypeConstraint.
2547

2548
If Mouse is loaded, then C<isa> mocks Mouse::Meta::TypeConstraint.
2549

2550
=item C<< DOES($role) >>
2551

2552
Overridden to advertise support for various roles.
2553

2554
See also L<Type::API::Constraint>, etc.
2555

2556
=item C<< TIESCALAR >>, C<< TIEARRAY >>, C<< TIEHASH >>
2557

2558
These are provided as hooks that wrap L<Type::Tie>. They allow the following
2559
to work:
2560

2561
   use Types::Standard qw(Int);
2562
   tie my @list, Int;
2563
   push @list, 123, 456;   # ok
2564
   push @list, "Hello";    # dies
2565

2566
=item C<< exportables( $base_name ) >>
2567

2568
Returns a list of the functions a type library should export if it contains
2569
this type constraint.
2570

2571
Example:
2572

2573
  [
2574
    { name => 'Int',        tags => [ 'types' ],  code => sub { ... } },
2575
    { name => 'is_Int',     tags => [ 'is' ],     code => sub { ... } },
2576
    { name => 'assert_Int', tags => [ 'assert' ], code => sub { ... } },
2577
    { name => 'to_Int',     tags => [ 'to' ],     code => sub { ... } },
2578
  ]
2579

2580
C<< $base_name >> is optional, but allows you to get a list of exportables
2581
using a specific name. This is useful if the type constraint has a name
2582
which wouldn't be a legal Perl function name.
2583

2584
=item C<< exportables_by_tag( $tag, $base_name ) >>
2585

2586
Filters C<exportables> by a specific tag name. In list context, returns all
2587
matching exportables. In scalar context returns a single matching exportable
2588
and dies if multiple exportables match, or none do!
2589

2590
=back
2591

2592
The following methods exist for Moose/Mouse compatibility, but do not do
2593
anything useful.
2594

2595
=over
2596

2597
=item C<< compile_type_constraint >>
2598

2599
=item C<< hand_optimized_type_constraint >>
2600

2601
=item C<< has_hand_optimized_type_constraint >>
2602

2603
=item C<< inline_environment >>
2604

2605
=item C<< meta >>
2606

2607
=back
2608

2609
=head2 Functions
2610

2611
=over
2612

2613
=item *
2614

2615
C<< check_parameter_count_for_parameterized_type( $lib, $typename, $args, $max, $min ) >>
2616

2617
Utility function used by some types from Types::Standard, etc.
2618

2619
Will throw a L<Error::TypeTiny::WrongNumberOfParameters> exception referencing
2620
C<< "$lib::\$typename\[]" >> if C<< $args >> is greater than C<< $max >> or
2621
less than C<< $min >>, if they're defined. If C<< $args >> is an arrayref,
2622
will use the length of the array.
2623

2624
=head2 Overloading
2625

2626
=over
2627

2628
=item *
2629

2630
Stringification is overloaded to return the qualified name.
2631

2632
=item *
2633

2634
Boolification is overloaded to always return true.
2635

2636
=item *
2637

2638
Coderefification is overloaded to call C<assert_return>.
2639

2640
=item *
2641

2642
On Perl 5.10.1 and above, smart match is overloaded to call C<check>.
2643

2644
=item *
2645

2646
The C<< == >> operator is overloaded to call C<equals>.
2647

2648
=item *
2649

2650
The C<< < >> and C<< > >> operators are overloaded to call C<is_subtype_of>
2651
and C<is_supertype_of>.
2652

2653
=item *
2654

2655
The C<< ~ >> operator is overloaded to call C<complementary_type>.
2656

2657
=item *
2658

2659
The C<< | >> operator is overloaded to build a union of two type constraints.
2660
See L<Type::Tiny::Union>.
2661

2662
=item *
2663

2664
The C<< & >> operator is overloaded to build the intersection of two type
2665
constraints. See L<Type::Tiny::Intersection>.
2666

2667
=item *
2668

2669
The C<< / >> operator provides magical L<Devel::StrictMode> support.
2670
If C<< $ENV{PERL_STRICT} >> (or a few other environment variables) is true,
2671
then it returns the left operand. Normally it returns the right operand.
2672

2673
=back
2674

2675
Previous versions of Type::Tiny would overload the C<< + >> operator to
2676
call C<plus_coercions> or C<plus_fallback_coercions> as appropriate.
2677
Support for this was dropped after 0.040.
2678

2679
=head2 Constants
2680

2681
=over
2682

2683
=item C<< Type::Tiny::SUPPORT_SMARTMATCH >>
2684

2685
Indicates whether the smart match overload is supported on your
2686
version of Perl.
2687

2688
=back
2689

2690
=head2 Package Variables
2691

2692
=over
2693

2694
=item C<< $Type::Tiny::DD >>
2695

2696
This undef by default but may be set to a coderef that Type::Tiny
2697
and related modules will use to dump data structures in things like
2698
error messages.
2699

2700
Otherwise Type::Tiny uses it's own routine to dump data structures.
2701
C<< $DD >> may then be set to a number to limit the lengths of the
2702
dumps. (Default limit is 72.)
2703

2704
This is a package variable (rather than get/set class methods) to allow
2705
for easy localization.
2706

2707
=item C<< $Type::Tiny::AvoidCallbacks >>
2708

2709
If this variable is set to true (you should usually do it in a
2710
C<local> scope), it acts as a hint for type constraints, when
2711
generating inlined code, to avoid making any callbacks to
2712
variables and functions defined outside the inlined code itself.
2713

2714
This should have the effect that C<< $type->inline_check('$foo') >>
2715
will return a string of code capable of checking the type on
2716
Perl installations that don't have Type::Tiny installed. This
2717
is intended to allow Type::Tiny to be used with things like
2718
L<Mite>.
2719

2720
The variable works on the honour system. Types need to explicitly
2721
check it and decide to generate different code based on its
2722
truth value. The bundled types in L<Types::Standard>,
2723
L<Types::Common::Numeric>, and L<Types::Common::String> all do.
2724
(B<StrMatch> is sometimes unable to, and will issue a warning
2725
if it needs to rely on callbacks when asked not to.)
2726

2727
Most normal users can ignore this.
2728

2729
=item C<< $Type::Tiny::SafePackage >>
2730

2731
This is the string "package Type::Tiny;" which is sometimes inserted
2732
into strings of inlined code to avoid namespace clashes. In most cases,
2733
you do not need to change this. However, if you are inlining type
2734
constraint code, saving that code into Perl modules, and uploading them
2735
to CPAN, you may wish to change it to avoid problems with the CPAN
2736
indexer. Most normal users of Type::Tiny do not need to be aware of this.
2737

2738
=back
2739

2740
=head2 Environment
2741

2742
=over
2743

2744
=item C<PERL_TYPE_TINY_XS>
2745

2746
Currently this has more effect on L<Types::Standard> than Type::Tiny. In
2747
future it may be used to trigger or suppress the loading XS implementations
2748
of parts of Type::Tiny.
2749

2750
=back
2751

2752
=head1 BUGS
2753

2754
Please report any bugs to
2755
L<https://github.com/tobyink/p5-type-tiny/issues>.
2756

2757
=head1 SEE ALSO
2758

2759
L<The Type::Tiny homepage|https://typetiny.toby.ink/>.
2760

2761
L<Type::Tiny::Manual>, L<Type::API>.
2762

2763
L<Type::Library>, L<Type::Utils>, L<Types::Standard>, L<Type::Coercion>.
2764

2765
L<Type::Tiny::Class>, L<Type::Tiny::Role>, L<Type::Tiny::Duck>,
2766
L<Type::Tiny::Enum>, L<Type::Tiny::Union>, L<Type::Tiny::Intersection>.
2767

2768
L<Moose::Meta::TypeConstraint>,
2769
L<Mouse::Meta::TypeConstraint>.
2770

2771
L<Type::Params>.
2772

2773
L<Type::Tiny on GitHub|https://github.com/tobyink/p5-type-tiny>,
2774
L<Type::Tiny on Travis-CI|https://travis-ci.com/tobyink/p5-type-tiny>,
2775
L<Type::Tiny on AppVeyor|https://ci.appveyor.com/project/tobyink/p5-type-tiny>,
2776
L<Type::Tiny on Codecov|https://codecov.io/gh/tobyink/p5-type-tiny>,
2777
L<Type::Tiny on Coveralls|https://coveralls.io/github/tobyink/p5-type-tiny>.
2778

2779
=head1 AUTHOR
2780

2781
Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
2782

2783
=head1 THANKS
2784

2785
Thanks to Matt S Trout for advice on L<Moo> integration.
2786

2787
=head1 COPYRIGHT AND LICENCE
2788

2789
This software is copyright (c) 2013-2014, 2017-2025 by Toby Inkster.
2790

2791
This is free software; you can redistribute it and/or modify it under
2792
the same terms as the Perl 5 programming language system itself.
2793

2794
=head1 DISCLAIMER OF WARRANTIES
2795

2796
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
2797
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2798
MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc