| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Mouse::Util::TypeConstraints; | 
| 2 | 283 |  |  | 283 |  | 135391 | use Mouse::Util; # enables strict and warnings | 
|  | 283 |  |  |  |  | 296 |  | 
|  | 283 |  |  |  |  | 1248 |  | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 283 |  |  | 283 |  | 3902 | use Mouse::Meta::TypeConstraint; | 
|  | 283 |  |  |  |  | 309 |  | 
|  | 283 |  |  |  |  | 4337 |  | 
| 5 | 283 |  |  | 283 |  | 844 | use Mouse::Exporter; | 
|  | 283 |  |  |  |  | 272 |  | 
|  | 283 |  |  |  |  | 1123 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 283 |  |  | 283 |  | 960 | use Carp         (); | 
|  | 283 |  |  |  |  | 305 |  | 
|  | 283 |  |  |  |  | 3255 |  | 
| 8 | 283 |  |  | 283 |  | 786 | use Scalar::Util (); | 
|  | 283 |  |  |  |  | 303 |  | 
|  | 283 |  |  |  |  | 658070 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | Mouse::Exporter->setup_import_methods( | 
| 11 |  |  |  |  |  |  | as_is => [qw( | 
| 12 |  |  |  |  |  |  | as where message optimize_as | 
| 13 |  |  |  |  |  |  | from via | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | type subtype class_type role_type maybe_type duck_type | 
| 16 |  |  |  |  |  |  | enum | 
| 17 |  |  |  |  |  |  | coerce | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | find_type_constraint | 
| 20 |  |  |  |  |  |  | register_type_constraint | 
| 21 |  |  |  |  |  |  | )], | 
| 22 |  |  |  |  |  |  | ); | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | our @CARP_NOT = qw(Mouse::Meta::Attribute); | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | my %TYPE; | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | # The root type | 
| 29 |  |  |  |  |  |  | $TYPE{Any} = Mouse::Meta::TypeConstraint->new( | 
| 30 |  |  |  |  |  |  | name => 'Any', | 
| 31 |  |  |  |  |  |  | ); | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | my @builtins = ( | 
| 34 |  |  |  |  |  |  | # $name    => $parent,   $code, | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | # the base type | 
| 37 |  |  |  |  |  |  | Item       => 'Any',     undef, | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | # the maybe[] type | 
| 40 |  |  |  |  |  |  | Maybe      => 'Item',    undef, | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | # value types | 
| 43 |  |  |  |  |  |  | Undef      => 'Item',    \&Undef, | 
| 44 |  |  |  |  |  |  | Defined    => 'Item',    \&Defined, | 
| 45 |  |  |  |  |  |  | Bool       => 'Item',    \&Bool, | 
| 46 |  |  |  |  |  |  | Value      => 'Defined', \&Value, | 
| 47 |  |  |  |  |  |  | Str        => 'Value',   \&Str, | 
| 48 |  |  |  |  |  |  | Num        => 'Str',     \&Num, | 
| 49 |  |  |  |  |  |  | Int        => 'Num',     \&Int, | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | # ref types | 
| 52 |  |  |  |  |  |  | Ref        => 'Defined', \&Ref, | 
| 53 |  |  |  |  |  |  | ScalarRef  => 'Ref',     \&ScalarRef, | 
| 54 |  |  |  |  |  |  | ArrayRef   => 'Ref',     \&ArrayRef, | 
| 55 |  |  |  |  |  |  | HashRef    => 'Ref',     \&HashRef, | 
| 56 |  |  |  |  |  |  | CodeRef    => 'Ref',     \&CodeRef, | 
| 57 |  |  |  |  |  |  | RegexpRef  => 'Ref',     \&RegexpRef, | 
| 58 |  |  |  |  |  |  | GlobRef    => 'Ref',     \&GlobRef, | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | # object types | 
| 61 |  |  |  |  |  |  | FileHandle => 'GlobRef', \&FileHandle, | 
| 62 |  |  |  |  |  |  | Object     => 'Ref',     \&Object, | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | # special string types | 
| 65 |  |  |  |  |  |  | ClassName  => 'Str',       \&ClassName, | 
| 66 |  |  |  |  |  |  | RoleName   => 'ClassName', \&RoleName, | 
| 67 |  |  |  |  |  |  | ); | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | while (my ($name, $parent, $code) = splice @builtins, 0, 3) { | 
| 70 |  |  |  |  |  |  | $TYPE{$name} = Mouse::Meta::TypeConstraint->new( | 
| 71 |  |  |  |  |  |  | name      => $name, | 
| 72 |  |  |  |  |  |  | parent    => $TYPE{$parent}, | 
| 73 |  |  |  |  |  |  | optimized => $code, | 
| 74 |  |  |  |  |  |  | ); | 
| 75 |  |  |  |  |  |  | } | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | # parametarizable types | 
| 78 |  |  |  |  |  |  | $TYPE{Maybe}   {constraint_generator} = \&_parameterize_Maybe_for; | 
| 79 |  |  |  |  |  |  | $TYPE{ArrayRef}{constraint_generator} = \&_parameterize_ArrayRef_for; | 
| 80 |  |  |  |  |  |  | $TYPE{HashRef} {constraint_generator} = \&_parameterize_HashRef_for; | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | # sugars | 
| 83 | 59 |  |  | 59 | 1 | 12473 | sub as          ($) { (as          => $_[0]) } ## no critic | 
| 84 | 58 |  |  | 58 | 1 | 3184 | sub where       (&) { (where       => $_[0]) } ## no critic | 
| 85 | 7 |  |  | 7 | 0 | 18 | sub message     (&) { (message     => $_[0]) } ## no critic | 
| 86 | 0 |  |  | 0 | 0 | 0 | sub optimize_as (&) { (optimize_as => $_[0]) } ## no critic | 
| 87 |  |  |  |  |  |  |  | 
| 88 | 37 |  |  | 37 | 1 | 108 | sub from    { @_ } | 
| 89 | 37 |  |  | 37 | 1 | 2307 | sub via (&) { $_[0] } ## no critic | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | # type utilities | 
| 92 |  |  |  |  |  |  |  | 
| 93 |  |  |  |  |  |  | sub optimized_constraints { # DEPRECATED | 
| 94 | 0 |  |  | 0 | 0 | 0 | Carp::cluck('optimized_constraints() has been deprecated'); | 
| 95 | 0 |  |  |  |  | 0 | return \%TYPE; | 
| 96 |  |  |  |  |  |  | } | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | undef @builtins;        # free the allocated memory | 
| 99 |  |  |  |  |  |  | @builtins = keys %TYPE; # reuse it | 
| 100 | 1 |  |  | 1 | 1 | 7 | sub list_all_builtin_type_constraints { @builtins } | 
| 101 | 5 |  |  | 5 | 1 | 469 | sub list_all_type_constraints         { keys %TYPE } | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | sub _define_type { | 
| 104 | 853 |  |  | 853 |  | 870 | my $is_subtype = shift; | 
| 105 | 853 |  |  |  |  | 741 | my $name; | 
| 106 |  |  |  |  |  |  | my %args; | 
| 107 |  |  |  |  |  |  |  | 
| 108 | 853 | 50 | 33 |  |  | 4512 | if(@_ == 1 && ref $_[0] ){    # @_ : { name => $name, where => ... } | 
|  |  | 50 | 66 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 109 | 0 |  |  |  |  | 0 | %args = %{$_[0]}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  | elsif(@_ == 2 && ref $_[1]) { # @_ : $name => { where => ... } | 
| 112 | 0 |  |  |  |  | 0 | $name = $_[0]; | 
| 113 | 0 |  |  |  |  | 0 | %args = %{$_[1]}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  | elsif(@_ % 2) {               # @_ : $name => ( where => ... ) | 
| 116 | 850 |  |  |  |  | 2668 | ($name, %args) = @_; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  | else{                         # @_ : (name => $name, where => ...) | 
| 119 | 3 |  |  |  |  | 10 | %args = @_; | 
| 120 |  |  |  |  |  |  | } | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 853 | 100 |  |  |  | 1791 | if(!defined $name){ | 
| 123 | 7 |  |  |  |  | 16 | $name = $args{name}; | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 853 |  |  |  |  | 1395 | $args{name} = $name; | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 853 |  |  |  |  | 1139 | my $parent = delete $args{as}; | 
| 129 | 853 | 100 | 100 |  |  | 3343 | if($is_subtype && !$parent){ | 
| 130 | 3 |  |  |  |  | 7 | $parent = delete $args{name}; | 
| 131 | 3 |  |  |  |  | 7 | $name   = undef; | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  | 
| 134 | 853 | 100 |  |  |  | 1471 | if(defined $parent) { | 
| 135 | 838 |  |  |  |  | 1408 | $args{parent} = find_or_create_isa_type_constraint($parent); | 
| 136 |  |  |  |  |  |  | } | 
| 137 |  |  |  |  |  |  |  | 
| 138 | 852 | 100 |  |  |  | 1426 | if(defined $name){ | 
| 139 |  |  |  |  |  |  | # set 'package_defined_in' only if it is not a core package | 
| 140 | 842 |  |  |  |  | 823 | my $this = $args{package_defined_in}; | 
| 141 | 842 | 50 |  |  |  | 1364 | if(!$this){ | 
| 142 | 842 |  |  |  |  | 1326 | $this = caller(1); | 
| 143 | 842 | 100 |  |  |  | 6177 | if($this !~ /\A Mouse \b/xms){ | 
| 144 | 79 |  |  |  |  | 142 | $args{package_defined_in} = $this; | 
| 145 |  |  |  |  |  |  | } | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 | 842 | 100 |  |  |  | 1677 | if(defined $TYPE{$name}){ | 
| 149 | 10 |  | 100 |  |  | 104 | my $that = $TYPE{$name}->{package_defined_in} || __PACKAGE__; | 
| 150 | 10 | 100 |  |  |  | 31 | if($this ne $that) { | 
| 151 | 3 |  |  |  |  | 6 | my $note = ''; | 
| 152 | 3 | 100 |  |  |  | 9 | if($that eq __PACKAGE__) { | 
| 153 |  |  |  |  |  |  | $note = sprintf " ('%s' is %s type constraint)", | 
| 154 |  |  |  |  |  |  | $name, | 
| 155 | 1 | 50 |  |  |  | 3 | scalar(grep { $name eq $_ } list_all_builtin_type_constraints()) | 
|  | 21 |  |  |  |  | 27 |  | 
| 156 |  |  |  |  |  |  | ? 'a builtin' | 
| 157 |  |  |  |  |  |  | : 'an implicitly created'; | 
| 158 |  |  |  |  |  |  | } | 
| 159 | 3 |  |  |  |  | 489 | Carp::croak("The type constraint '$name' has already been created in $that" | 
| 160 |  |  |  |  |  |  | . " and cannot be created again in $this" . $note); | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 | 849 | 100 |  |  |  | 1424 | $args{constraint} = delete $args{where}        if exists $args{where}; | 
| 166 | 849 | 100 |  |  |  | 1850 | $args{optimized}  = delete $args{optimized_as} if exists $args{optimized_as}; | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 849 |  |  |  |  | 3590 | my $constraint = Mouse::Meta::TypeConstraint->new(%args); | 
| 169 |  |  |  |  |  |  |  | 
| 170 | 849 | 100 |  |  |  | 1561 | if(defined $name){ | 
| 171 | 839 |  |  |  |  | 2727 | return $TYPE{$name} = $constraint; | 
| 172 |  |  |  |  |  |  | } | 
| 173 |  |  |  |  |  |  | else{ | 
| 174 | 10 |  |  |  |  | 43 | return $constraint; | 
| 175 |  |  |  |  |  |  | } | 
| 176 |  |  |  |  |  |  | } | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | sub type { | 
| 179 | 15 |  |  | 15 | 1 | 38 | return _define_type 0, @_; | 
| 180 |  |  |  |  |  |  | } | 
| 181 |  |  |  |  |  |  |  | 
| 182 |  |  |  |  |  |  | sub subtype { | 
| 183 | 825 |  |  | 825 | 1 | 1442 | return _define_type 1, @_; | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | sub coerce { # coerce $type, from $from, via { ... }, ... | 
| 187 | 31 |  |  | 31 | 1 | 43 | my $type_name = shift; | 
| 188 | 31 | 100 |  |  |  | 78 | my $type = find_type_constraint($type_name) | 
| 189 |  |  |  |  |  |  | or Carp::croak("Cannot find type '$type_name', perhaps you forgot to load it"); | 
| 190 |  |  |  |  |  |  |  | 
| 191 | 30 |  |  |  |  | 146 | $type->_add_type_coercions(@_); | 
| 192 | 28 |  |  |  |  | 45 | return; | 
| 193 |  |  |  |  |  |  | } | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | sub class_type { | 
| 196 | 570 |  |  | 570 | 1 | 691 | my($name, $options) = @_; | 
| 197 | 570 |  | 33 |  |  | 1894 | my $class = $options->{class} || $name; | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | # ClassType | 
| 200 | 570 |  |  |  |  | 3441 | return subtype $name => ( | 
| 201 |  |  |  |  |  |  | as           => 'Object', | 
| 202 |  |  |  |  |  |  | optimized_as => Mouse::Util::generate_isa_predicate_for($class), | 
| 203 |  |  |  |  |  |  | class        => $class, | 
| 204 |  |  |  |  |  |  | ); | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub role_type { | 
| 208 | 193 |  |  | 193 | 1 | 278 | my($name, $options) = @_; | 
| 209 | 193 |  | 66 |  |  | 649 | my $role = $options->{role} || $name; | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | # RoleType | 
| 212 |  |  |  |  |  |  | return subtype $name => ( | 
| 213 |  |  |  |  |  |  | as           => 'Object', | 
| 214 |  |  |  |  |  |  | optimized_as => sub { | 
| 215 | 23 |  | 100 | 23 |  | 4156 | return Scalar::Util::blessed($_[0]) | 
| 216 |  |  |  |  |  |  | && Mouse::Util::does_role($_[0], $role); | 
| 217 |  |  |  |  |  |  | }, | 
| 218 | 193 |  |  |  |  | 746 | role         => $role, | 
| 219 |  |  |  |  |  |  | ); | 
| 220 |  |  |  |  |  |  | } | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | sub maybe_type { | 
| 223 | 1 |  |  | 1 | 0 | 1 | my $param = shift; | 
| 224 | 1 |  |  |  |  | 7 | return _find_or_create_parameterized_type($TYPE{Maybe}, $param); | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | sub duck_type { | 
| 228 | 6 |  |  | 6 | 1 | 27 | my($name, @methods); | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 6 | 100 |  |  |  | 17 | if(ref($_[0]) ne 'ARRAY'){ | 
| 231 | 4 |  |  |  |  | 7 | $name = shift; | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  |  | 
| 234 | 6 | 100 | 66 |  |  | 29 | @methods = (@_ == 1 && ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_; | 
|  | 4 |  |  |  |  | 8 |  | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | # DuckType | 
| 237 |  |  |  |  |  |  | return _define_type 1, $name => ( | 
| 238 |  |  |  |  |  |  | as           => 'Object', | 
| 239 |  |  |  |  |  |  | optimized_as => Mouse::Util::generate_can_predicate_for(\@methods), | 
| 240 |  |  |  |  |  |  | message      => sub { | 
| 241 | 1 |  |  | 1 |  | 2 | my($object) = @_; | 
| 242 | 1 |  |  |  |  | 2 | my @missing = grep { !$object->can($_) } @methods; | 
|  | 1 |  |  |  |  | 10 |  | 
| 243 | 1 |  |  |  |  | 6 | return ref($object) | 
| 244 |  |  |  |  |  |  | . ' is missing methods ' | 
| 245 |  |  |  |  |  |  | . Mouse::Util::quoted_english_list(@missing); | 
| 246 |  |  |  |  |  |  | }, | 
| 247 | 6 |  |  |  |  | 64 | methods      => \@methods, | 
| 248 |  |  |  |  |  |  | ); | 
| 249 |  |  |  |  |  |  | } | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | sub enum { | 
| 252 | 7 |  |  | 7 | 1 | 872 | my($name, %valid); | 
| 253 |  |  |  |  |  |  |  | 
| 254 | 7 | 100 | 66 |  |  | 27 | if(!(@_ == 1 && ref($_[0]) eq 'ARRAY')){ | 
| 255 | 5 |  |  |  |  | 8 | $name = shift; | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 78 |  |  |  |  | 92 | %valid = map{ $_ => undef } | 
| 259 | 7 | 100 | 66 |  |  | 26 | (@_ == 1 && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_); | 
|  | 3 |  |  |  |  | 6 |  | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | # EnumType | 
| 262 |  |  |  |  |  |  | return _define_type 1, $name => ( | 
| 263 |  |  |  |  |  |  | as            => 'Str', | 
| 264 |  |  |  |  |  |  | optimized_as  => sub{ | 
| 265 | 120 |  | 66 | 120 |  | 27799 | return defined($_[0]) && !ref($_[0]) && exists $valid{$_[0]}; | 
| 266 |  |  |  |  |  |  | }, | 
| 267 | 7 |  |  |  |  | 32 | ); | 
| 268 |  |  |  |  |  |  | } | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | sub _find_or_create_regular_type{ | 
| 271 | 128 |  |  | 128 |  | 241 | my($spec, $create)  = @_; | 
| 272 |  |  |  |  |  |  |  | 
| 273 | 128 | 100 |  |  |  | 446 | return $TYPE{$spec} if exists $TYPE{$spec}; | 
| 274 |  |  |  |  |  |  |  | 
| 275 | 13 |  |  |  |  | 48 | my $meta = Mouse::Util::get_metaclass_by_name($spec); | 
| 276 |  |  |  |  |  |  |  | 
| 277 | 13 | 50 |  |  |  | 38 | if(!defined $meta){ | 
| 278 | 13 | 100 |  |  |  | 45 | return $create ? class_type($spec) : undef; | 
| 279 |  |  |  |  |  |  | } | 
| 280 |  |  |  |  |  |  |  | 
| 281 | 0 | 0 |  |  |  | 0 | if(Mouse::Util::is_a_metarole($meta)){ | 
| 282 | 0 |  |  |  |  | 0 | return role_type($spec); | 
| 283 |  |  |  |  |  |  | } | 
| 284 |  |  |  |  |  |  | else{ | 
| 285 | 0 |  |  |  |  | 0 | return class_type($spec); | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  | } | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | sub _find_or_create_parameterized_type{ | 
| 290 | 45 |  |  | 45 |  | 55 | my($base, $param) = @_; | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 45 |  |  |  |  | 330 | my $name = sprintf '%s[%s]', $base->name, $param->name; | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 45 |  | 100 |  |  | 322 | $TYPE{$name} ||= $base->parameterize($param, $name); | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | sub _find_or_create_union_type{ | 
| 298 | 22 | 50 |  | 22 |  | 35 | return if grep{ not defined } @_; # all things must be defined | 
|  | 48 |  |  |  |  | 92 |  | 
| 299 |  |  |  |  |  |  | my @types = sort | 
| 300 | 22 | 100 |  |  |  | 30 | map{ $_->{type_constraints} ? @{$_->{type_constraints}} : $_ } @_; | 
|  | 48 |  |  |  |  | 290 |  | 
|  | 2 |  |  |  |  | 4 |  | 
| 301 |  |  |  |  |  |  |  | 
| 302 | 22 |  |  |  |  | 55 | my $name = join '|', @types; | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | # UnionType | 
| 305 | 22 |  | 66 |  |  | 137 | $TYPE{$name} ||= Mouse::Meta::TypeConstraint->new( | 
| 306 |  |  |  |  |  |  | name              => $name, | 
| 307 |  |  |  |  |  |  | type_constraints  => \@types, | 
| 308 |  |  |  |  |  |  | ); | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | # The type parser | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | # param : '[' type ']' | NOTHING | 
| 314 |  |  |  |  |  |  | sub _parse_param { | 
| 315 | 128 |  |  | 128 |  | 200 | my($c) = @_; | 
| 316 |  |  |  |  |  |  |  | 
| 317 | 128 | 100 |  |  |  | 499 | if($c->{spec} =~ s/^\[//){ | 
| 318 | 44 |  |  |  |  | 111 | my $type = _parse_type($c, 1); | 
| 319 |  |  |  |  |  |  |  | 
| 320 | 44 | 50 |  |  |  | 185 | if($c->{spec} =~ s/^\]//){ | 
| 321 | 44 |  |  |  |  | 64 | return $type; | 
| 322 |  |  |  |  |  |  | } | 
| 323 | 0 |  |  |  |  | 0 | Carp::croak("Syntax error in type: missing right square bracket in '$c->{orig}'"); | 
| 324 |  |  |  |  |  |  | } | 
| 325 |  |  |  |  |  |  |  | 
| 326 | 84 |  |  |  |  | 114 | return undef; | 
| 327 |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | # name : [\w.:]+ | 
| 330 |  |  |  |  |  |  | sub _parse_name { | 
| 331 | 128 |  |  | 128 |  | 119 | my($c, $create) = @_; | 
| 332 |  |  |  |  |  |  |  | 
| 333 | 128 | 50 |  |  |  | 604 | if($c->{spec} =~ s/\A ([\w.:]+) //xms){ | 
| 334 | 128 |  |  |  |  | 250 | return _find_or_create_regular_type($1, $create); | 
| 335 |  |  |  |  |  |  | } | 
| 336 | 0 |  |  |  |  | 0 | Carp::croak("Syntax error in type: expect type name near '$c->{spec}' in '$c->{orig}'"); | 
| 337 |  |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | # single_type : name param | 
| 340 |  |  |  |  |  |  | sub _parse_single_type { | 
| 341 | 128 |  |  | 128 |  | 143 | my($c, $create) = @_; | 
| 342 |  |  |  |  |  |  |  | 
| 343 | 128 |  |  |  |  | 193 | my $type  = _parse_name($c, $create); | 
| 344 | 128 |  |  |  |  | 271 | my $param = _parse_param($c); | 
| 345 |  |  |  |  |  |  |  | 
| 346 | 128 | 100 |  |  |  | 232 | if(defined $type){ | 
|  |  | 50 |  |  |  |  |  | 
| 347 | 118 | 100 |  |  |  | 164 | if(defined $param){ | 
| 348 | 44 |  |  |  |  | 116 | return _find_or_create_parameterized_type($type, $param); | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  | else { | 
| 351 | 74 |  |  |  |  | 133 | return $type; | 
| 352 |  |  |  |  |  |  | } | 
| 353 |  |  |  |  |  |  | } | 
| 354 |  |  |  |  |  |  | elsif(defined $param){ | 
| 355 | 0 |  |  |  |  | 0 | Carp::croak("Undefined type with parameter [$param] in '$c->{orig}'"); | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  | else{ | 
| 358 | 10 |  |  |  |  | 19 | return undef; | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | # type : single_type  ('|' single_type)* | 
| 363 |  |  |  |  |  |  | sub _parse_type { | 
| 364 | 108 |  |  | 108 |  | 127 | my($c, $create) = @_; | 
| 365 |  |  |  |  |  |  |  | 
| 366 | 108 |  |  |  |  | 223 | my $type = _parse_single_type($c, $create); | 
| 367 | 107 | 100 |  |  |  | 242 | if($c->{spec}){ # can be an union type | 
| 368 | 58 |  |  |  |  | 68 | my @types; | 
| 369 | 58 |  |  |  |  | 182 | while($c->{spec} =~ s/^\|//){ | 
| 370 | 20 |  |  |  |  | 32 | push @types, _parse_single_type($c, $create); | 
| 371 |  |  |  |  |  |  | } | 
| 372 | 58 | 100 |  |  |  | 137 | if(@types){ | 
| 373 | 16 |  |  |  |  | 37 | return _find_or_create_union_type($type, @types); | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  | } | 
| 376 | 91 |  |  |  |  | 140 | return $type; | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | sub find_type_constraint { | 
| 381 | 972 |  |  | 972 | 1 | 20449 | my($spec) = @_; | 
| 382 | 972 | 100 | 66 |  |  | 4321 | return $spec if Mouse::Util::is_a_type_constraint($spec) or not defined $spec; | 
| 383 |  |  |  |  |  |  |  | 
| 384 | 971 |  |  |  |  | 2026 | $spec =~ s/\s+//g; | 
| 385 | 971 |  |  |  |  | 3937 | return $TYPE{$spec}; | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | sub register_type_constraint { | 
| 389 | 2 |  |  | 2 | 0 | 7 | my($constraint) = @_; | 
| 390 | 2 | 50 |  |  |  | 6 | Carp::croak("No type supplied / type is not a valid type constraint") | 
| 391 |  |  |  |  |  |  | unless Mouse::Util::is_a_type_constraint($constraint); | 
| 392 | 2 |  |  |  |  | 6 | return $TYPE{$constraint->name} = $constraint; | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | sub find_or_parse_type_constraint { | 
| 396 | 1251 |  |  | 1251 | 0 | 8131 | my($spec) = @_; | 
| 397 | 1251 | 100 | 66 |  |  | 5163 | return $spec if Mouse::Util::is_a_type_constraint($spec) or not defined $spec; | 
| 398 |  |  |  |  |  |  |  | 
| 399 | 1233 |  |  |  |  | 2019 | $spec =~ tr/ \t\r\n//d; | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 1233 |  |  |  |  | 1645 | my $tc = $TYPE{$spec}; | 
| 402 | 1233 | 100 |  |  |  | 2466 | if(defined $tc) { | 
| 403 | 1169 |  |  |  |  | 1723 | return $tc; | 
| 404 |  |  |  |  |  |  | } | 
| 405 |  |  |  |  |  |  |  | 
| 406 | 64 |  |  |  |  | 214 | my %context = ( | 
| 407 |  |  |  |  |  |  | spec => $spec, | 
| 408 |  |  |  |  |  |  | orig => $spec, | 
| 409 |  |  |  |  |  |  | ); | 
| 410 | 64 |  |  |  |  | 192 | $tc = _parse_type(\%context); | 
| 411 |  |  |  |  |  |  |  | 
| 412 | 63 | 50 |  |  |  | 166 | if($context{spec}){ | 
| 413 | 0 |  |  |  |  | 0 | Carp::croak("Syntax error: extra elements '$context{spec}' in '$context{orig}'"); | 
| 414 |  |  |  |  |  |  | } | 
| 415 |  |  |  |  |  |  |  | 
| 416 | 63 |  |  |  |  | 209 | return $TYPE{$spec} = $tc; | 
| 417 |  |  |  |  |  |  | } | 
| 418 |  |  |  |  |  |  |  | 
| 419 |  |  |  |  |  |  | sub find_or_create_does_type_constraint{ | 
| 420 |  |  |  |  |  |  | # XXX: Moose does not register a new role_type, but Mouse does. | 
| 421 | 5 |  |  | 5 | 0 | 13 | my $tc = find_or_parse_type_constraint(@_); | 
| 422 | 5 | 50 |  |  |  | 25 | return defined($tc) ? $tc : role_type(@_); | 
| 423 |  |  |  |  |  |  | } | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | sub find_or_create_isa_type_constraint { | 
| 426 |  |  |  |  |  |  | # XXX: Moose does not register a new class_type, but Mouse does. | 
| 427 | 1196 |  |  | 1196 | 0 | 2042 | my $tc = find_or_parse_type_constraint(@_); | 
| 428 | 1195 | 100 |  |  |  | 3129 | return defined($tc) ? $tc : class_type(@_); | 
| 429 |  |  |  |  |  |  | } | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | 1; | 
| 432 |  |  |  |  |  |  | __END__ |