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.
72 sub __is_parameterized;
74 sub _compiled_type_constraint;
75 sub _compiled_type_coercion;
77 sub compile_type_constraint;
79 sub _add_type_coercions{
82 my $coercions = ($self->{_coercion_map} ||= []);
83 my %has = map{ $_->[0] => undef } @{$coercions};
85 for(my $i = 0; $i < @_; $i++){
87 my $action = $_[++$i];
89 if(exists $has{$from}){
90 Carp::confess("A coercion action already exists for '$from'");
93 my $type = Mouse::Util::TypeConstraints::find_or_parse_type_constraint($from)
94 or Carp::confess("Could not find the type constraint ($from) to coerce from");
96 push @{$coercions}, [ $type => $action ];
100 if(exists $self->{type_constraints}){ # union type
101 Carp::confess("Cannot add additional type coercions to Union types");
104 $self->_compile_type_coercion();
109 sub _compile_type_coercion {
112 my @coercions = @{$self->{_coercion_map}};
114 $self->{_compiled_type_coercion} = sub {
116 foreach my $pair (@coercions) {
117 #my ($constraint, $converter) = @$pair;
118 if ($pair->[0]->check($thing)) {
120 return $pair->[1]->($thing);
128 sub _compile_union_type_coercion {
132 foreach my $type(@{$self->{type_constraints}}){
133 if($type->has_coercion){
134 push @coercions, $type;
138 $self->{_compiled_type_coercion} = sub {
140 foreach my $type(@coercions){
141 my $value = $type->coerce($thing);
142 return $value if $self->check($value);
152 return $self->_compiled_type_constraint->(@_);
158 my $coercion = $self->_compiled_type_coercion;
160 Carp::confess("Cannot coerce without a type coercion");
163 return $_[0] if $self->_compiled_type_constraint->(@_);
165 return $coercion->(@_);
169 my ($self, $value) = @_;
170 if ( my $msg = $self->message ) {
172 return $msg->($value);
175 $value = ( defined $value ? overload::StrVal($value) : 'undef' );
176 return "Validation failed for '$self' failed with value $value";
181 my($self, $other) = @_;
183 # ->is_a_type_of('__ANON__') is always false
184 return 0 if !ref($other) && $other eq '__ANON__';
186 (my $other_name = $other) =~ s/\s+//g;
188 return 1 if $self->name eq $other_name;
190 if(exists $self->{type_constraints}){ # union
191 foreach my $type(@{$self->{type_constraints}}){
192 return 1 if $type->name eq $other_name;
196 for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){
197 return 1 if $parent->name eq $other_name;
203 # See also Moose::Meta::TypeConstraint::Parameterizable
205 my($self, $param, $name) = @_;
208 require Mouse::Util::TypeConstraints;
209 $param = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($param);
212 $name ||= sprintf '%s[%s]', $self->name, $param->name;
214 my $generator = $self->{constraint_generator}
215 || Carp::confess("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type");
217 return Mouse::Meta::TypeConstraint->new(
220 type_parameter => $param,
221 constraint => $generator->($param), # must be 'constraint', not 'optimized'
223 type => 'Parameterized',
228 my ($self, $value) = @_;
230 if(!$self->_compiled_type_constraint->($value)){
231 Carp::confess($self->get_message($value));
241 Mouse::Meta::TypeConstraint - The Mouse Type Constraint metaclass
245 This document describes Mouse version 0.50_01
249 For the most part, the only time you will ever encounter an
250 instance of this class is if you are doing some serious deep
251 introspection. This API should not be considered final, but
252 it is B<highly unlikely> that this will matter to a regular
269 L<Moose::Meta::TypeConstraint>