Rewrite builtin type tests to test optimized, unoptimized, and inlined version of...
[gitmo/Moose.git] / lib / Moose / Util / TypeConstraints / Builtins.pm
CommitLineData
06d02aac 1package Moose::Util::TypeConstraints::Builtins;
2
3use strict;
4use warnings;
5
9882ca98 6use Scalar::Util qw( blessed looks_like_number reftype );
06d02aac 7
8sub type { goto &Moose::Util::TypeConstraints::type }
9sub subtype { goto &Moose::Util::TypeConstraints::subtype }
10sub as { goto &Moose::Util::TypeConstraints::as }
11sub where (&) { goto &Moose::Util::TypeConstraints::where }
12sub optimize_as (&) { goto &Moose::Util::TypeConstraints::optimize_as }
4e36cf24 13sub inline_as (&) { goto &Moose::Util::TypeConstraints::inline_as }
06d02aac 14
15sub define_builtins {
16 my $registry = shift;
17
4e36cf24 18 type 'Any' # meta-type including all
19 => where {1}
20 => inline_as { '1' };
06d02aac 21
4e36cf24 22 subtype 'Item' # base-type
94ab1609 23 => as 'Any'
24 => inline_as { '1' };
4e36cf24 25
26 subtype 'Undef'
27 => as 'Item'
28 => where { !defined($_) }
29 => inline_as { "! defined $_[0]" };
30
31 subtype 'Defined'
32 => as 'Item'
33 => where { defined($_) }
34 => inline_as { "defined $_[0]" };
06d02aac 35
36 subtype 'Bool'
37 => as 'Item'
4e36cf24 38 => where { !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' }
39 => inline_as { qq{!defined($_[0]) || $_[0] eq "" || "$_[0]" eq '1' || "$_[0]" eq '0'} };
06d02aac 40
41 subtype 'Value'
42 => as 'Defined'
43 => where { !ref($_) }
4e36cf24 44 => optimize_as( \&_Value )
45 => inline_as { "defined $_[0] && ! ref $_[0]" };
06d02aac 46
47 subtype 'Ref'
48 => as 'Defined'
49 => where { ref($_) }
4e36cf24 50 => optimize_as( \&_Ref )
51 => inline_as { "ref $_[0]" };
06d02aac 52
53 subtype 'Str'
54 => as 'Value'
55 => where { ref(\$_) eq 'SCALAR' }
4e36cf24 56 => optimize_as( \&_Str )
57 => inline_as {
58 return ( qq{defined $_[0]}
59 . qq{&& ( ref(\\ $_[0] ) eq 'SCALAR'}
60 . qq{ || ref(\\(my \$value = $_[0])) eq 'SCALAR')} );
61 };
06d02aac 62
63 subtype 'Num'
64 => as 'Str'
65 => where { Scalar::Util::looks_like_number($_) }
4e36cf24 66 => optimize_as( \&_Num )
67 => inline_as { "!ref $_[0] && Scalar::Util::looks_like_number($_[0])" };
06d02aac 68
69 subtype 'Int'
70 => as 'Num'
71 => where { "$_" =~ /^-?[0-9]+$/ }
4e36cf24 72 => optimize_as( \&_Int )
73 => inline_as {
74 return ( qq{defined $_[0]}
75 . qq{&& ! ref $_[0]}
76 . qq{&& ( my \$value = $_[0] ) =~ /\\A-?[0-9]+\\z/} );
77 };
06d02aac 78
79 subtype 'CodeRef'
80 => as 'Ref'
81 => where { ref($_) eq 'CODE' }
4e36cf24 82 => optimize_as( \&_CodeRef )
94ab1609 83 => inline_as { qq{ref $_[0] eq 'CODE'} };
06d02aac 84
85 subtype 'RegexpRef'
86 => as 'Ref'
9882ca98 87 => where( \&_RegexpRef )
4e36cf24 88 => optimize_as( \&_RegexpRef )
94ab1609 89 => inline_as { "Moose::Util::TypeConstraints::Builtins::_RegexpRef( $_[0] )" };
06d02aac 90
91 subtype 'GlobRef'
92 => as 'Ref'
93 => where { ref($_) eq 'GLOB' }
4e36cf24 94 => optimize_as( \&_GlobRef )
94ab1609 95 => inline_as { qq{ref $_[0] eq 'GLOB'} };
06d02aac 96
97 # NOTE: scalar filehandles are GLOB refs, but a GLOB ref is not always a
98 # filehandle
99 subtype 'FileHandle'
94ab1609 100 => as 'Ref'
06d02aac 101 => where {
102 Scalar::Util::openhandle($_) || ( blessed($_) && $_->isa("IO::Handle") );
103 }
4e36cf24 104 => optimize_as( \&_FileHandle )
105 => inline_as {
94ab1609 106 return ( qq{ref $_[0] eq 'GLOB'}
4e36cf24 107 . qq{&& Scalar::Util::openhandle( $_[0] )}
94ab1609 108 . qq{or Scalar::Util::blessed( $_[0] ) && $_[0]->isa("IO::Handle")} );
4e36cf24 109 };
06d02aac 110
111 subtype 'Object'
112 => as 'Ref'
113 => where { blessed($_) }
4e36cf24 114 => optimize_as( \&_Object )
115 => inline_as { "Scalar::Util::blessed( $_[0] )" };
06d02aac 116
117 # This type is deprecated.
118 subtype 'Role'
119 => as 'Object'
120 => where { $_->can('does') }
4e36cf24 121 => optimize_as( \&_Role );
06d02aac 122
123 subtype 'ClassName'
124 => as 'Str'
125 => where { Class::MOP::is_class_loaded($_) }
4e36cf24 126 => optimize_as( \&_ClassName )
127 => inline_as { "Class::MOP::is_class_loaded( $_[0] )" };
06d02aac 128
129 subtype 'RoleName'
130 => as 'ClassName'
131 => where {
132 (Class::MOP::class_of($_) || return)->isa('Moose::Meta::Role');
133 }
4e36cf24 134 => optimize_as( \&_RoleName )
135 => inline_as {
136 return ( qq{Class::MOP::is_class_loaded( $_[0] )}
137 . qq{&& ( Class::MOP::class_of( $_[0] ) || return )}
138 . qq{ ->isa('Moose::Meta::Role')} );
139 };
06d02aac 140
141 $registry->add_type_constraint(
142 Moose::Meta::TypeConstraint::Parameterizable->new(
143 name => 'ScalarRef',
144 package_defined_in => __PACKAGE__,
145 parent =>
146 Moose::Util::TypeConstraints::find_type_constraint('Ref'),
147 constraint => sub { ref($_) eq 'SCALAR' || ref($_) eq 'REF' },
9882ca98 148 optimized => \&_ScalarRef,
06d02aac 149 constraint_generator => sub {
150 my $type_parameter = shift;
151 my $check = $type_parameter->_compiled_type_constraint;
152 return sub {
153 return $check->( ${$_} );
154 };
155 }
156 )
157 );
158
159 $registry->add_type_constraint(
160 Moose::Meta::TypeConstraint::Parameterizable->new(
161 name => 'ArrayRef',
162 package_defined_in => __PACKAGE__,
163 parent =>
164 Moose::Util::TypeConstraints::find_type_constraint('Ref'),
165 constraint => sub { ref($_) eq 'ARRAY' },
9882ca98 166 optimized => \&_ArrayRef,
06d02aac 167 constraint_generator => sub {
168 my $type_parameter = shift;
169 my $check = $type_parameter->_compiled_type_constraint;
170 return sub {
171 foreach my $x (@$_) {
172 ( $check->($x) ) || return;
173 }
174 1;
175 }
176 }
177 )
178 );
179
180 $registry->add_type_constraint(
181 Moose::Meta::TypeConstraint::Parameterizable->new(
182 name => 'HashRef',
183 package_defined_in => __PACKAGE__,
184 parent =>
185 Moose::Util::TypeConstraints::find_type_constraint('Ref'),
186 constraint => sub { ref($_) eq 'HASH' },
9882ca98 187 optimized => \&_HashRef,
06d02aac 188 constraint_generator => sub {
189 my $type_parameter = shift;
190 my $check = $type_parameter->_compiled_type_constraint;
191 return sub {
192 foreach my $x ( values %$_ ) {
193 ( $check->($x) ) || return;
194 }
195 1;
196 }
197 }
198 )
199 );
200
201 $registry->add_type_constraint(
202 Moose::Meta::TypeConstraint::Parameterizable->new(
203 name => 'Maybe',
204 package_defined_in => __PACKAGE__,
205 parent =>
206 Moose::Util::TypeConstraints::find_type_constraint('Item'),
207 constraint => sub {1},
208 constraint_generator => sub {
209 my $type_parameter = shift;
210 my $check = $type_parameter->_compiled_type_constraint;
211 return sub {
212 return 1 if not( defined($_) ) || $check->($_);
213 return;
214 }
215 }
216 )
217 );
218}
219
9882ca98 220sub _Value { defined($_[0]) && !ref($_[0]) }
221
222sub _Ref { ref($_[0]) }
223
224# We might need to use a temporary here to flatten LVALUEs, for instance as in
225# Str(substr($_,0,255)).
226sub _Str {
227 defined($_[0])
228 && ( ref(\ $_[0] ) eq 'SCALAR'
229 || ref(\(my $value = $_[0])) eq 'SCALAR')
230}
231
232sub _Num { !ref($_[0]) && looks_like_number($_[0]) }
233
234# using a temporary here because regex matching promotes an IV to a PV,
235# and that confuses some things (like JSON.pm)
236sub _Int {
237 my $value = $_[0];
238 defined($value) && !ref($value) && $value =~ /\A-?[0-9]+\z/
239}
240
241sub _ScalarRef { ref($_[0]) eq 'SCALAR' || ref($_[0]) eq 'REF' }
242sub _ArrayRef { ref($_[0]) eq 'ARRAY' }
243sub _HashRef { ref($_[0]) eq 'HASH' }
244sub _CodeRef { ref($_[0]) eq 'CODE' }
245sub _GlobRef { ref($_[0]) eq 'GLOB' }
246
247# RegexpRef is implemented in Moose.xs
248
249sub _FileHandle {
250 ref( $_[0] ) eq 'GLOB' && Scalar::Util::openhandle( $_[0] )
251 or blessed( $_[0] ) && $_[0]->isa("IO::Handle");
252}
253
254sub _Object { blessed($_[0]) }
255
256sub _Role {
257 Moose::Deprecated::deprecated(
258 feature => 'Role type',
259 message =>
260 'The Role type has been deprecated. Maybe you meant to create a RoleName type? This type be will be removed in Moose 2.0200.'
261 );
262 blessed( $_[0] ) && $_[0]->can('does');
263}
264
265sub _ClassName {
266 return Class::MOP::is_class_loaded( $_[0] );
267}
268
269sub _RoleName {
4e36cf24 270 _ClassName( $_[0] )
9882ca98 271 && ( Class::MOP::class_of( $_[0] ) || return )
272 ->isa('Moose::Meta::Role');
273}
274
06d02aac 2751;