Refactor MOP Instance API in XS
[gitmo/Class-MOP.git] / xs / MethodAccessor.xs
CommitLineData
206860b8 1#include "mop.h"
2
e989c0df 3
4static MGVTBL mop_accessor_vtbl; /* the MAGIC identity */
5
6MAGIC*
7mop_accessor_get_mg(pTHX_ CV* const xsub){
8 return mop_mg_find(aTHX_ (SV*)xsub, &mop_accessor_vtbl, MOPf_DIE_ON_FAIL);
9}
10
11CV*
12mop_install_accessor(pTHX_ const char* const fq_name, const char* const key, I32 const keylen, XSPROTO(accessor_impl), const mop_instance_vtbl* vtbl){
13 CV* const xsub = newXS((char*)fq_name, accessor_impl, __FILE__);
14 SV* const keysv = newSVpvn_share(key, keylen, 0U);
15 AV* const meta = newAV();
d83eddd0 16 MAGIC* mg;
e989c0df 17
18 if(!vtbl){
19 vtbl = mop_get_default_instance_vtbl(aTHX);
20 }
21
d83eddd0 22 mg = sv_magicext((SV*)xsub, (SV*)meta, PERL_MAGIC_ext, &mop_accessor_vtbl, (char*)vtbl, 0);
e989c0df 23 SvREFCNT_dec(meta); /* sv_magicext() increases refcnt in mg_obj */
24
d83eddd0 25 av_store(meta, MOP_MI_SLOT, keysv);
26
27 /* NOTE:
28 * although we use MAGIC for gc, we also store mg to any slot for efficiency (gfx)
29 */
30 CvXSUBANY(xsub).any_ptr = (void*)mg;
e989c0df 31
32 return xsub;
33}
34
35
206860b8 36static CV*
e989c0df 37mop_instantiate_xs_accessor(pTHX_ SV* const accessor, XSPROTO(accessor_impl), mop_instance_vtbl* const vtbl){
38 /* $key = $accessor->associated_attribute->name */
39 SV* const attr = mop_call0(aTHX_ accessor, mop_associated_attribute);
40 SV* const key = mop_call0(aTHX_ attr, mop_name);
41 STRLEN klen;
42 const char* const kpv = SvPV_const(key, klen);
43
44 return mop_install_accessor(aTHX_ NULL /* anonymous */, kpv, klen, accessor_impl, vtbl);
45}
46
47SV*
48mop_accessor_get_self(pTHX_ I32 const ax, I32 const items, CV* const cv) {
49 SV* self;
50
51 if(items < 1){
52 croak("too few arguments for %s", GvNAME(CvGV(cv)));
53 }
54
55 self = ST(0);
56 if(!(SvROK(self) && SvOBJECT(SvRV(self)))){
57 croak("cant call %s as a class method", GvNAME(CvGV(cv)));
58 }
59 return self;
60}
61
d83eddd0 62#ifdef DEBUGGING
63SV**
64mop_debug_mi_access(pTHX_ AV* const mi, I32 const attr_ix){
65 assert(mi);
66 assert(SvTYPE(mi) == SVt_PVAV);
67 assert(AvMAX(mi) >= attr_ix);
68 return &AvARRAY(mi)[attr_ix];
69}
70#endif
71
e989c0df 72XS(mop_xs_simple_accessor)
73{
74 dVAR; dXSARGS;
75 dMOP_METHOD_COMMON; /* self, mg */
76 SV* value;
d83eddd0 77
e989c0df 78 if(items == 1){ /* reader */
d83eddd0 79 value = MOP_mg_get_slot(mg, self);
e989c0df 80 }
81 else if (items == 2){ /* writer */
d83eddd0 82 value = MOP_mg_set_slot(mg, self, ST(1));
e989c0df 83 }
84 else{
85 croak("expected exactly one or two argument");
86 }
87
88 ST(0) = value ? value : &PL_sv_undef;
89 XSRETURN(1);
90}
91
92
93XS(mop_xs_simple_reader)
94{
95 dVAR; dXSARGS;
96 dMOP_METHOD_COMMON; /* self, mg */
97 SV* value;
98
99 if (items != 1) {
100 croak("expected exactly one argument");
101 }
102
d83eddd0 103 value = MOP_mg_get_slot(mg, self);
e989c0df 104 ST(0) = value ? value : &PL_sv_undef;
105 XSRETURN(1);
106}
107
108XS(mop_xs_simple_writer)
109{
110 dVAR; dXSARGS;
111 dMOP_METHOD_COMMON; /* self, mg */
112
113 if (items != 2) {
114 croak("expected exactly two argument");
115 }
116
d83eddd0 117 ST(0) = MOP_mg_set_slot(mg, self, ST(1));
e989c0df 118 XSRETURN(1);
119}
120
121XS(mop_xs_simple_clearer)
122{
123 dVAR; dXSARGS;
124 dMOP_METHOD_COMMON; /* self, mg */
125 SV* value;
126
127 if (items != 1) {
128 croak("expected exactly one argument");
129 }
130
d83eddd0 131 value = MOP_mg_delete_slot(mg, self);
e989c0df 132 ST(0) = value ? value : &PL_sv_undef;
133 XSRETURN(1);
134}
135
136
137XS(mop_xs_simple_predicate)
138{
139 dVAR; dXSARGS;
140 dMOP_METHOD_COMMON; /* self, mg */
141
142 if (items != 1) {
143 croak("expected exactly one argument");
144 }
145
d83eddd0 146 ST(0) = boolSV( MOP_mg_has_slot(mg, self) );
e989c0df 147 XSRETURN(1);
148}
149
150
151XS(mop_xs_simple_predicate_for_metaclass)
152{
153 dVAR; dXSARGS;
154 dMOP_METHOD_COMMON; /* self, mg */
155 SV* value;
156
157 if (items != 1) {
158 croak("expected exactly one argument");
159 }
160
d83eddd0 161 value = MOP_mg_get_slot(mg, self);
e989c0df 162 ST(0) = boolSV( value && SvOK(value ));
163 XSRETURN(1);
206860b8 164}
165
166MODULE = Class::MOP::Method::Accessor PACKAGE = Class::MOP::Method::Accessor
167
168PROTOTYPES: DISABLE
169
170BOOT:
171 INSTALL_SIMPLE_READER_WITH_KEY(Method::Accessor, associated_attribute, attribute);
172 INSTALL_SIMPLE_READER(Method::Accessor, accessor_type);
173
174
175CV*
e989c0df 176_generate_accessor_method_xs(SV* self, void* instance_vtbl)
206860b8 177CODE:
e989c0df 178 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_accessor, instance_vtbl);
206860b8 179OUTPUT:
180 RETVAL
181
182CV*
e989c0df 183_generate_reader_method_xs(SV* self, void* instance_vtbl)
206860b8 184CODE:
e989c0df 185 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_reader, instance_vtbl);
206860b8 186OUTPUT:
187 RETVAL
188
189CV*
e989c0df 190_generate_writer_method_xs(SV* self, void* instance_vtbl)
206860b8 191CODE:
e989c0df 192 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_writer, instance_vtbl);
206860b8 193OUTPUT:
194 RETVAL
195
196CV*
e989c0df 197_generate_predicate_method_xs(SV* self, void* instance_vtbl)
206860b8 198CODE:
e989c0df 199 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_predicate, instance_vtbl);
206860b8 200OUTPUT:
201 RETVAL
202
203CV*
e989c0df 204_generate_clearer_method_xs(SV* self, void* instance_vtbl)
206860b8 205CODE:
e989c0df 206 RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_clearer, instance_vtbl);
206860b8 207OUTPUT:
208 RETVAL
209