X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=blobdiff_plain;f=xs-src%2FMouseTypeConstraints.xs;h=6f0fe6cb3736ebd1768e0e0b61564c902f2a5a68;hp=81d0811252284dfad0988b938d3fb5ad64336fec;hb=619338ac4245c7c523d67645d6cd51cb982d4841;hpb=f6e3b8a91527e33b3952e77303231d1c6d1ad3e9 diff --git a/xs-src/MouseTypeConstraints.xs b/xs-src/MouseTypeConstraints.xs index 81d0811..6f0fe6c 100644 --- a/xs-src/MouseTypeConstraints.xs +++ b/xs-src/MouseTypeConstraints.xs @@ -18,10 +18,8 @@ typedef int (*check_fptr_t)(pTHX_ SV* const data, SV* const sv); int mouse_tc_check(pTHX_ SV* const tc_code, SV* const sv) { - CV* cv; - assert(SvROK(tc_code) && SvTYPE(SvRV(tc_code))); - - cv = (CV*)SvRV(tc_code); + CV* const cv = (CV*)SvRV(tc_code); + assert(SvTYPE(cv) == Svt_PVCV); if(CvISXSUB(cv)){ /* can be built-in tc */ if(CvXSUB(cv) == XS_Mouse__Util__TypeConstraints_Item){ @@ -33,7 +31,9 @@ mouse_tc_check(pTHX_ SV* const tc_code, SV* const sv) { MAGIC* const mg = (MAGIC*)CvXSUBANY(cv).any_ptr; assert(CvXSUBANY(cv).any_ptr != NULL); - return CALL_FPTR((check_fptr_t)mg->mg_ptr)(aTHX_ mg->mg_obj /* stash */, sv); + + /* call the check function directly, skipping call_sv() */ + return CALL_FPTR((check_fptr_t)mg->mg_ptr)(aTHX_ mg->mg_obj, sv); } } @@ -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,42 +427,47 @@ 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 */ +static CV* +mouse_tc_parameterize(pTHX_ const char* const name, check_fptr_t const fptr, SV* const param) { + 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 */ + PERL_MAGIC_ext, + &mouse_util_type_constraints_vtbl, + (void*)fptr, /* mg_ptr */ + 0 /* mg_len: 0 for static data */ + ); + + if(!name){ + sv_2mortal((SV*)xsub); + } + + return xsub; +} + CV* mouse_generate_isa_predicate_for(pTHX_ SV* const klass, const char* const predicate_name){ STRLEN klass_len; const char* klass_pv = SvPV_const(klass, klass_len); - CV* xsub; - SV* mg_obj; - void* mg_ptr; + SV* param; + void* fptr; klass_pv = mouse_canonicalize_package_name(klass_pv); if(strNE(klass_pv, "UNIVERSAL")){ - mg_obj = (SV*)gv_stashpvn(klass_pv, klass_len, GV_ADD); - mg_ptr = (void*)mouse_is_an_instance_of; + param = (SV*)gv_stashpvn(klass_pv, klass_len, GV_ADD); + fptr = (void*)mouse_is_an_instance_of; } else{ - mg_obj = NULL; - mg_ptr = (void*)mouse_is_an_instance_of_universal; - } - - xsub = newXS(predicate_name, XS_Mouse_parameterized_check, __FILE__); - - CvXSUBANY(xsub).any_ptr = sv_magicext( - (SV*)xsub, - mg_obj, - PERL_MAGIC_ext, - &mouse_util_type_constraints_vtbl, - mg_ptr, - 0 /* indicates static data */ - ); - - if(!predicate_name){ - sv_2mortal((SV*)xsub); + param = NULL; + fptr = (void*)mouse_is_an_instance_of_universal; } - return xsub; + return mouse_tc_parameterize(aTHX_ predicate_name, fptr, param); } XS(XS_Mouse_parameterized_check) { @@ -491,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 +