}
}
+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;
flags |= MOUSEf_XC_HAS_BUILDARGS;
}
- if(predicate_calls(metaclass, "__strict_constructor")){
+ if(predicate_calls(metaclass, "strict_constructor")){
flags |= MOUSEf_XC_CONSTRUCTOR_IS_STRICT;
}
static void
-mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const ignore_triggers) {
+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);
croak("You cannot use tied HASH reference as initializing arguments");
}
- if(!ignore_triggers){
- triggers_queue = newAV_mortal();
- }
-
/* for each attribute */
for(i = 0; i < len; i++){
SV* const attr = MOUSE_av_at(attrs, i);
if(SvROK(value) && flags & MOUSEf_ATTR_IS_WEAK_REF){
weaken_slot(object, slot);
}
- if(flags & MOUSEf_ATTR_HAS_TRIGGER && triggers_queue){
+ if(flags & MOUSEf_ATTR_HAS_TRIGGER){
AV* const pair = newAV();
av_push(pair, newSVsv( mcall0s(attr, "trigger") ));
av_push(pair, newSVsv(value));
+ if(!triggers_queue) {
+ triggers_queue = newAV_mortal();
+ }
av_push(triggers_queue, (SV*)pair);
}
used++;
}
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);
}
}
}
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];
PUSHs(args);
PUTBACK;
- call_sv(AvARRAY(buildall)[i], G_VOID);
+ call_sv_safe(AvARRAY(buildall)[i], G_VOID);
/* discard a scalar which G_VOID returns */
SPAGAIN;
return (AV*)SvRV(storage_ref);
}
+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
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
/* *{$package . '::' . $name} -> *gv */
gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV);
mouse_install_sub(aTHX_ gv, code_ref);
+ //CvMETHOD_on((CV*)SvRV(code_ref));
(void)set_slot(methods, name, code); /* $self->{methods}{$name} = $code */
}
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_CLASS_HOLDER(Class, method_metaclass, "Mouse::Meta::Method");
INSTALL_CLASS_HOLDER(Class, attribute_metaclass, "Mouse::Meta::Attribute");
newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Destructor::XS", TRUE), "_generate_destructor",
newRV_inc((SV*)get_cvs("Mouse::Object::DESTROY", TRUE)));
-
void
linearized_isa(SV* self)
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);
+}
+
+void
+_initialize_object(SV* meta, SV* object, HV* args, bool is_cloning = FALSE)
+CODE:
+{
+ mouse_class_initialize_object(aTHX_ meta, object, args, is_cloning);
}
-OUTPUT:
- RETVAL
void
-_initialize_object(SV* meta, SV* object, HV* args, bool ignore_triggers = FALSE)
+strict_constructor(SV* self, SV* value = NULL)
CODE:
{
- mouse_class_initialize_object(aTHX_ meta, object, args, ignore_triggers);
+ SV* const slot = sv_2mortal(newSVpvs_share("strict_constructor"));
+ SV* const stash_ref = mcall0(self, mouse_namespace);
+ HV* stash;
+
+ if(!(SvROK(stash_ref) && SvTYPE(SvRV(stash_ref)) == SVt_PVHV)) {
+ croak("namespace() didn't return a HASH reference");
+ }
+ stash = (HV*)SvRV(stash_ref);
+
+ if(value) { /* setter */
+ set_slot(self, slot, value);
+ mro_method_changed_in(stash);
+ }
+
+ 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;
+ }
+ }
+ }
+ ST(0) = value ? value : &PL_sv_no;
}
MODULE = Mouse PACKAGE = Mouse::Meta::Role
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
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;
MODULE = Mouse PACKAGE = Mouse::Object
-SV*
+void
new(SV* klass, ...)
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){
for(i = 0; i < items; i++){
PUSHs(ST(i));
}
- //SP += items;
+
PUTBACK;
- call_method("BUILDARGS", G_SCALAR);
+ call_method_safes("BUILDARGS", G_SCALAR);
+
SPAGAIN;
args = POPs;
PUTBACK;
}
/* 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)
len = AvFILLp(demolishall) + 1;
if(len > 0){
- GV* const statusvalue = gv_fetchpvs("?", 0, SVt_PV);
+ SV* const in_global_destruction = boolSV(PL_dirty);
+ SAVEI32(PL_statusvalue); /* local $? */
+ PL_statusvalue = 0;
- if(statusvalue){ /* it can be NULL */
- SAVESPTR(GvSV(statusvalue)); /* local $? */
- GvSV(statusvalue) = sv_newmortal();
- }
SAVESPTR(ERRSV); /* local $@ */
- ERRSV = newSVpvs_flags("", SVs_TEMP);
+ ERRSV = sv_newmortal();
+
+ EXTEND(SP, 2);
for(i = 0; i < len; i++){
SPAGAIN;
PUSHMARK(SP);
- XPUSHs(object);
- XPUSHs(boolSV(PL_dirty));
+ PUSHs(object);
+ PUSHs(in_global_destruction);
PUTBACK;
call_sv(AvARRAY(demolishall)[i], G_VOID | G_EVAL);