X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=xs-src%2FMouseAccessor.xs;h=3df9fdaf28223e65ac2dbc37d18e9699d53f0235;hb=05e658dc1915e54a27d218201b3a9d7314ccdabe;hp=37c5ffd8708dd9f7903f29e6afd449560fd58c73;hpb=06afbf314918195c3d4ab2e154f84d46b2633d7c;p=gitmo%2FMouse.git diff --git a/xs-src/MouseAccessor.xs b/xs-src/MouseAccessor.xs index 37c5ffd..3df9fda 100644 --- a/xs-src/MouseAccessor.xs +++ b/xs-src/MouseAccessor.xs @@ -1,9 +1,10 @@ #include "mouse.h" -#define CHECK_INSTANCE(instance) STMT_START{ \ - if(!(SvROK(instance) && SvTYPE(SvRV(instance)) == SVt_PVHV)){ \ - croak("Invalid object instance"); \ - } \ +#define CHECK_INSTANCE(instance) STMT_START{ \ + assert(instance); \ + if(!(SvROK(instance) && SvTYPE(SvRV(instance)) == SVt_PVHV)){ \ + croak("Invalid object instance: '%"SVf"'", instance); \ + } \ } STMT_END @@ -13,7 +14,7 @@ static MGVTBL mouse_accessor_vtbl; /* MAGIC identity */ #define dMOUSE_self SV* const self = mouse_accessor_get_self(aTHX_ ax, items, cv) -static inline SV* +STATIC_INLINE SV* mouse_accessor_get_self(pTHX_ I32 const ax, I32 const items, CV* const cv) { if(items < 1){ croak("Too few arguments for %s", GvNAME(CvGV(cv))); @@ -88,10 +89,12 @@ mouse_push_values(pTHX_ SV* const value, U16 const flags){ PUSHs(svp ? *svp : &PL_sv_undef); } } - else if(flags & MOUSEf_TC_IS_HASHREF){ + else{ HV* hv; HE* he; + assert(flags & MOUSEf_TC_IS_HASHREF); + if(!IsHashRef(value)){ croak("Mouse-panic: Not a HASH reference"); } @@ -142,14 +145,22 @@ mouse_attr_set(pTHX_ SV* const self, MAGIC* const mg, SV* value){ SV* const trigger = mcall0s(MOUSE_mg_attribute(mg), "trigger"); dSP; + /* NOTE: triggers can remove value, so + value must be copied here, + revealed by Net::Google::DataAPI (DANJOU). + */ + value = sv_mortalcopy(value); + PUSHMARK(SP); EXTEND(SP, 2); PUSHs(self); PUSHs(value); PUTBACK; - call_sv(trigger, G_VOID | G_DISCARD); + call_sv_safe(trigger, G_VOID | G_DISCARD); /* need not SPAGAIN */ + + assert(SvTYPE(value) != SVTYPEMASK); } PUSH_VALUE(value, flags); @@ -172,7 +183,8 @@ XS(XS_Mouse_accessor) } else{ mouse_throw_error(MOUSE_mg_attribute(mg), NULL, - "Expected exactly one or two argument for an accessor"); + "Expected exactly one or two argument for an accessor of %"SVf, + MOUSE_mg_slot(mg)); } } @@ -185,7 +197,8 @@ XS(XS_Mouse_reader) if (items != 1) { mouse_throw_error(MOUSE_mg_attribute(mg), NULL, - "Cannot assign a value to a read-only accessor"); + "Cannot assign a value to a read-only accessor of %"SVf, + MOUSE_mg_slot(mg)); } SP -= items; /* PPCODE */ @@ -202,7 +215,8 @@ XS(XS_Mouse_writer) if (items != 2) { mouse_throw_error(MOUSE_mg_attribute(mg), NULL, - "Too few arguments for a write-only accessor"); + "Too few arguments for a write-only accessor of %"SVf, + MOUSE_mg_slot(mg)); } SP -= items; /* PPCODE */ @@ -221,7 +235,9 @@ mouse_accessor_get_mg(pTHX_ CV* const xsub){ */ CV* -mouse_simple_accessor_generate(pTHX_ const char* const fq_name, const char* const key, I32 const keylen, XSUBADDR_t const accessor_impl, void* const dptr, I32 const dlen){ +mouse_simple_accessor_generate(pTHX_ + const char* const fq_name, const char* const key, I32 const keylen, + XSUBADDR_t const accessor_impl, void* const dptr, I32 const dlen) { CV* const xsub = newXS((char*)fq_name, accessor_impl, __FILE__); SV* const slot = newSVpvn_share(key, keylen, 0U); MAGIC* mg; @@ -253,7 +269,8 @@ XS(XS_Mouse_simple_reader) SV* value; if (items != 1) { - croak("Expected exactly one argument for a reader for '%"SVf"'", MOUSE_mg_slot(mg)); + croak("Expected exactly one argument for a reader of %"SVf, + MOUSE_mg_slot(mg)); } value = get_slot(self, MOUSE_mg_slot(mg)); @@ -280,7 +297,8 @@ XS(XS_Mouse_simple_writer) SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); if (items != 2) { - croak("Expected exactly two argument for a writer for '%"SVf"'", slot); + croak("Expected exactly two argument for a writer of %"SVf, + slot); } ST(0) = set_slot(self, slot, ST(1)); @@ -295,7 +313,8 @@ XS(XS_Mouse_simple_clearer) SV* value; if (items != 1) { - croak("Expected exactly one argument for a clearer for '%"SVf"'", slot); + croak("Expected exactly one argument for a clearer of %"SVf, + slot); } value = delete_slot(self, slot); @@ -310,35 +329,90 @@ XS(XS_Mouse_simple_predicate) SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); if (items != 1) { - croak("Expected exactly one argument for a predicate for '%"SVf"'", slot); + croak("Expected exactly one argument for a predicate of %"SVf, slot); } ST(0) = boolSV( has_slot(self, slot) ); XSRETURN(1); } +/* Class::Data::Inheritable-like class accessor */ +XS(XS_Mouse_inheritable_class_accessor) { + dVAR; dXSARGS; + dMOUSE_self; + SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); + SV* value; + HV* stash; + + if(items == 1){ /* reader */ + value = NULL; + } + else if (items == 2){ /* writer */ + value = ST(1); + } + else{ + croak("Expected exactly one or two argument for a class data accessor" + "of %"SVf, slot); + value = NULL; /* -Wuninitialized */ + } + + stash = mouse_get_namespace(aTHX_ self); + + if(!value) { /* reader */ + value = get_slot(self, slot); + if(!value) { + AV* const isa = mro_get_linear_isa(stash); + I32 const len = av_len(isa) + 1; + I32 i; + for(i = 1; i < len; i++) { + SV* const klass = MOUSE_av_at(isa, i); + SV* const meta = get_metaclass(klass); + if(!SvOK(meta)){ + continue; /* skip non-Mouse classes */ + } + value = get_slot(meta, slot); + if(value) { + break; + } + } + if(!value) { + value = &PL_sv_undef; + } + } + } + else { /* writer */ + set_slot(self, slot, value); + mro_method_changed_in(stash); + } + + ST(0) = value; + XSRETURN(1); +} + /* simple instance slot accessor (or Mouse::Meta::Instance) */ SV* mouse_instance_create(pTHX_ HV* const stash) { + SV* instance; assert(stash); assert(SvTYPE(stash) == SVt_PVHV); - return sv_bless( newRV_noinc((SV*)newHV()), stash ); + instance = sv_bless( newRV_noinc((SV*)newHV()), stash ); + return sv_2mortal(instance); } SV* mouse_instance_clone(pTHX_ SV* const instance) { - HV* proto; - assert(instance); - + SV* proto; CHECK_INSTANCE(instance); - proto = newHVhv((HV*)SvRV(instance)); - return sv_bless( newRV_noinc((SV*)proto), SvSTASH(SvRV(instance)) ); + assert(SvOBJECT(SvRV(instance))); + + proto = newRV_noinc((SV*)newHVhv((HV*)SvRV(instance))); + sv_bless(proto, SvSTASH(SvRV(instance))); + return sv_2mortal(proto); } bool mouse_instance_has_slot(pTHX_ SV* const instance, SV* const slot) { - assert(instance); assert(slot); CHECK_INSTANCE(instance); return hv_exists_ent((HV*)SvRV(instance), slot, 0U); @@ -347,7 +421,6 @@ mouse_instance_has_slot(pTHX_ SV* const instance, SV* const slot) { SV* mouse_instance_get_slot(pTHX_ SV* const instance, SV* const slot) { HE* he; - assert(instance); assert(slot); CHECK_INSTANCE(instance); he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U); @@ -358,7 +431,6 @@ SV* mouse_instance_set_slot(pTHX_ SV* const instance, SV* const slot, SV* const value) { HE* he; SV* sv; - assert(instance); assert(slot); assert(value); CHECK_INSTANCE(instance); @@ -380,7 +452,6 @@ mouse_instance_delete_slot(pTHX_ SV* const instance, SV* const slot) { void mouse_instance_weaken_slot(pTHX_ SV* const instance, SV* const slot) { HE* he; - assert(instance); assert(slot); CHECK_INSTANCE(instance); he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U);