X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=xs-src%2FMouse.xs;h=8bb69c56b948453b013160cc5b0761efc31d6fbe;hb=902174eb6dc2afbe8a2b8fb0a27446b3276787d8;hp=f27c52feba3e4f1e7f59c23d2f91b95c40705ac9;hpb=cb6a9721f6d1bf6aaba58920378aad6c03524639;p=gitmo%2FMouse.git diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index f27c52f..8bb69c5 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -76,10 +76,10 @@ mouse_class_push_attribute_list(pTHX_ SV* const metaclass, AV* const attrall, HV } } +XS(XS_Mouse__Object_BUILDARGS); /* prototype */ + static int 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); return buildargs && CvXSUB(GvCV(buildargs)) != XS_Mouse__Object_BUILDARGS; @@ -123,7 +123,7 @@ mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stas flags |= MOUSEf_XC_HAS_BUILDARGS; } - if(predicate_calls(metaclass, "__strict_constructor")){ + if(predicate_calls(metaclass, "strict_constructor")){ flags |= MOUSEf_XC_CONSTRUCTOR_IS_STRICT; } @@ -294,10 +294,10 @@ static void mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const is_cloning) { AV* const xc = mouse_get_xc(aTHX_ meta); AV* const attrs = MOUSE_xc_attrall(xc); - I32 len = AvFILLp(attrs) + 1; + I32 const len = AvFILLp(attrs) + 1; I32 i; AV* triggers_queue = NULL; - I32 used = 0; + U32 used = 0; assert(meta || object); assert(args); @@ -338,13 +338,15 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const } used++; } - else if(!is_cloning){ /* no init arg, noop while cloning */ + else { /* no init arg */ if(flags & (MOUSEf_ATTR_HAS_DEFAULT | MOUSEf_ATTR_HAS_BUILDER)){ - if(!(flags & MOUSEf_ATTR_IS_LAZY)){ + /* skip if the object has the slot (it occurs on cloning/reblessing) */ + if(!(flags & MOUSEf_ATTR_IS_LAZY) && !has_slot(object, slot)){ mouse_xa_set_default(aTHX_ xa, object); } } - else if(flags & MOUSEf_ATTR_IS_REQUIRED) { + /* don't check while cloning (or reblesseing) */ + else if(!is_cloning && flags & MOUSEf_ATTR_IS_REQUIRED) { mouse_throw_error(attr, NULL, "Attribute (%"SVf") is required", slot); } } @@ -355,7 +357,7 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const } if(triggers_queue){ - len = AvFILLp(triggers_queue) + 1; + I32 const 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]; @@ -443,11 +445,27 @@ mouse_get_modifier_storage(pTHX_ return (AV*)SvRV(storage_ref); } +static void +XS_Mouse_value_holder(pTHX_ CV* const cv PERL_UNUSED_DECL) { + dVAR; dXSARGS; + SV* const value = (SV*)XSANY.any_ptr; + assert(value); + PERL_UNUSED_VAR(items); + ST(0) = value; + XSRETURN(1); +} + +DECL_BOOT(Mouse__Util); +DECL_BOOT(Mouse__Util__TypeConstraints); +DECL_BOOT(Mouse__Meta__Method__Accessor__XS); +DECL_BOOT(Mouse__Meta__Attribute); + MODULE = Mouse PACKAGE = Mouse PROTOTYPES: DISABLE BOOT: +{ mouse_package = newSVpvs_share("package"); mouse_namespace = newSVpvs_share("namespace"); mouse_methods = newSVpvs_share("methods"); @@ -457,11 +475,11 @@ BOOT: mouse_get_attribute = newSVpvs_share("get_attribute"); mouse_get_attribute_list = newSVpvs_share("get_attribute_list"); - MOUSE_CALL_BOOT(Mouse__Util); - MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints); - MOUSE_CALL_BOOT(Mouse__Meta__Method__Accessor__XS); - MOUSE_CALL_BOOT(Mouse__Meta__Attribute); - + CALL_BOOT(Mouse__Util); + CALL_BOOT(Mouse__Util__TypeConstraints); + CALL_BOOT(Mouse__Meta__Method__Accessor__XS); + CALL_BOOT(Mouse__Meta__Attribute); +} MODULE = Mouse PACKAGE = Mouse::Meta::Module @@ -516,23 +534,45 @@ CODE: (void)set_slot(methods, name, code); /* $self->{methods}{$name} = $code */ } +void +add_class_accessor(SV* self, SV* name) +CODE: +{ + SV* const klass = mouse_call0(self, mouse_name); + const char* fq_name = form("%"SVf"::%"SVf, klass, name); + STRLEN keylen; + const char* const key = SvPV_const(name, keylen); + mouse_simple_accessor_generate(aTHX_ fq_name, key, keylen, + XS_Mouse_inheritable_class_accessor, NULL, 0); +} + MODULE = Mouse PACKAGE = Mouse::Meta::Class BOOT: +{ + CV* xsub; + INSTALL_SIMPLE_READER(Class, roles); INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id); INSTALL_SIMPLE_READER(Class, is_immutable); - INSTALL_SIMPLE_READER_WITH_KEY(Class, __strict_constructor, strict_constructor); + + INSTALL_INHERITABLE_CLASS_ACCESSOR(strict_constructor); INSTALL_CLASS_HOLDER(Class, method_metaclass, "Mouse::Meta::Method"); INSTALL_CLASS_HOLDER(Class, attribute_metaclass, "Mouse::Meta::Attribute"); INSTALL_CLASS_HOLDER(Class, constructor_class, "Mouse::Meta::Method::Constructor::XS"); INSTALL_CLASS_HOLDER(Class, destructor_class, "Mouse::Meta::Method::Destructor::XS"); - newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Constructor::XS", TRUE), "_generate_constructor", - newRV_inc((SV*)get_cvs("Mouse::Object::new", TRUE))); - newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Destructor::XS", TRUE), "_generate_destructor", - newRV_inc((SV*)get_cvs("Mouse::Object::DESTROY", TRUE))); + xsub = newXS("Mouse::Meta::Method::Constructor::XS::_generate_constructor", + XS_Mouse_value_holder, file); + CvXSUBANY(xsub).any_ptr + = newRV_inc((SV*)get_cvs("Mouse::Object::new", GV_ADD)); + + xsub = newXS("Mouse::Meta::Method::Destructor::XS::_generate_destructor", + XS_Mouse_value_holder, file); + CvXSUBANY(xsub).any_ptr + = newRV_inc((SV*)get_cvs("Mouse::Object::DESTROY", GV_ADD)); +} void @@ -569,18 +609,40 @@ PPCODE: } } -SV* +void new_object(SV* meta, ...) CODE: { AV* const xc = mouse_get_xc(aTHX_ meta); HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax, items); + SV* object; - RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); - mouse_class_initialize_object(aTHX_ meta, RETVAL, args, FALSE); + object = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); + mouse_class_initialize_object(aTHX_ meta, object, args, FALSE); + mouse_buildall(aTHX_ xc, object, sv_2mortal(newRV_inc((SV*)args))); /* BUILDALL */ + ST(0) = object; /* because object is mortal, we should return it as is */ + XSRETURN(1); +} + +void +clone_object(SV* meta, SV* object, ...) +CODE: +{ + AV* const xc = mouse_get_xc(aTHX_ meta); + HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax + 1, items - 1); + SV* proto; + + if(!mouse_is_an_instance_of(aTHX_ MOUSE_xc_stash(xc), object)) { + mouse_throw_error(meta, object, + "You must pass an instance of the metaclass (%"SVf"), not (%"SVf")", + mcall0(meta, mouse_name), object); + } + + proto = mouse_instance_clone(aTHX_ object); + mouse_class_initialize_object(aTHX_ meta, proto, args, TRUE); + ST(0) = proto; /* because object is mortal, we should return it as is */ + XSRETURN(1); } -OUTPUT: - RETVAL void _initialize_object(SV* meta, SV* object, HV* args, bool is_cloning = FALSE) @@ -601,7 +663,7 @@ void add_before_modifier(SV* self, SV* name, SV* modifier) CODE: { - av_push(mouse_get_modifier_storage(aTHX_ self, ix, name), newSVsv(modifier)); + av_push(mouse_get_modifier_storage(aTHX_ self, (enum mouse_modifier_t)ix, name), newSVsv(modifier)); } ALIAS: add_before_method_modifier = MOUSE_M_BEFORE @@ -616,7 +678,7 @@ ALIAS: get_after_method_modifiers = MOUSE_M_AFTER PPCODE: { - AV* const storage = mouse_get_modifier_storage(aTHX_ self, ix, name); + AV* const storage = mouse_get_modifier_storage(aTHX_ self, (enum mouse_modifier_t)ix, name); I32 const len = av_len(storage) + 1; if(GIMME_V == G_ARRAY) { I32 i; @@ -632,7 +694,7 @@ PPCODE: MODULE = Mouse PACKAGE = Mouse::Object -SV* +void new(SV* klass, ...) CODE: { @@ -640,6 +702,7 @@ CODE: AV* const xc = mouse_get_xc(aTHX_ meta); UV const flags = MOUSE_xc_flags(xc); SV* args; + SV* object; /* BUILDARGS */ if(flags & MOUSEf_XC_HAS_BUILDARGS){ @@ -669,13 +732,12 @@ CODE: } /* new_object */ - RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); - mouse_class_initialize_object(aTHX_ meta, RETVAL, (HV*)SvRV(args), FALSE); - - mouse_buildall(aTHX_ xc, RETVAL, args); + object = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc)); + mouse_class_initialize_object(aTHX_ meta, object, (HV*)SvRV(args), FALSE); + mouse_buildall(aTHX_ xc, object, args); /* BUILDALL */ + ST(0) = object; /* because object is mortal, we should return it as is */ + XSRETURN(1); } -OUTPUT: - RETVAL void DESTROY(SV* object)