#endif /* MGf_LOCAL */
};
+STATIC MAGIC *stash_in_mg (pTHX_ SV *sv, SV *obj) {
+ MAGIC *mg = sv_magicext(sv, obj, PERL_MAGIC_ext, &null_mg_vtbl, NULL, 0 );
+ mg->mg_flags |= MGf_REFCOUNTED;
+
+ return mg;
+}
+
+STATIC SV *get_stashed_in_mg(pTHX_ SV *sv) {
+ MAGIC *mg, *moremagic;
+
+ if (SvTYPE(sv) >= SVt_PVMG) {
+ for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
+ if ((mg->mg_type == PERL_MAGIC_ext) && (mg->mg_virtual == &null_mg_vtbl))
+ break;
+ }
+ if (mg)
+ return mg->mg_obj;
+ }
+
+ return NULL;
+}
typedef enum {
CV *initializer;
CV *trigger;
- SV *attr; /* the meta attr object */
+ SV *meta_attr; /* the meta attr object */
AV *cvs; /* CVs which use this attr */
} ATTR;
#define ATTR_DUMB_WRITER(attr) ( ( attr->flags & ATTR_WRITING_MASK ) == 0 )
#define ATTR_DUMB_INSTANCE(attr) ( ( attr->flags & ATTR_INSTANCE_MASK ) == 0 )
-#define dATTR ATTR *attr = (INT2PTR(ATTR *, (XSANY.any_i32 || define_attr(aTHX_ cv))))
+#define dATTR ATTR *attr = (XSANY.any_i32 ? INT2PTR(ATTR *, (XSANY.any_i32)) : define_attr(aTHX_ cv))
/* FIXME define a vtable that does call_sv */
} instance_types;
typedef struct mi {
- SV *associated_metaclass;
HV *stash;
/* slot access method */
if ( !meta_attr ) croak("'meta' is required");
- attr->attr = *meta_attr;
+ attr->meta_attr = *meta_attr;
attr->mi = mi;
attr->cvs = newAV();
}
-STATIC MI *new_mi (pTHX_ HV *stash, SV *meta, AV *attrs) {
+STATIC MI *new_mi (pTHX_ HV *stash, AV *attrs) {
MI *mi;
I32 ix;
const I32 num = av_len(attrs) + 1;
SvREFCNT_inc_simple(stash);
mi->stash = stash;
- SvREFCNT_inc_simple(meta);
- mi->associated_metaclass = meta;
-
mi->type = 0; /* nothing else implemented yet */
/* initialize attributes */
mi->num_attrs = num;
Newx(mi->attrs, num, ATTR);
- for ( ix = 0; ix < mi->num_attrs; ix++ ) {
+ for ( ix = 0; ix < num; ix++ ) {
SV **desc = av_fetch(attrs, ix, 0);
- if ( !desc || !SvROK(*desc) || !(SvTYPE(SvRV(*desc)) == SVt_PVHV) )
+ if ( !desc || !*desc || !SvROK(*desc) || !(SvTYPE(SvRV(*desc)) == SVt_PVHV) ) {
croak("Attribute descriptor has to be a hash reference");
+ }
init_attr(mi, &mi->attrs[ix], (HV *)SvRV(*desc));
}
return mi;
}
-STATIC SV *get_meta_attr_from_mg(pTHX_ CV *cv) {
- MAGIC *mg, *moremagic;
+STATIC SV *new_mi_obj (pTHX_ MI *mi) {
+ return newRV_noinc(newSViv(PTR2IV(mi)));
+}
- if (SvTYPE(cv) >= SVt_PVMG) {
- for (mg = SvMAGIC(cv); mg; mg = mg->mg_moremagic) {
- if ((mg->mg_type == PERL_MAGIC_ext) && (mg->mg_virtual == &null_mg_vtbl))
- break;
+STATIC SV *attr_to_meta_instance(pTHX_ SV *meta_attr) {
+ dSP;
+ I32 count;
+ SV *mi;
+
+ if ( !meta_attr )
+ croak("No attr found in magic!");
+
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(meta_attr);
+ PUTBACK;
+ count = call_pv("Moose::XS::attr_to_meta_instance", G_SCALAR);
+
+ if ( count != 1 )
+ croak("attr_to_meta_instance borked (%d args returned, expecting 1)", count);
+
+ SPAGAIN;
+ mi = POPs;
+
+ SvREFCNT_inc(mi);
+
+ PUTBACK;
+ FREETMPS;
+ LEAVE;
+
+ return mi;
+}
+
+STATIC SV *perl_mi_to_c_mi(pTHX_ SV *perl_mi) {
+ dSP;
+ I32 count;
+ MI *mi = NULL;
+ SV *class;
+ SV *attrs;
+ HV *stash;
+
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(perl_mi);
+ PUTBACK;
+ count = call_pv("Moose::XS::meta_instance_to_attr_descs", G_ARRAY);
+
+ if ( count != 2 )
+ croak("meta_instance_to_attr_descs borked (%d args returned, expecting 2)", count);
+
+ SPAGAIN;
+ attrs = POPs;
+ class = POPs;
+
+ PUTBACK;
+
+ stash = gv_stashsv(class, 0);
+
+ mi = new_mi(aTHX_ stash, (AV *)SvRV(attrs));
+
+ FREETMPS;
+ LEAVE;
+
+ return new_mi_obj(aTHX_ mi);
+}
+
+STATIC ATTR *mi_find_attr(MI *mi, SV *meta_attr) {
+ I32 ix;
+
+ for ( ix = 0; ix <= mi->num_attrs; ix++ ) {
+ if ( SvRV(mi->attrs[ix].meta_attr) == SvRV(meta_attr) ) {
+ return &mi->attrs[ix];
}
- if (mg)
- return mg->mg_obj;
}
- croak("No attr found in magic!");
+ sv_dump(meta_attr);
+ croak("Attr not found");
return NULL;
}
STATIC ATTR *get_attr(pTHX_ CV *cv) {
- SV *meta_attr = get_meta_attr_from_mg(aTHX_ cv);
-
-#if 0
- my $mi = $meta_attr->associated_metaclass->get_meta_instance;
- my @attrs = map {
- {
- meta => $_,
- key => ($_->slots)[0],
- },
- } @{ $mi->attributes };
-#else
- croak("todo");
-#endif
+ SV *meta_attr = get_stashed_in_mg(aTHX_ (SV *)cv);
+ SV *perl_mi = attr_to_meta_instance(aTHX_ meta_attr);
+ SV *c_mi = get_stashed_in_mg(aTHX_ SvRV(perl_mi));
+ MI *mi;
- return NULL;
+ if (!c_mi) {
+ c_mi = perl_mi_to_c_mi(aTHX_ perl_mi);
+ stash_in_mg(aTHX_ perl_mi, c_mi);
+ }
+
+ sv_2mortal(perl_mi);
+
+ mi = INT2PTR(MI *, SvIV(SvRV(c_mi)));
+
+ return mi_find_attr(mi, meta_attr);
}
STATIC ATTR *define_attr (pTHX_ CV *cv) {
assert(attr);
XSANY.any_i32 = PTR2IV(attr);
- av_push( attr->cvs, cv );
+
+ av_push( attr->cvs, (SV *)cv );
return attr;
}
croak("Oi vey!");
/* associate CV with meta attr */
- (void)Perl_sv_magicext(aTHX_ (SV *)cv, attr, PERL_MAGIC_ext, &null_mg_vtbl, STR_WITH_LEN("Moose::Meta::Attribute") );
+ stash_in_mg(aTHX_ (SV *)cv, attr);
/* this will be set on first call */
XSANY.any_i32 = 0;
RETVAL
+MODULE = Moose PACKAGE = Moose::XS::Meta::Instance
+
+void
+DESTROY(self)
+ INPUT:
+ SV *self;
+ PREINIT:
+ MI *mi = INT2PTR(MI *, SvIV(SvRV(self)));
+ CODE:
+ /* foreach attr ( delete cvs XSANY ), free attrs free mi */