1 package Mouse::Meta::TypeConstraint;
2 use Mouse::Util qw(:meta); # enables strict and warnings
7 my %args = @_ == 1 ? %{$_[0]} : @_;
9 $args{name} = '__ANON__' if !defined $args{name};
11 my $check = delete $args{optimized};
14 $args{hand_optimized_type_constraint} = $check;
15 $args{compiled_type_constraint} = $check;
18 $check = $args{constraint};
20 if(defined($check) && ref($check) ne 'CODE'){
21 $class->throw_error("Constraint for $args{name} is not a CODE reference");
24 my $self = bless \%args, $class;
25 $self->compile_type_constraint() if !$self->{hand_optimized_type_constraint};
27 $self->_compile_union_type_coercion() if $self->{type_constraints};
31 sub create_child_type{
33 return ref($self)->new(
34 # a child inherits its parent's attributes
37 # but does not inherit 'compiled_type_constraint' and 'hand_optimized_type_constraint'
38 compiled_type_constraint => undef,
39 hand_optimized_type_constraint => undef,
41 # and is given child-specific args, of course.
57 sub __is_parameterized;
59 sub _compiled_type_constraint;
60 sub _compiled_type_coercion;
62 sub compile_type_constraint;
65 sub _add_type_coercions{
68 my $coercions = ($self->{coercion_map} ||= []);
69 my %has = map{ $_->[0] => undef } @{$coercions};
71 for(my $i = 0; $i < @_; $i++){
73 my $action = $_[++$i];
75 if(exists $has{$from}){
76 $self->throw_error("A coercion action already exists for '$from'");
79 my $type = Mouse::Util::TypeConstraints::find_or_parse_type_constraint($from)
80 or $self->throw_error("Could not find the type constraint ($from) to coerce from");
82 push @{$coercions}, [ $type => $action ];
86 if(exists $self->{type_constraints}){ # union type
87 $self->throw_error("Cannot add additional type coercions to Union types");
90 $self->_compile_type_coercion();
95 sub _compile_type_coercion {
98 my @coercions = @{$self->{coercion_map}};
100 $self->{_compiled_type_coercion} = sub {
102 foreach my $pair (@coercions) {
103 #my ($constraint, $converter) = @$pair;
104 if ($pair->[0]->check($thing)) {
106 return $pair->[1]->($thing);
114 sub _compile_union_type_coercion {
118 foreach my $type(@{$self->{type_constraints}}){
119 if($type->has_coercion){
120 push @coercions, $type;
124 $self->{_compiled_type_coercion} = sub {
126 foreach my $type(@coercions){
127 my $value = $type->coerce($thing);
128 return $value if $self->check($value);
139 my $coercion = $self->_compiled_type_coercion;
141 $self->throw_error("Cannot coerce without a type coercion");
144 return $_[0] if $self->check(@_);
146 return $coercion->(@_);
150 my ($self, $value) = @_;
151 if ( my $msg = $self->message ) {
153 return $msg->($value);
156 if(not defined $value) {
159 elsif( ref($value) && defined(&overload::StrVal) ) {
160 $value = overload::StrVal($value);
162 return "Validation failed for '$self' with value $value";
167 my($self, $other) = @_;
169 # ->is_a_type_of('__ANON__') is always false
170 return 0 if !ref($other) && $other eq '__ANON__';
172 (my $other_name = $other) =~ s/\s+//g;
174 return 1 if $self->name eq $other_name;
176 if(exists $self->{type_constraints}){ # union
177 foreach my $type(@{$self->{type_constraints}}){
178 return 1 if $type->name eq $other_name;
182 for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){
183 return 1 if $parent->name eq $other_name;
189 # See also Moose::Meta::TypeConstraint::Parameterizable
191 my($self, $param, $name) = @_;
194 require Mouse::Util::TypeConstraints;
195 $param = Mouse::Util::TypeConstraints::find_or_create_isa_type_constraint($param);
198 $name ||= sprintf '%s[%s]', $self->name, $param->name;
200 my $generator = $self->{constraint_generator}
201 || $self->throw_error("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type");
203 return Mouse::Meta::TypeConstraint->new(
206 type_parameter => $param,
207 constraint => $generator->($param), # must be 'constraint', not 'optimized'
212 my ($self, $value) = @_;
214 if(!$self->check($value)){
215 $self->throw_error($self->get_message($value));
220 sub _as_string { $_[0]->name } # overload ""
221 sub _identity { Scalar::Util::refaddr($_[0]) } # overload 0+
223 sub _unite { # overload infix:<|>
225 require Mouse::Util::TypeConstraints;
226 return Mouse::Util::TypeConstraints::find_or_parse_type_constraint(
232 require Mouse::Meta::Module;
233 goto &Mouse::Meta::Module::throw_error;
241 Mouse::Meta::TypeConstraint - The Mouse Type Constraint metaclass
245 This document describes Mouse version 0.70
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>