From: gfx Date: Sun, 15 Nov 2009 08:47:25 +0000 (+0900) Subject: Add _initialize_object() X-Git-Tag: 0.40_06~16 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=4e7e3250fdc8eeccfd656270b40f6aa9817da9a9;p=gitmo%2FMouse.git Add _initialize_object() --- diff --git a/lib/Mouse/Meta/Class.pm b/lib/Mouse/Meta/Class.pm index 75fd5af..8183a96 100644 --- a/lib/Mouse/Meta/Class.pm +++ b/lib/Mouse/Meta/Class.pm @@ -11,7 +11,7 @@ our @ISA = qw(Mouse::Meta::Module); sub method_metaclass() { 'Mouse::Meta::Method' } sub attribute_metaclass() { 'Mouse::Meta::Attribute' } -sub constructor_class() { 'Mouse::Meta::Method::Constructor' } +sub constructor_class(); # XS sub destructor_class() { 'Mouse::Meta::Method::Destructor' } sub _construct_meta { @@ -166,62 +166,6 @@ sub new_object { return $object; } -sub _initialize_object{ - my($self, $object, $args, $ignore_triggers) = @_; - - my @triggers_queue; - - foreach my $attribute ($self->get_all_attributes) { - my $from = $attribute->init_arg; - my $key = $attribute->name; - - if (defined($from) && exists($args->{$from})) { - $object->{$key} = $attribute->_coerce_and_verify($args->{$from}, $object); - - weaken($object->{$key}) - if ref($object->{$key}) && $attribute->is_weak_ref; - - if ($attribute->has_trigger) { - push @triggers_queue, [ $attribute->trigger, $object->{$key} ]; - } - } - else { - if ($attribute->has_default || $attribute->has_builder) { - unless ($attribute->is_lazy) { - my $default = $attribute->default; - my $builder = $attribute->builder; - my $value = $builder ? $object->$builder() - : ref($default) eq 'CODE' ? $object->$default() - : $default; - - $object->{$key} = $attribute->_coerce_and_verify($value, $object); - - weaken($object->{$key}) - if ref($object->{$key}) && $attribute->is_weak_ref; - } - } - else { - if ($attribute->is_required) { - $self->throw_error("Attribute (".$attribute->name.") is required"); - } - } - } - } - - if(!$ignore_triggers){ - foreach my $trigger_and_value(@triggers_queue){ - my($trigger, $value) = @{$trigger_and_value}; - $trigger->($object, $value); - } - } - - if($self->is_anon_class){ - $object->{__METACLASS__} = $self; - } - - return $object; -} - sub clone_object { my $class = shift; my $object = shift; diff --git a/lib/Mouse/PurePerl.pm b/lib/Mouse/PurePerl.pm index a6f1be4..e50b57a 100644 --- a/lib/Mouse/PurePerl.pm +++ b/lib/Mouse/PurePerl.pm @@ -203,6 +203,8 @@ sub add_method { package Mouse::Meta::Class; +sub constructor_class() { 'Mouse::Meta::Method::Constructor' } + sub is_anon_class{ return exists $_[0]->{anon_serial_id}; } @@ -217,6 +219,61 @@ sub get_all_attributes { return values %attrs; } +sub _initialize_object{ + my($self, $object, $args, $ignore_triggers) = @_; + + my @triggers_queue; + + foreach my $attribute ($self->get_all_attributes) { + my $init_arg = $attribute->init_arg; + my $slot = $attribute->name; + + if (defined($init_arg) && exists($args->{$init_arg})) { + $object->{$slot} = $attribute->_coerce_and_verify($args->{$init_arg}, $object); + + weaken($object->{$slot}) + if ref($object->{$slot}) && $attribute->is_weak_ref; + + if ($attribute->has_trigger) { + push @triggers_queue, [ $attribute->trigger, $object->{$slot} ]; + } + } + else { # no init arg + if ($attribute->has_default || $attribute->has_builder) { + if (!$attribute->is_lazy) { + my $default = $attribute->default; + my $builder = $attribute->builder; + my $value = $builder ? $object->$builder() + : ref($default) eq 'CODE' ? $object->$default() + : $default; + + $object->{$slot} = $attribute->_coerce_and_verify($value, $object); + + weaken($object->{$slot}) + if ref($object->{$slot}) && $attribute->is_weak_ref; + } + } + elsif($attribute->is_required) { + $self->throw_error("Attribute (".$attribute->name.") is required"); + } + } + } + + if(!$ignore_triggers){ + foreach my $trigger_and_value(@triggers_queue){ + my($trigger, $value) = @{$trigger_and_value}; + $trigger->($object, $value); + } + } + + if($self->is_anon_class){ + $object->{__METACLASS__} = $self; + } + + return; +} + + package Mouse::Meta::Role; diff --git a/mouse.h b/mouse.h index a359b14..0be0825 100644 --- a/mouse.h +++ b/mouse.h @@ -190,11 +190,14 @@ XS(XS_Mouse_constraint_check); /* Mouse XS Attribute object */ AV* mouse_get_xa(pTHX_ SV* const attr); +SV* mouse_xa_apply_type_constraint(pTHX_ AV* const xa, SV* value, U16 const flags); +SV* mouse_xa_set_default(pTHX_ AV* const xa, SV* const object); enum mouse_xa_ix_t{ MOUSE_XA_SLOT, /* for constructors, sync to mg_obj */ MOUSE_XA_FLAGS, /* for constructors, sync to mg_private */ MOUSE_XA_ATTRIBUTE, + MOUSE_XA_INIT_ARG, MOUSE_XA_TC, MOUSE_XA_TC_CODE, @@ -202,17 +205,17 @@ enum mouse_xa_ix_t{ }; #define MOUSE_xa_slot(m) MOUSE_av_at(m, MOUSE_XA_SLOT) -#define MOUSE_xa_flags(m) MOUSE_av_at(m, MOUSE_XA_FLAGS) +#define MOUSE_xa_flags(m) SvUVX( MOUSE_av_at(m, MOUSE_XA_FLAGS) ) #define MOUSE_xa_attribute(m) MOUSE_av_at(m, MOUSE_XA_ATTRIBUTE) +#define MOUSE_xa_init_arg(m) MOUSE_av_at(m, MOUSE_XA_INIT_ARG) #define MOUSE_xa_tc(m) MOUSE_av_at(m, MOUSE_XA_TC) #define MOUSE_xa_tc_code(m) MOUSE_av_at(m, MOUSE_XA_TC_CODE) - enum mouse_xa_flags_t{ MOUSEf_ATTR_HAS_TC = 0x0001, MOUSEf_ATTR_HAS_DEFAULT = 0x0002, MOUSEf_ATTR_HAS_BUILDER = 0x0004, - MOUSEf_ATTR_HAS_INITIALIZER = 0x0008, + MOUSEf_ATTR_HAS_INITIALIZER = 0x0008, /* not used */ MOUSEf_ATTR_HAS_TRIGGER = 0x0010, MOUSEf_ATTR_IS_LAZY = 0x0020, diff --git a/xs-src/Mouse.xs b/xs-src/Mouse.xs index bec3c7d..e518b03 100644 --- a/xs-src/Mouse.xs +++ b/xs-src/Mouse.xs @@ -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 */ @@ -102,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); @@ -171,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{ @@ -224,13 +231,72 @@ void 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 const len = AvFILLp(attrs) + 1; + I32 len = AvFILLp(attrs) + 1; I32 i; - AV* const triggers_queue = (ignore_triggers ? NULL : newAV_mortal()); + AV* triggers_queue = NULL; + + ENTER; + SAVETMPS; + + if(!ignore_triggers){ + triggers_queue = newAV_mortal(); + } for(i = 0; i < len; i++){ - AV* const xa = mouse_get_xa(aTHX_ AvARRAY(attrs)[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]; + + 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 @@ -332,6 +398,8 @@ MODULE = Mouse PACKAGE = Mouse::Meta::Class BOOT: INSTALL_SIMPLE_READER(Class, roles); INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id); + newCONSTSUB(gv_stashpvs("Mouse::Meta::Class", TRUE), "constructor_class", + newSVpvs("Mouse::Meta::Method::Constructor::XS")); void linearized_isa(SV* self) @@ -380,7 +448,7 @@ CODE: void -_initialize_object_(SV* meta, SV* object, HV* args, bool ignore_triggers = FALSE) +_initialize_object(SV* meta, SV* object, HV* args, bool ignore_triggers = FALSE) CODE: { mouse_class_initialize_object(aTHX_ meta, object, args, ignore_triggers); @@ -403,3 +471,15 @@ CODE: OUTPUT: RETVAL +MODULE = Mouse PACKAGE = Mouse::Meta::Method::Constructor::XS + +CV* +_generate_constructor(...) +CODE: +{ + RETVAL = get_cvs("Mouse::Object::new", TRUE); + SvREFCNT_inc_simple_void_NN(RETVAL); +} +OUTPUT: + RETVAL + diff --git a/xs-src/MouseAccessor.xs b/xs-src/MouseAccessor.xs index 86b0b9f..ef5009a 100644 --- a/xs-src/MouseAccessor.xs +++ b/xs-src/MouseAccessor.xs @@ -37,7 +37,7 @@ mouse_instantiate_xs_accessor(pTHX_ SV* const attr, XSUBADDR_t const accessor_im mg = sv_magicext((SV*)xsub, MOUSE_xa_slot(xa), PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY); - MOUSE_mg_flags(mg) = (U16)SvUV(MOUSE_xa_flags(xa)); + MOUSE_mg_flags(mg) = (U16)MOUSE_xa_flags(xa); /* NOTE: * although we use MAGIC for gc, we also store mg to CvXSUBANY for efficiency (gfx) @@ -47,36 +47,6 @@ mouse_instantiate_xs_accessor(pTHX_ SV* const attr, XSUBADDR_t const accessor_im return xsub; } -static SV* -mouse_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; -} #define PUSH_VALUE(value, flags) STMT_START { \ if((flags) & MOUSEf_ATTR_SHOULD_AUTO_DEREF && GIMME_V == G_ARRAY){ \ @@ -140,36 +110,13 @@ mouse_push_values(pTHX_ SV* const value, U16 const flags){ static void mouse_attr_get(pTHX_ SV* const self, MAGIC* const mg){ U16 const flags = MOUSE_mg_flags(mg); - SV* const slot = MOUSE_mg_slot(mg); SV* value; - value = get_slot(self, slot); + value = get_slot(self, MOUSE_mg_slot(mg)); /* check_lazy */ if( !value && flags & MOUSEf_ATTR_IS_LAZY ){ - AV* const xa = MOUSE_mg_xa(mg); - SV* const attr = MOUSE_xa_attribute(xa); - - /* get default value by $attr->builder or $attr->default */ - if(flags & MOUSEf_ATTR_HAS_BUILDER){ - SV* const builder = mcall0s(attr, "builder"); - value = mcall0(self, builder); - } - else { - value = mcall0s(attr, "default"); - - if(IsCodeRef(value)){ - value = mcall0(self, value); - } - } - - /* apply coerce and type constraint */ - if(flags & MOUSEf_ATTR_HAS_TC){ - value = mouse_apply_type_constraint(aTHX_ xa, value, flags); - } - - /* store value to slot */ - value = set_slot(self, slot, value); + value = mouse_xa_set_default(aTHX_ MOUSE_mg_xa(mg), self); } PUSH_VALUE(value, flags); @@ -181,7 +128,7 @@ mouse_attr_set(pTHX_ SV* const self, MAGIC* const mg, SV* value){ SV* const slot = MOUSE_mg_slot(mg); if(flags & MOUSEf_ATTR_HAS_TC){ - value = mouse_apply_type_constraint(aTHX_ MOUSE_mg_xa(mg), value, flags); + value = mouse_xa_apply_type_constraint(aTHX_ MOUSE_mg_xa(mg), value, flags); } set_slot(self, slot, value); diff --git a/xs-src/MouseAttribute.xs b/xs-src/MouseAttribute.xs index 9bda4c6..62b2593 100644 --- a/xs-src/MouseAttribute.xs +++ b/xs-src/MouseAttribute.xs @@ -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