1 package Mouse::Meta::TypeConstraint;
2 use Mouse::Util qw(:meta); # enables strict and warnings
5 'bool' => sub { 1 }, # always true
7 '""' => sub { $_[0]->name }, # stringify to tc name
9 '|' => sub { # or-combination
10 require Mouse::Util::TypeConstraints;
11 return Mouse::Util::TypeConstraints::find_or_parse_type_constraint(
21 my($class, %args) = @_;
23 $args{name} = '__ANON__' if !defined $args{name};
25 my $check = delete $args{optimized};
28 $args{hand_optimized_type_constraint} = $check;
29 $args{compiled_type_constraint} = $check;
32 $check = $args{constraint};
34 if(defined($check) && ref($check) ne 'CODE'){
35 Carp::confess("Constraint for $args{name} is not a CODE reference");
38 $args{package_defined_in} ||= caller;
40 my $self = bless \%args, $class;
41 $self->compile_type_constraint() if !$self->{hand_optimized_type_constraint};
43 $self->_compile_union_type_coercion() if $self->{type_constraints};
47 sub create_child_type{
50 return ref($self)->new(
51 # a child inherits its parent's attributes
54 # but does not inherit 'compiled_type_constraint' and 'hand_optimized_type_constraint'
55 compiled_type_constraint => undef,
56 hand_optimized_type_constraint => undef,
58 # and is given child-specific args, of course.
70 sub _compiled_type_constraint;
71 sub _compiled_type_coercion;
73 sub compile_type_constraint;
75 sub _add_type_coercions{
78 my $coercions = ($self->{_coercion_map} ||= []);
79 my %has = map{ $_->[0] => undef } @{$coercions};
81 for(my $i = 0; $i < @_; $i++){
83 my $action = $_[++$i];
85 if(exists $has{$from}){
86 Carp::confess("A coercion action already exists for '$from'");
89 my $type = Mouse::Util::TypeConstraints::find_or_parse_type_constraint($from)
90 or Carp::confess("Could not find the type constraint ($from) to coerce from");
92 push @{$coercions}, [ $type => $action ];
96 if(exists $self->{type_constraints}){ # union type
97 Carp::confess("Cannot add additional type coercions to Union types");
100 $self->_compile_type_coercion();
105 sub _compile_type_coercion {
108 my @coercions = @{$self->{_coercion_map}};
110 $self->{_compiled_type_coercion} = sub {
112 foreach my $pair (@coercions) {
113 #my ($constraint, $converter) = @$pair;
114 if ($pair->[0]->check($thing)) {
116 return $pair->[1]->($thing);
124 sub _compile_union_type_coercion {
128 foreach my $type(@{$self->{type_constraints}}){
129 if($type->has_coercion){
130 push @coercions, $type;
134 $self->{_compiled_type_coercion} = sub {
136 foreach my $type(@coercions){
137 my $value = $type->coerce($thing);
138 return $value if $self->check($value);
148 return $self->_compiled_type_constraint->(@_);
154 my $coercion = $self->_compiled_type_coercion;
156 Carp::confess("Cannot coerce without a type coercion");
159 return $_[0] if $self->_compiled_type_constraint->(@_);
161 return $coercion->(@_);
165 my ($self, $value) = @_;
166 if ( my $msg = $self->message ) {
168 return $msg->($value);
171 $value = ( defined $value ? overload::StrVal($value) : 'undef' );
172 return "Validation failed for '$self' failed with value $value";
177 my($self, $other) = @_;
179 # ->is_a_type_of('__ANON__') is always false
180 return 0 if !ref($other) && $other eq '__ANON__';
182 (my $other_name = $other) =~ s/\s+//g;
184 return 1 if $self->name eq $other_name;
186 if(exists $self->{type_constraints}){ # union
187 foreach my $type(@{$self->{type_constraints}}){
188 return 1 if $type->name eq $other_name;
192 for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){
193 return 1 if $parent->name eq $other_name;
199 # See also Moose::Meta::TypeConstraint::Parameterizable
201 my($self, $param, $name) = @_;
204 require Mouse::Util::TypeConstraints;
205 $param = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($param);
208 $name ||= sprintf '%s[%s]', $self->name, $param->name;
210 my $generator = $self->{constraint_generator}
211 || Carp::confess("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type");
213 return Mouse::Meta::TypeConstraint->new(
217 constraint => $generator->($param), # must be 'constraint', not 'optimized'
219 type => 'Parameterized',
228 Mouse::Meta::TypeConstraint - The Mouse Type Constraint metaclass
232 This document describes Mouse version 0.50_01
236 For the most part, the only time you will ever encounter an
237 instance of this class is if you are doing some serious deep
238 introspection. This API should not be considered final, but
239 it is B<highly unlikely> that this will matter to a regular
256 L<Moose::Meta::TypeConstraint>