Add a comment
[gitmo/Mouse.git] / xs-src / MouseTypeConstraints.xs
index 31d7c46..43800a2 100644 (file)
 #define SvRXOK(sv) (SvROK(sv) && SvMAGICAL(SvRV(sv)) && mg_find(SvRV(sv), PERL_MAGIC_qr))
 #endif
 
+typedef int (*check_fptr_t)(pTHX_ SV* const data, SV* const sv);
+
 int
 mouse_tc_check(pTHX_ SV* const tc_code, SV* const sv) {
-    if(SvIOK(tc_code)){ /* built-in type constraints */
-        return mouse_builtin_tc_check(aTHX_ SvIVX(tc_code), sv);
+    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){
+            assert(CvXSUBANY(cv).any_iv > 0);
+
+            return mouse_builtin_tc_check(aTHX_ CvXSUBANY(cv).any_iv, sv);
+        }
+        else if(CvXSUB(cv) == XS_Mouse_parameterized_check){
+            MAGIC* const mg = (MAGIC*)CvXSUBANY(cv).any_ptr;
+
+            assert(CvXSUBANY(cv).any_ptr != NULL);
+
+            /* call the check function directly, skipping call_sv() */
+            return CALL_FPTR((check_fptr_t)mg->mg_ptr)(aTHX_ mg->mg_obj, sv);
+        }
     }
-    else {
+
+    /* user-defined type constraints */
+    {
         int ok;
         dSP;
 
@@ -67,11 +86,10 @@ mouse_builtin_tc_check(pTHX_ mouse_tc const tc, SV* const sv) {
     case MOUSE_TC_CLASS_NAME: return mouse_tc_ClassName(aTHX_ sv);
     case MOUSE_TC_ROLE_NAME:  return mouse_tc_RoleName(aTHX_ sv);
     default:
-        /* custom type constraints */
         NOOP;
     }
 
-    croak("Custom type constraint is not yet implemented");
+    croak("Mouse-panic: unrecognized type constraint id: %d", (int)tc);
     return FALSE; /* not reached */
 }
 
@@ -90,22 +108,23 @@ mouse_tc_Any(pTHX_ SV* const sv PERL_UNUSED_DECL) {
 int
 mouse_tc_Bool(pTHX_ SV* const sv) {
     assert(sv);
-    if(SvOK(sv)){
+
+    if(SvTRUE(sv)){
         if(SvIOKp(sv)){
-            return SvIVX(sv) == 1 || SvIVX(sv) == 0;
+            return SvIVX(sv) == 1;
         }
         else if(SvNOKp(sv)){
-            return SvNVX(sv) == 1.0 || SvNVX(sv) == 0.0;
+            return SvNVX(sv) == 1.0;
         }
-        else if(SvPOKp(sv)){ /* "" or "1" or "0" */
-            return SvCUR(sv) == 0
-                || ( SvCUR(sv) == 1 && ( SvPVX(sv)[0] == '1' || SvPVX(sv)[0] == '0' ) );
+        else if(SvPOKp(sv)){ /* "1" */
+            return SvCUR(sv) == 1 && SvPVX(sv)[0] == '1';
         }
         else{
             return FALSE;
         }
     }
     else{
+        /* false must be boolean */
         return TRUE;
     }
 }
@@ -184,7 +203,7 @@ mouse_tc_RoleName(pTHX_ SV* const sv) {
         meta = POPs;
         PUTBACK;
 
-        ok =  is_instance_of(meta, newSVpvs_flags("Mouse::Meta::Role", SVs_TEMP));
+        ok =  is_an_instance_of("Mouse::Meta::Role", meta);
 
         FREETMPS;
         LEAVE;
@@ -252,7 +271,7 @@ mouse_tc_FileHandle(pTHX_ SV* const sv) {
         }
     }
 
-    return is_instance_of(sv, newSVpvs_flags("IO::Handle", SVs_TEMP));
+    return is_an_instance_of("IO::Handle", sv);
 }
 
 int
@@ -312,7 +331,7 @@ mouse_is_an_instance_of(pTHX_ HV* const stash, SV* const instance){
     assert(stash);
     assert(SvTYPE(stash) == SVt_PVHV);
 
-    if(SvROK(instance) && SvOBJECT(SvRV(instance))){
+    if(IsObject(instance)){
         dMY_CXT;
         HV* const instance_stash = SvSTASH(SvRV(instance));
         GV* const instance_isa   = gv_fetchmeth_autoload(instance_stash, "isa", sizeof("isa")-1, 0);
@@ -385,7 +404,7 @@ mouse_generate_isa_predicate_for(pTHX_ SV* const klass, const char* const predic
 
     CvXSUBANY(xsub).any_ptr = sv_magicext(
         (SV*)xsub,
-        mg_obj,
+        mg_obj, /* refcnt will be increased */
         PERL_MAGIC_ext,
         &mouse_util_type_constraints_vtbl,
         mg_ptr,
@@ -403,7 +422,6 @@ XS(XS_Mouse_parameterized_check) {
     dVAR;
     dXSARGS;
     MAGIC* const mg = (MAGIC*)XSANY.any_ptr;
-    typedef int (*check_fptr_t)(pTHX_ SV* const data, SV* const sv);
 
     if(items < 1){
         croak("Too few arguments for parameterized check functions");