use Carp ();
-my $null_check = sub { 1 };
-
sub new {
my($class, %args) = @_;
);
}
-
-sub compile_type_constraint{
- my($self) = @_;
-
- # add parents first
- my @checks;
- for(my $parent = $self->{parent}; defined $parent; $parent = $parent->{parent}){
- if($parent->{hand_optimized_type_constraint}){
- unshift @checks, $parent->{hand_optimized_type_constraint};
- last; # a hand optimized constraint must include all the parents
- }
- elsif($parent->{constraint}){
- unshift @checks, $parent->{constraint};
- }
- }
-
- # then add child
- if($self->{constraint}){
- push @checks, $self->{constraint};
- }
-
- if($self->{type_constraints}){ # Union
- my @types = map{ $_->{compiled_type_constraint} } @{ $self->{type_constraints} };
- push @checks, sub{
- foreach my $c(@types){
- return 1 if $c->($_[0]);
- }
- return 0;
- };
- }
-
- if(@checks == 0){
- $self->{compiled_type_constraint} = $null_check;
- }
- else{
- $self->{compiled_type_constraint} = sub{
- my(@args) = @_;
- local $_ = $args[0];
- foreach my $c(@checks){
- return undef if !$c->(@args);
- }
- return 1;
- };
- }
- return;
-}
-
sub _add_type_coercions{
my $self = shift;
sub has_coercion{ exists $_[0]->{_compiled_type_coercion} }
+
+sub compile_type_constraint{
+ my($self) = @_;
+
+ # add parents first
+ my @checks;
+ for(my $parent = $self->{parent}; defined $parent; $parent = $parent->{parent}){
+ if($parent->{hand_optimized_type_constraint}){
+ unshift @checks, $parent->{hand_optimized_type_constraint};
+ last; # a hand optimized constraint must include all the parents
+ }
+ elsif($parent->{constraint}){
+ unshift @checks, $parent->{constraint};
+ }
+ }
+
+ # then add child
+ if($self->{constraint}){
+ push @checks, $self->{constraint};
+ }
+
+ if($self->{type_constraints}){ # Union
+ my @types = map{ $_->{compiled_type_constraint} } @{ $self->{type_constraints} };
+ push @checks, sub{
+ foreach my $c(@types){
+ return 1 if $c->($_[0]);
+ }
+ return 0;
+ };
+ }
+
+ if(@checks == 0){
+ $self->{compiled_type_constraint} = \&Mouse::Util::TypeConstraints::Any;
+ }
+ else{
+ $self->{compiled_type_constraint} = sub{
+ my(@args) = @_;
+ local $_ = $args[0];
+ foreach my $c(@checks){
+ return undef if !$c->(@args);
+ }
+ return 1;
+ };
+ }
+ return;
+}
+
+
+
1;
__END__
SV* mouse_instance_delete_slot(pTHX_ SV* const instance, SV* const slot);
void mouse_instance_weaken_slot(pTHX_ SV* const instance, SV* const slot);
+#define has_slot(self, key) mouse_instance_has_slot(aTHX_ self, key)
+#define get_slot(self, key) mouse_instance_get_slot(aTHX_ self, key)
+#define set_slot(self, key, value) mouse_instance_set_slot(aTHX_ self, key, value)
+
+#define has_slots(self, key) mouse_instance_has_slot(aTHX_ self, sv_2mortal(newSVpvs_share(key)))
+#define get_slots(self, key) mouse_instance_get_slot(aTHX_ self, sv_2mortal(newSVpvs_share(key)))
+#define set_slots(self, key, value) mouse_instance_set_slot(aTHX_ self, sv_2mortal(newSVpvs_share(key)), value)
/* mouse_simle_accessor.xs */
#define INSTALL_SIMPLE_READER(klass, name) INSTALL_SIMPLE_READER_WITH_KEY(klass, name, name)
switch(tc){
case MOUSE_TC_ANY: return mouse_tc_Any(aTHX_ sv);
case MOUSE_TC_ITEM: return mouse_tc_Any(aTHX_ sv);
+ case MOUSE_TC_MAYBE: return mouse_tc_Any(aTHX_ sv);
case MOUSE_TC_UNDEF: return mouse_tc_Undef(aTHX_ sv);
case MOUSE_TC_DEFINED: return mouse_tc_Defined(aTHX_ sv);
case MOUSE_TC_BOOL: return mouse_tc_Bool(aTHX_ sv);
/* Parameterized type constraints */
-int
+static int
mouse_parameterized_ArrayRef(pTHX_ SV* const param, SV* const sv) {
if(mouse_tc_ArrayRef(aTHX_ sv)){
AV* const av = (AV*)SvRV(sv);
return FALSE;
}
-int
+static int
mouse_parameterized_HashRef(pTHX_ SV* const param, SV* const sv) {
if(mouse_tc_HashRef(aTHX_ sv)){
HV* const hv = (HV*)SvRV(sv);
return FALSE;
}
-int
+static int
mouse_parameterized_Maybe(pTHX_ SV* const param, SV* const sv) {
if(SvOK(sv)){
return mouse_tc_check(aTHX_ param, sv);
return TRUE;
}
+static int
+mouse_types_union_check(pTHX_ AV* const types, SV* const sv) {
+ I32 const len = AvFILLp(types) + 1;
+ I32 i;
+
+ for(i = 0; i < len; i++){
+ if(mouse_tc_check(aTHX_ AvARRAY(types)[i], sv)){
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static int
+mouse_types_check(pTHX_ AV* const types, SV* const sv) {
+ I32 const len = AvFILLp(types) + 1;
+ I32 i;
+
+ ENTER;
+ SAVE_DEFSV;
+ DEFSV_set(sv);
+
+ for(i = 0; i < len; i++){
+ if(!mouse_tc_check(aTHX_ AvARRAY(types)[i], sv)){
+ LEAVE;
+ return FALSE;
+ }
+ }
+
+ LEAVE;
+
+ return TRUE;
+}
+
/*
* This class_type generator is taken from Scalar::Util::Instance
*/
OUTPUT:
RETVAL
+MODULE = Mouse::Util::TypeConstraints PACKAGE = Mouse::Meta::TypeConstraint
+
+void
+compile_type_constraint(SV* self)
+CODE:
+{
+ AV* const checks = newAV();
+ SV* check; /* check function */
+ SV* parent;
+ SV* types_ref;
+
+ sv_2mortal((SV*)checks);
+
+ for(parent = get_slots(self, "parent"); parent; parent = get_slots(parent, "parent")){
+ check = get_slots(parent, "hand_optimized_type_constraint");
+ if(check && SvOK(check)){
+ if(!mouse_tc_CodeRef(aTHX_ check)){
+ croak("Not a CODE reference");
+ }
+ av_unshift(checks, 1);
+ av_store(checks, 0, newSVsv(check));
+ break; /* a hand optimized constraint must include all the parent */
+ }
+
+ check = get_slots(parent, "constraint");
+ if(check && SvOK(check)){
+ if(!mouse_tc_CodeRef(aTHX_ check)){
+ croak("Not a CODE reference");
+ }
+ av_unshift(checks, 1);
+ av_store(checks, 0, newSVsv(check));
+ }
+ }
+
+ check = get_slots(self, "constraint");
+ if(check && SvOK(check)){
+ if(!mouse_tc_CodeRef(aTHX_ check)){
+ croak("Not a CODE reference");
+ }
+ av_push(checks, newSVsv(check));
+ }
+
+ types_ref = get_slots(self, "type_constraints");
+ if(types_ref && SvOK(types_ref)){ /* union type */
+ AV* types;
+ AV* union_checks;
+ CV* union_check;
+ I32 len;
+ I32 i;
+
+ if(!mouse_tc_ArrayRef(aTHX_ types_ref)){
+ croak("Not an ARRAY reference");
+ }
+ types = (AV*)SvRV(types_ref);
+ len = av_len(types) + 1;
+
+ union_checks = newAV();
+ sv_2mortal((SV*)union_checks);
+
+ for(i = 0; i < len; i++){
+ SV* const tc = *av_fetch(types, i, TRUE);
+ SV* const c = get_slots(tc, "compiled_type_constraint");
+ if(!(c && mouse_tc_CodeRef(aTHX_ c))){
+ sv_dump(self);
+ croak("'%"SVf"' has no compiled type constraint", self);
+ }
+ av_push(union_checks, newSVsv(c));
+ }
+
+ union_check = mouse_tc_parameterize(aTHX_ NULL, (check_fptr_t)mouse_types_union_check, (SV*)union_checks);
+ av_push(checks, newRV_inc((SV*)union_check));
+ }
+
+ if(AvFILLp(checks) < 0){
+ check = newRV_inc((SV*)get_cv("Mouse::Util::TypeConstraints::Any", TRUE));
+ }
+ else{
+ check = newRV_inc((SV*)mouse_tc_parameterize(aTHX_ NULL, (check_fptr_t)mouse_types_check, (SV*)checks));
+ }
+ set_slots(self, "compiled_type_constraint", check);
+}
+