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 my $self = bless \%args, $class;
39 $self->compile_type_constraint() if !$self->{hand_optimized_type_constraint};
41 $self->_compile_union_type_coercion() if $self->{type_constraints};
45 sub create_child_type{
48 return ref($self)->new(
49 # a child inherits its parent's attributes
52 # but does not inherit 'compiled_type_constraint' and 'hand_optimized_type_constraint'
53 compiled_type_constraint => undef,
54 hand_optimized_type_constraint => undef,
56 # and is given child-specific args, of course.
70 sub __is_parameterized;
72 sub _compiled_type_constraint;
73 sub _compiled_type_coercion;
75 sub compile_type_constraint;
77 sub _add_type_coercions{
80 my $coercions = ($self->{_coercion_map} ||= []);
81 my %has = map{ $_->[0] => undef } @{$coercions};
83 for(my $i = 0; $i < @_; $i++){
85 my $action = $_[++$i];
87 if(exists $has{$from}){
88 Carp::confess("A coercion action already exists for '$from'");
91 my $type = Mouse::Util::TypeConstraints::find_or_parse_type_constraint($from)
92 or Carp::confess("Could not find the type constraint ($from) to coerce from");
94 push @{$coercions}, [ $type => $action ];
98 if(exists $self->{type_constraints}){ # union type
99 Carp::confess("Cannot add additional type coercions to Union types");
102 $self->_compile_type_coercion();
107 sub _compile_type_coercion {
110 my @coercions = @{$self->{_coercion_map}};
112 $self->{_compiled_type_coercion} = sub {
114 foreach my $pair (@coercions) {
115 #my ($constraint, $converter) = @$pair;
116 if ($pair->[0]->check($thing)) {
118 return $pair->[1]->($thing);
126 sub _compile_union_type_coercion {
130 foreach my $type(@{$self->{type_constraints}}){
131 if($type->has_coercion){
132 push @coercions, $type;
136 $self->{_compiled_type_coercion} = sub {
138 foreach my $type(@coercions){
139 my $value = $type->coerce($thing);
140 return $value if $self->check($value);
150 return $self->_compiled_type_constraint->(@_);
156 my $coercion = $self->_compiled_type_coercion;
158 Carp::confess("Cannot coerce without a type coercion");
161 return $_[0] if $self->_compiled_type_constraint->(@_);
163 return $coercion->(@_);
167 my ($self, $value) = @_;
168 if ( my $msg = $self->message ) {
170 return $msg->($value);
173 $value = ( defined $value ? overload::StrVal($value) : 'undef' );
174 return "Validation failed for '$self' failed with value $value";
179 my($self, $other) = @_;
181 # ->is_a_type_of('__ANON__') is always false
182 return 0 if !ref($other) && $other eq '__ANON__';
184 (my $other_name = $other) =~ s/\s+//g;
186 return 1 if $self->name eq $other_name;
188 if(exists $self->{type_constraints}){ # union
189 foreach my $type(@{$self->{type_constraints}}){
190 return 1 if $type->name eq $other_name;
194 for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){
195 return 1 if $parent->name eq $other_name;
201 # See also Moose::Meta::TypeConstraint::Parameterizable
203 my($self, $param, $name) = @_;
206 require Mouse::Util::TypeConstraints;
207 $param = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($param);
210 $name ||= sprintf '%s[%s]', $self->name, $param->name;
212 my $generator = $self->{constraint_generator}
213 || Carp::confess("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type");
215 return Mouse::Meta::TypeConstraint->new(
218 type_parameter => $param,
219 constraint => $generator->($param), # must be 'constraint', not 'optimized'
221 type => 'Parameterized',
226 my ($self, $value) = @_;
228 if(!$self->_compiled_type_constraint->($value)){
229 Carp::confess($self->get_message($value));
239 Mouse::Meta::TypeConstraint - The Mouse Type Constraint metaclass
243 This document describes Mouse version 0.50_02
247 For the most part, the only time you will ever encounter an
248 instance of this class is if you are doing some serious deep
249 introspection. This API should not be considered final, but
250 it is B<highly unlikely> that this will matter to a regular
267 L<Moose::Meta::TypeConstraint>