| Filename | /usr/local/lib/perl/5.10.1/Mouse/Meta/TypeConstraint.pm |
| Statements | Executed 547 statements in 2.63ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 29 | 3 | 1 | 730µs | 751µs | Mouse::Meta::TypeConstraint::new |
| 3 | 1 | 1 | 21µs | 21µs | Mouse::Meta::TypeConstraint::compile_type_constraint (xsub) |
| 19 | 4 | 4 | 18µs | 18µs | Mouse::Meta::TypeConstraint::_compiled_type_constraint (xsub) |
| 1 | 1 | 1 | 16µs | 66µs | Mouse::Meta::TypeConstraint::BEGIN@2 |
| 2 | 1 | 1 | 5µs | 5µs | Mouse::Meta::TypeConstraint::_identity (xsub) |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::__ANON__[:157] |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::__ANON__[:174] |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::__ANON__[:50] |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::_add_type_coercions |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::_as_string |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::_compiled_type_coercion |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::_unite |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::assert_valid |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::coerce |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::create_child_type |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::get_message |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::is_a_type_of |
| 0 | 0 | 0 | 0s | 0s | Mouse::Meta::TypeConstraint::parameterize |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Mouse::Meta::TypeConstraint; | ||||
| 2 | 3 | 1.83ms | 2 | 115µs | # spent 66µs (16+50) within Mouse::Meta::TypeConstraint::BEGIN@2 which was called:
# once (16µs+50µs) by Mouse::Meta::Attribute::BEGIN@6 at line 2 # spent 66µs making 1 call to Mouse::Meta::TypeConstraint::BEGIN@2
# spent 50µs making 1 call to Mouse::Exporter::do_import |
| 3 | |||||
| 4 | # spent 751µs (730+21) within Mouse::Meta::TypeConstraint::new which was called 29 times, avg 26µs/call:
# 20 times (383µs+11µs) by Mouse::BEGIN@18 at line 69 of Mouse/Util/TypeConstraints.pm, avg 20µs/call
# 8 times (293µs+0s) by Mouse::Util::TypeConstraints::_define_type at line 168 of Mouse/Util/TypeConstraints.pm, avg 37µs/call
# once (54µs+11µs) by Mouse::BEGIN@18 at line 29 of Mouse/Util/TypeConstraints.pm | ||||
| 5 | 348 | 498µs | my $class = shift; | ||
| 6 | my %args = @_ == 1 ? %{$_[0]} : @_; | ||||
| 7 | |||||
| 8 | $args{name} = '__ANON__' if !defined $args{name}; | ||||
| 9 | |||||
| 10 | my $type_parameter; | ||||
| 11 | 140 | 259µs | if(defined $args{parent}) { # subtyping | ||
| 12 | %args = (%{$args{parent}}, %args); | ||||
| 13 | |||||
| 14 | # a child type must not inherit 'compiled_type_constraint' | ||||
| 15 | # and 'hand_optimized_type_constraint' from the parent | ||||
| 16 | delete $args{compiled_type_constraint}; # don't inherit it | ||||
| 17 | delete $args{hand_optimized_type_constraint}; # don't inherit it | ||||
| 18 | |||||
| 19 | $type_parameter = $args{type_parameter}; | ||||
| 20 | if(defined(my $parent_tp = $args{parent}{type_parameter})) { | ||||
| 21 | if($parent_tp != $type_parameter) { | ||||
| 22 | $type_parameter->is_a_type_of($parent_tp) | ||||
| 23 | or $class->throw_error( | ||||
| 24 | "$type_parameter is not a subtype of $parent_tp", | ||||
| 25 | ); | ||||
| 26 | } | ||||
| 27 | else { | ||||
| 28 | $type_parameter = undef; | ||||
| 29 | } | ||||
| 30 | } | ||||
| 31 | } | ||||
| 32 | |||||
| 33 | my $check; | ||||
| 34 | |||||
| 35 | 55 | 32µs | if($check = delete $args{optimized}) { # likely to be builtins | ||
| 36 | $args{hand_optimized_type_constraint} = $check; | ||||
| 37 | $args{compiled_type_constraint} = $check; | ||||
| 38 | } | ||||
| 39 | elsif(defined $type_parameter) { # parameterizing | ||||
| 40 | my $generator = $args{constraint_generator} | ||||
| 41 | || $class->throw_error( | ||||
| 42 | "The $args{name} constraint cannot be used," | ||||
| 43 | . " because $type_parameter doesn't subtype" | ||||
| 44 | . " from a parameterizable type"); | ||||
| 45 | |||||
| 46 | my $parameterized_check = $generator->($type_parameter); | ||||
| 47 | if(defined(my $my_check = $args{constraint})) { | ||||
| 48 | $check = sub { | ||||
| 49 | return $parameterized_check->($_) && $my_check->($_); | ||||
| 50 | }; | ||||
| 51 | } | ||||
| 52 | else { | ||||
| 53 | $check = $parameterized_check; | ||||
| 54 | } | ||||
| 55 | $args{constraint} = $check; | ||||
| 56 | } | ||||
| 57 | else { # common cases | ||||
| 58 | $check = $args{constraint}; | ||||
| 59 | } | ||||
| 60 | |||||
| 61 | if(defined($check) && ref($check) ne 'CODE'){ | ||||
| 62 | $class->throw_error( | ||||
| 63 | "Constraint for $args{name} is not a CODE reference"); | ||||
| 64 | } | ||||
| 65 | |||||
| 66 | my $self = bless \%args, $class; | ||||
| 67 | 3 | 21µs | $self->compile_type_constraint() # spent 21µs making 3 calls to Mouse::Meta::TypeConstraint::compile_type_constraint, avg 7µs/call | ||
| 68 | if !$args{hand_optimized_type_constraint}; | ||||
| 69 | |||||
| 70 | if($args{type_constraints}) { # union types | ||||
| 71 | foreach my $type(@{$self->{type_constraints}}){ | ||||
| 72 | if($type->has_coercion){ | ||||
| 73 | # set undef for has_coercion() | ||||
| 74 | $self->{_compiled_type_coercion} = undef; | ||||
| 75 | last; | ||||
| 76 | } | ||||
| 77 | } | ||||
| 78 | } | ||||
| 79 | |||||
| 80 | return $self; | ||||
| 81 | } | ||||
| 82 | |||||
| 83 | sub create_child_type { | ||||
| 84 | my $self = shift; | ||||
| 85 | return ref($self)->new(@_, parent => $self); | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | sub name; | ||||
| 89 | sub parent; | ||||
| 90 | sub message; | ||||
| 91 | sub has_coercion; | ||||
| 92 | |||||
| 93 | sub check; | ||||
| 94 | |||||
| 95 | sub type_parameter; | ||||
| 96 | sub __is_parameterized; | ||||
| 97 | |||||
| 98 | sub _compiled_type_constraint; | ||||
| 99 | sub _compiled_type_coercion; | ||||
| 100 | |||||
| 101 | sub compile_type_constraint; | ||||
| 102 | |||||
| 103 | |||||
| 104 | sub _add_type_coercions { # ($self, @pairs) | ||||
| 105 | my $self = shift; | ||||
| 106 | |||||
| 107 | if(exists $self->{type_constraints}){ # union type | ||||
| 108 | $self->throw_error( | ||||
| 109 | "Cannot add additional type coercions to Union types '$self'"); | ||||
| 110 | } | ||||
| 111 | |||||
| 112 | my $coercion_map = ($self->{coercion_map} ||= []); | ||||
| 113 | my %has = map{ $_->[0]->name => undef } @{$coercion_map}; | ||||
| 114 | |||||
| 115 | for(my $i = 0; $i < @_; $i++){ | ||||
| 116 | my $from = $_[ $i]; | ||||
| 117 | my $action = $_[++$i]; | ||||
| 118 | |||||
| 119 | if(exists $has{$from}){ | ||||
| 120 | $self->throw_error("A coercion action already exists for '$from'"); | ||||
| 121 | } | ||||
| 122 | |||||
| 123 | my $type = Mouse::Util::TypeConstraints::find_or_parse_type_constraint($from) | ||||
| 124 | or $self->throw_error( | ||||
| 125 | "Could not find the type constraint ($from) to coerce from"); | ||||
| 126 | |||||
| 127 | push @{$coercion_map}, [ $type => $action ]; | ||||
| 128 | } | ||||
| 129 | |||||
| 130 | $self->{_compiled_type_coercion} = undef; | ||||
| 131 | return; | ||||
| 132 | } | ||||
| 133 | |||||
| 134 | sub _compiled_type_coercion { | ||||
| 135 | my($self) = @_; | ||||
| 136 | |||||
| 137 | my $coercion = $self->{_compiled_type_coercion}; | ||||
| 138 | return $coercion if defined $coercion; | ||||
| 139 | |||||
| 140 | if(!$self->{type_constraints}) { | ||||
| 141 | my @coercions; | ||||
| 142 | foreach my $pair(@{$self->{coercion_map}}) { | ||||
| 143 | push @coercions, | ||||
| 144 | [ $pair->[0]->_compiled_type_constraint, $pair->[1] ]; | ||||
| 145 | } | ||||
| 146 | |||||
| 147 | $coercion = sub { | ||||
| 148 | my($thing) = @_; | ||||
| 149 | foreach my $pair (@coercions) { | ||||
| 150 | #my ($constraint, $converter) = @$pair; | ||||
| 151 | if ($pair->[0]->($thing)) { | ||||
| 152 | local $_ = $thing; | ||||
| 153 | return $pair->[1]->($thing); | ||||
| 154 | } | ||||
| 155 | } | ||||
| 156 | return $thing; | ||||
| 157 | }; | ||||
| 158 | } | ||||
| 159 | else { # for union type | ||||
| 160 | my @coercions; | ||||
| 161 | foreach my $type(@{$self->{type_constraints}}){ | ||||
| 162 | if($type->has_coercion){ | ||||
| 163 | push @coercions, $type; | ||||
| 164 | } | ||||
| 165 | } | ||||
| 166 | if(@coercions){ | ||||
| 167 | $coercion = sub { | ||||
| 168 | my($thing) = @_; | ||||
| 169 | foreach my $type(@coercions){ | ||||
| 170 | my $value = $type->coerce($thing); | ||||
| 171 | return $value if $self->check($value); | ||||
| 172 | } | ||||
| 173 | return $thing; | ||||
| 174 | }; | ||||
| 175 | } | ||||
| 176 | } | ||||
| 177 | |||||
| 178 | return( $self->{_compiled_type_coercion} = $coercion ); | ||||
| 179 | } | ||||
| 180 | |||||
| 181 | sub coerce { | ||||
| 182 | my $self = shift; | ||||
| 183 | return $_[0] if $self->check(@_); | ||||
| 184 | |||||
| 185 | my $coercion = $self->_compiled_type_coercion | ||||
| 186 | or $self->throw_error("Cannot coerce without a type coercion"); | ||||
| 187 | return $coercion->(@_); | ||||
| 188 | } | ||||
| 189 | |||||
| 190 | sub get_message { | ||||
| 191 | my ($self, $value) = @_; | ||||
| 192 | if ( my $msg = $self->message ) { | ||||
| 193 | local $_ = $value; | ||||
| 194 | return $msg->($value); | ||||
| 195 | } | ||||
| 196 | else { | ||||
| 197 | if(not defined $value) { | ||||
| 198 | $value = 'undef'; | ||||
| 199 | } | ||||
| 200 | elsif( ref($value) && defined(&overload::StrVal) ) { | ||||
| 201 | $value = overload::StrVal($value); | ||||
| 202 | } | ||||
| 203 | return "Validation failed for '$self' with value $value"; | ||||
| 204 | } | ||||
| 205 | } | ||||
| 206 | |||||
| 207 | sub is_a_type_of { | ||||
| 208 | my($self, $other) = @_; | ||||
| 209 | |||||
| 210 | # ->is_a_type_of('__ANON__') is always false | ||||
| 211 | return 0 if !ref($other) && $other eq '__ANON__'; | ||||
| 212 | |||||
| 213 | (my $other_name = $other) =~ s/\s+//g; | ||||
| 214 | |||||
| 215 | return 1 if $self->name eq $other_name; | ||||
| 216 | |||||
| 217 | if(exists $self->{type_constraints}){ # union | ||||
| 218 | foreach my $type(@{$self->{type_constraints}}) { | ||||
| 219 | return 1 if $type->name eq $other_name; | ||||
| 220 | } | ||||
| 221 | } | ||||
| 222 | |||||
| 223 | for(my $p = $self->parent; defined $p; $p = $p->parent) { | ||||
| 224 | return 1 if $p->name eq $other_name; | ||||
| 225 | } | ||||
| 226 | |||||
| 227 | return 0; | ||||
| 228 | } | ||||
| 229 | |||||
| 230 | # See also Moose::Meta::TypeConstraint::Parameterizable | ||||
| 231 | sub parameterize { | ||||
| 232 | my($self, $param, $name) = @_; | ||||
| 233 | |||||
| 234 | if(!ref $param){ | ||||
| 235 | require Mouse::Util::TypeConstraints; | ||||
| 236 | $param = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($param); | ||||
| 237 | } | ||||
| 238 | |||||
| 239 | $name ||= sprintf '%s[%s]', $self->name, $param->name; | ||||
| 240 | return Mouse::Meta::TypeConstraint->new( | ||||
| 241 | name => $name, | ||||
| 242 | parent => $self, | ||||
| 243 | type_parameter => $param, | ||||
| 244 | ); | ||||
| 245 | } | ||||
| 246 | |||||
| 247 | sub assert_valid { | ||||
| 248 | my ($self, $value) = @_; | ||||
| 249 | |||||
| 250 | if(!$self->check($value)){ | ||||
| 251 | $self->throw_error($self->get_message($value)); | ||||
| 252 | } | ||||
| 253 | return 1; | ||||
| 254 | } | ||||
| 255 | |||||
| 256 | # overloading stuff | ||||
| 257 | |||||
| 258 | sub _as_string { $_[0]->name } # overload "" | ||||
| 259 | sub _identity; # overload 0+ | ||||
| 260 | |||||
| 261 | sub _unite { # overload infix:<|> | ||||
| 262 | my($lhs, $rhs) = @_; | ||||
| 263 | require Mouse::Util::TypeConstraints; | ||||
| 264 | return Mouse::Util::TypeConstraints::_find_or_create_union_type( | ||||
| 265 | $lhs, | ||||
| 266 | Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($rhs), | ||||
| 267 | ); | ||||
| 268 | } | ||||
| 269 | |||||
| 270 | 1 | 3µs | 1; | ||
| 271 | __END__ | ||||
# spent 18µs within Mouse::Meta::TypeConstraint::_compiled_type_constraint which was called 19 times, avg 953ns/call:
# 14 times (12µs+0s) by Mouse::Object::new at line 13 of mongo_pain.pl, avg 864ns/call
# 2 times (3µs+0s) by Mouse::Object::new at line 531 of MongoDB/Connection.pm, avg 1µs/call
# 2 times (2µs+0s) by Mouse::Object::new at line 108 of MongoDB/Database.pm, avg 1µs/call
# once (1µs+0s) by MongoDB::Collection::full_name at line 300 of MongoDB/Collection.pm | |||||
# spent 5µs within Mouse::Meta::TypeConstraint::_identity which was called 2 times, avg 2µs/call:
# 2 times (5µs+0s) by Mouse::init_meta at line 143 of Mouse.pm, avg 2µs/call | |||||
# spent 21µs within Mouse::Meta::TypeConstraint::compile_type_constraint which was called 3 times, avg 7µs/call:
# 3 times (21µs+0s) by Mouse::Meta::TypeConstraint::new at line 67, avg 7µs/call |