Change inline_constructor => 0
[gitmo/Mouse.git] / xs-src / Mouse.xs
index 3e654c4..b167206 100644 (file)
@@ -8,7 +8,7 @@ SV* mouse_name;
 SV* mouse_get_attribute;
 SV* mouse_get_attribute_list;
 
-
+#define MOUSE_xc_flags(a)       SvUVX(MOUSE_av_at((a), MOUSE_XC_FLAGS))
 #define MOUSE_xc_gen(a)         MOUSE_av_at((a), MOUSE_XC_GEN)
 #define MOUSE_xc_stash(a)       ( (HV*)MOUSE_av_at((a), MOUSE_XC_STASH) )
 #define MOUSE_xc_attrall(a)     ( (AV*)MOUSE_av_at((a), MOUSE_XC_ATTRALL) )
@@ -25,9 +25,10 @@ enum mouse_xc_flags_t {
 
 /* Mouse XS Metaclass object */
 enum mouse_xc_ix_t{
+    MOUSE_XC_FLAGS,
+
     MOUSE_XC_GEN,          /* class generation */
     MOUSE_XC_STASH,        /* symbol table hash */
-    MOUSE_XC_FLAGS,
 
     MOUSE_XC_BUILDARGS,    /* Custom BUILDARGS */
 
@@ -72,10 +73,8 @@ mouse_class_has_custom_buildargs(pTHX_ HV* const stash) {
     XS(XS_Mouse__Object_BUILDARGS); /* prototype */
 
     GV* const buildargs = gv_fetchmeth_autoload(stash, "BUILDARGS", sizeof("BUILDARGS")-1, 0);
-    CV* const cv        = GvCV(buildargs);
 
-    assert(cv);
-    return CvXSUB(cv) == XS_Mouse__Object_BUILDARGS;
+    return buildargs && CvXSUB(GvCV(buildargs)) == XS_Mouse__Object_BUILDARGS;
 }
 
 static void
@@ -104,14 +103,19 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas
 
     /* update */
 
-    if(SvTRUEx( mcall0s(metaclass, "is_immutable") )){
+    if(predicate_calls(metaclass, "is_immutable")){
         flags |= MOUSEf_XC_IS_IMMUTABLE;
     }
 
+    if(predicate_calls(metaclass, "is_anon_class")){
+        flags |= MOUSEf_XC_IS_ANON;
+    }
+
     if(mouse_class_has_custom_buildargs(aTHX_ stash)){
         flags |= MOUSEf_XC_HAS_BUILDARGS;
     }
 
+    av_store(xc, MOUSE_XC_FLAGS,       newSVuv(flags));
     av_store(xc, MOUSE_XC_ATTRALL,     (SV*)attrall);
     av_store(xc, MOUSE_XC_BUILDALL,    (SV*)buildall);
     av_store(xc, MOUSE_XC_DEMOLISHALL, (SV*)demolishall);
@@ -173,6 +177,7 @@ mouse_get_xc(pTHX_ SV* const metaclass) {
 
         av_store(xc, MOUSE_XC_GEN, newSViv(0));
         av_store(xc, MOUSE_XC_STASH, (SV*)stash);
+
         SvREFCNT_inc_simple_void_NN(stash);
     }
     else{
@@ -192,14 +197,8 @@ mouse_get_xc(pTHX_ SV* const metaclass) {
     return xc;
 }
 
-AV*
-mouse_get_all_attributes(pTHX_ SV* const metaclass) {
-    AV* const xc = mouse_get_xc(aTHX_ metaclass);
-    return MOUSE_xc_attrall(xc);
-}
-
 HV*
-mouse_build_args(aTHX_ SV* metaclass, SV* const klass, I32 const start, I32 const items, I32 const ax) {
+mouse_build_args(pTHX_ SV* metaclass, SV* const klass, I32 const start, I32 const items, I32 const ax) {
     HV* args;
     if((items - start) == 1){
         SV* const args_ref = ST(start);
@@ -229,10 +228,75 @@ mouse_build_args(aTHX_ SV* metaclass, SV* const klass, I32 const start, I32 cons
 }
 
 void
-mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const invoke_triggers) {
-    AV* const xc = mouse_get_xc(aTHX_ meta);
+mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const ignore_triggers) {
+    AV* const xc    = mouse_get_xc(aTHX_ meta);
+    AV* const attrs = MOUSE_xc_attrall(xc);
+    I32 len         = AvFILLp(attrs) + 1;
+    I32 i;
+    AV* triggers_queue = NULL;
+
+    ENTER;
+    SAVETMPS;
+
+    if(!ignore_triggers){
+        triggers_queue = newAV_mortal();
+    }
+
+    for(i = 0; i < len; i++){
+        SV* const attr = AvARRAY(attrs)[i];
+        AV* const xa   = mouse_get_xa(aTHX_ AvARRAY(attrs)[i]);
+
+        SV* const slot     = MOUSE_xa_slot(xa);
+        U16 const flags    = (U16)MOUSE_xa_flags(xa);
+        SV* const init_arg = MOUSE_xa_init_arg(xa);
+        HE* he;
+
+        if(SvOK(init_arg) && ( he = hv_fetch_ent(args, init_arg, FALSE, 0U) ) ){
+            SV* value = HeVAL(he);
+            if(flags & MOUSEf_ATTR_HAS_TC){
+                value = mouse_xa_apply_type_constraint(aTHX_ xa, value, flags);
+            }
+            set_slot(object, slot, value);
+            if(SvROK(value) && flags & MOUSEf_ATTR_IS_WEAK_REF){
+                weaken_slot(object, slot);
+            }
+            if(flags & MOUSEf_ATTR_HAS_TRIGGER && triggers_queue){
+                AV* const pair = newAV();
+                av_push(pair, newSVsv( mcall0s(attr, "trigger") ));
+                av_push(pair, newSVsv(value));
+
+                av_push(triggers_queue, (SV*)pair);
+            }
+        }
+        else { /* no init arg */
+            if(flags & (MOUSEf_ATTR_HAS_DEFAULT | MOUSEf_ATTR_HAS_BUILDER)){
+                if(!(flags & MOUSEf_ATTR_IS_LAZY)){
+                    mouse_xa_set_default(aTHX_ xa, object);
+                }
+            }
+            else if(flags & MOUSEf_ATTR_IS_REQUIRED) {
+                mouse_throw_error(attr, NULL, "Attribute (%"SVf") is required", slot);
+            }
+        }
+    } /* for each attributes */
+
+    if(triggers_queue){
+        len = AvFILLp(triggers_queue) + 1;
+        for(i = 0; i < len; i++){
+            AV* const pair    = (AV*)AvARRAY(triggers_queue)[i];
+            SV* const trigger = AvARRAY(pair)[0];
+            SV* const value   = AvARRAY(pair)[1];
 
-    // TODO
+            mcall1(object, trigger, value);
+        }
+    }
+
+    if(MOUSE_xc_flags(xc) & MOUSEf_XC_IS_ANON){
+        set_slot(object, newSVpvs_flags("__ANON__", SVs_TEMP), meta);
+    }
+
+    FREETMPS;
+    LEAVE;
 }
 
 MODULE = Mouse  PACKAGE = Mouse
@@ -358,7 +422,8 @@ void
 get_all_attributes(SV* self)
 PPCODE:
 {
-    AV* const all_attrs = mouse_get_all_attributes(aTHX_ self);
+    AV* const xc        = mouse_get_xc(aTHX_ self);
+    AV* const all_attrs =  MOUSE_xc_attrall(xc);
     I32 const len       = AvFILLp(all_attrs) + 1;
     I32 i;
 
@@ -374,16 +439,17 @@ CODE:
 {
     HV* const args = mouse_build_args(aTHX_ meta, NULL, 1, items, ax);
     AV* const xc   = mouse_get_xc(aTHX_ meta);
+
     RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
-    mouse_class_initialize_object(aTHX_ meta, RETVAL, args, TRUE);
+    mouse_class_initialize_object(aTHX_ meta, RETVAL, args, FALSE);
 }
 
 
 void
-_initialize_object_(SV* meta, SV* object, HV* args, bool invoke_triggers = TRUE)
+_initialize_object(SV* meta, SV* object, HV* args, bool ignore_triggers = FALSE)
 CODE:
 {
-    mouse_class_initialize_object(aTHX_ meta, object, args, invoke_triggers);
+    mouse_class_initialize_object(aTHX_ meta, object, args, ignore_triggers);
 }
 
 MODULE = Mouse  PACKAGE = Mouse::Meta::Role
@@ -402,4 +468,3 @@ CODE:
 }
 OUTPUT:
     RETVAL
-