Add _initialize_object()
[gitmo/Mouse.git] / xs-src / MouseAttribute.xs
index 9bda4c6..62b2593 100644 (file)
@@ -35,6 +35,8 @@ mouse_get_xa(pTHX_ SV* const attr) {
 
         av_store(xa, MOUSE_XA_ATTRIBUTE, newSVsv(attr));
 
+        av_store(xa, MOUSE_XA_INIT_ARG, newSVsv(mcall0s(attr, "init_arg")));
+
         if(predicate_calls(attr, "has_type_constraint")){
             SV* tc;
             flags |= MOUSEf_ATTR_HAS_TC;
@@ -71,13 +73,12 @@ mouse_get_xa(pTHX_ SV* const attr) {
 
         if(predicate_calls(attr, "is_lazy")){
             flags |= MOUSEf_ATTR_IS_LAZY;
-
-            if(predicate_calls(attr, "has_builder")){
-                flags |= MOUSEf_ATTR_HAS_BUILDER;
-            }
-            else if(predicate_calls(attr, "has_default")){
-                flags |= MOUSEf_ATTR_HAS_DEFAULT;
-            }
+        }
+        if(predicate_calls(attr, "has_builder")){
+            flags |= MOUSEf_ATTR_HAS_BUILDER;
+        }
+        else if(predicate_calls(attr, "has_default")){
+            flags |= MOUSEf_ATTR_HAS_DEFAULT;
         }
 
         if(predicate_calls(attr, "is_weak_ref")){
@@ -104,6 +105,70 @@ mouse_get_xa(pTHX_ SV* const attr) {
     return xa;
 }
 
+SV*
+mouse_xa_apply_type_constraint(pTHX_ AV* const xa, SV* value, U16 const flags){
+    SV* const tc = MOUSE_xa_tc(xa);
+    SV* tc_code;
+
+    if(flags & MOUSEf_ATTR_SHOULD_COERCE){
+          value = mcall1s(tc, "coerce", value);
+    }
+
+    if(!SvOK(MOUSE_xa_tc_code(xa))){
+        tc_code = mcall0s(tc, "_compiled_type_constraint");
+        av_store(xa, MOUSE_XA_TC_CODE, newSVsv(tc_code));
+
+        if(!IsCodeRef(tc_code)){
+            mouse_throw_error(MOUSE_xa_attribute(xa), tc, "Not a CODE reference");
+        }
+    }
+    else{
+        tc_code = MOUSE_xa_tc_code(xa);
+    }
+
+    if(!mouse_tc_check(aTHX_ tc_code, value)){
+        mouse_throw_error(MOUSE_xa_attribute(xa), value,
+            "Attribute (%"SVf") does not pass the type constraint because: %"SVf,
+                mcall0(MOUSE_xa_attribute(xa), mouse_name),
+                mcall1s(tc, "get_message", value));
+    }
+
+    return value;
+}
+
+
+SV*
+mouse_xa_set_default(pTHX_ AV* const xa, SV* const object) {
+    U16 const flags = (U16)MOUSE_xa_flags(xa);
+    SV* value;
+
+    /* get default value by $attr->builder or $attr->default */
+    if(flags & MOUSEf_ATTR_HAS_BUILDER){
+        SV* const builder = mcall0s(MOUSE_xa_attribute(xa), "builder");
+        value = mcall0(object, builder); /* $object->$builder() */
+    }
+    else {
+        value = mcall0s(MOUSE_xa_attribute(xa), "default");
+
+        if(IsCodeRef(value)){
+            value = mcall0(object, value);
+        }
+    }
+
+    /* apply coerce and type constraint */
+    if(flags & MOUSEf_ATTR_HAS_TC){
+        value = mouse_xa_apply_type_constraint(aTHX_ xa, value, flags);
+    }
+
+    /* store value to slot */
+    value = set_slot(object, MOUSE_xa_slot(xa), value);
+
+    if(flags & MOUSEf_ATTR_IS_WEAK_REF && SvROK(value)){
+        weaken_slot(object, MOUSE_xa_slot(xa));
+    }
+
+    return value;
+}
 
 MODULE = Mouse::Meta::Attribute  PACKAGE = Mouse::Meta::Attribute