From: gfx Date: Sat, 31 Oct 2009 07:56:08 +0000 (+0900) Subject: Implement type parameterization in XS X-Git-Tag: 0.40_04~11 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=619338ac4245c7c523d67645d6cd51cb982d4841;p=gitmo%2FMouse.git Implement type parameterization in XS --- diff --git a/lib/Mouse/PurePerl.pm b/lib/Mouse/PurePerl.pm index b2c4b67..32616b0 100644 --- a/lib/Mouse/PurePerl.pm +++ b/lib/Mouse/PurePerl.pm @@ -124,6 +124,41 @@ sub Object { blessed($_[0]) && blessed($_[0]) ne 'Regexp' } sub ClassName { Mouse::Util::is_class_loaded($_[0]) } sub RoleName { (Mouse::Util::class_of($_[0]) || return 0)->isa('Mouse::Meta::Role') } +sub _parameterize_ArrayRef_for { + my($type_parameter) = @_; + my $check = $type_parameter->_compiled_type_constraint; + + return sub { + foreach my $value (@{$_}) { + return undef unless $check->($value); + } + return 1; + } +} + +sub _parameterize_HashRef_for { + my($type_parameter) = @_; + my $check = $type_parameter->_compiled_type_constraint; + + return sub { + foreach my $value(values %{$_}){ + return undef unless $check->($value); + } + return 1; + }; +} + +# 'Maybe' type accepts 'Any', so it requires parameters +sub _parameterize_Maybe_for { + my($type_parameter) = @_; + my $check = $type_parameter->_compiled_type_constraint; + + return sub{ + return !defined($_) || $check->($_); + }; +}; + + package Mouse::Meta::Module; diff --git a/lib/Mouse/Util/TypeConstraints.pm b/lib/Mouse/Util/TypeConstraints.pm index be2ddaf..9658ca5 100644 --- a/lib/Mouse/Util/TypeConstraints.pm +++ b/lib/Mouse/Util/TypeConstraints.pm @@ -217,38 +217,9 @@ sub _find_or_create_regular_type{ } } -$TYPE{ArrayRef}{constraint_generator} = sub { - my($type_parameter) = @_; - my $check = $type_parameter->_compiled_type_constraint; - - return sub{ - foreach my $value (@{$_}) { - return undef unless $check->($value); - } - return 1; - } -}; -$TYPE{HashRef}{constraint_generator} = sub { - my($type_parameter) = @_; - my $check = $type_parameter->_compiled_type_constraint; - - return sub{ - foreach my $value(values %{$_}){ - return undef unless $check->($value); - } - return 1; - }; -}; - -# 'Maybe' type accepts 'Any', so it requires parameters -$TYPE{Maybe}{constraint_generator} = sub { - my($type_parameter) = @_; - my $check = $type_parameter->_compiled_type_constraint; - - return sub{ - return !defined($_) || $check->($_); - }; -}; +$TYPE{ArrayRef}{constraint_generator} = \&_parameterize_ArrayRef_for; +$TYPE{HashRef}{constraint_generator} = \&_parameterize_HashRef_for; +$TYPE{Maybe}{constraint_generator} = \&_parameterize_Maybe_for; sub _find_or_create_parameterized_type{ my($base, $param) = @_; diff --git a/mouse.h b/mouse.h index 8d25738..daf740f 100644 --- a/mouse.h +++ b/mouse.h @@ -126,7 +126,8 @@ XS(mouse_xs_reader); XS(mouse_xs_writer); typedef enum mouse_tc{ - MOUSE_TC_ANY = 1, + MOUSE_TC_MAYBE, + MOUSE_TC_ANY, MOUSE_TC_ITEM, MOUSE_TC_UNDEF, MOUSE_TC_DEFINED, diff --git a/xs-src/MouseTypeConstraints.xs b/xs-src/MouseTypeConstraints.xs index 6c84858..6f0fe6c 100644 --- a/xs-src/MouseTypeConstraints.xs +++ b/xs-src/MouseTypeConstraints.xs @@ -280,6 +280,53 @@ mouse_tc_Object(pTHX_ SV* const sv) { return SvROK(sv) && SvOBJECT(SvRV(sv)) && !SvRXOK(sv); } +/* Parameterized type constraints */ + +int +mouse_parameterized_ArrayRef(pTHX_ SV* const param, SV* const sv) { + if(mouse_tc_ArrayRef(aTHX_ sv)){ + AV* const av = (AV*)SvRV(sv); + I32 const len = av_len(av) + 1; + I32 i; + for(i = 0; i < len; i++){ + SV* const value = *av_fetch(av, i, TRUE); + SvGETMAGIC(value); + if(!mouse_tc_check(aTHX_ param, value)){ + return FALSE; + } + } + return TRUE; + } + return FALSE; +} + +int +mouse_parameterized_HashRef(pTHX_ SV* const param, SV* const sv) { + if(mouse_tc_HashRef(aTHX_ sv)){ + HV* const hv = (HV*)SvRV(sv); + HE* he; + + hv_iterinit(hv); + while((he = hv_iternext(hv))){ + SV* const value = hv_iterval(hv, he); + SvGETMAGIC(value); + if(!mouse_tc_check(aTHX_ param, value)){ + return FALSE; + } + } + return TRUE; + } + return FALSE; +} + +int +mouse_parameterized_Maybe(pTHX_ SV* const param, SV* const sv) { + if(SvOK(sv)){ + return mouse_tc_check(aTHX_ param, sv); + } + return TRUE; +} + /* * This class_type generator is taken from Scalar::Util::Instance */ @@ -380,10 +427,11 @@ mouse_is_an_instance_of_universal(pTHX_ SV* const data, SV* const sv){ static MGVTBL mouse_util_type_constraints_vtbl; /* not used, only for identity */ -CV* +static CV* mouse_tc_parameterize(pTHX_ const char* const name, check_fptr_t const fptr, SV* const param) { - CV* const xsub = newXS(name, XS_Mouse_parameterized_check, __FILE__); + CV* xsub; + xsub = newXS(name, XS_Mouse_parameterized_check, __FILE__); CvXSUBANY(xsub).any_ptr = sv_magicext( (SV*)xsub, param, /* mg_obj: refcnt will be increased */ @@ -495,3 +543,32 @@ CODE: XSRETURN(1); +CV* +_parameterize_ArrayRef_for(SV* param) +ALIAS: + _parameterize_ArrayRef_for = MOUSE_TC_ARRAY_REF + _parameterize_HashRef_for = MOUSE_TC_HASH_REF + _parameterize_Maybe_for = MOUSE_TC_MAYBE +CODE: +{ + check_fptr_t fptr; + SV* const tc_code = mcall0s(param, "_compiled_type_constraint"); + if(!(SvROK(tc_code) && SvTYPE(SvRV(tc_code)) == SVt_PVCV)){ + croak("_compiled_type_constraint didn't return a CODE reference"); + } + + switch(ix){ + case MOUSE_TC_ARRAY_REF: + fptr = mouse_parameterized_ArrayRef; + break; + case MOUSE_TC_HASH_REF: + fptr = mouse_parameterized_HashRef; + break; + default: /* Maybe type */ + fptr = mouse_parameterized_Maybe; + } + RETVAL = mouse_tc_parameterize(aTHX_ NULL, fptr, tc_code); +} +OUTPUT: + RETVAL +