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