Commit | Line | Data |
a69b9501 |
1 | #include "mop.h" |
2 | |
353c6152 |
3 | |
8615de16 |
4 | static 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 | |
18 | MAGIC* |
19 | mop_accessor_get_mg(pTHX_ CV* const xsub){ |
20 | return mop_mg_find(aTHX_ (SV*)xsub, &mop_accessor_vtbl, MOPf_DIE_ON_FAIL); |
21 | } |
22 | |
23 | CV* |
80457d12 |
24 | mop_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 |
50 | CV* |
51 | mop_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 | |
72 | SV* |
73 | mop_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 | |
91 | XS(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 | |
112 | XS(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 | |
127 | XS(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 | |
140 | XS(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 | |
156 | XS(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 | |
170 | XS(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 | |
185 | MODULE = Class::MOP::Method::Accessor PACKAGE = Class::MOP::Method::Accessor |
186 | |
187 | PROTOTYPES: DISABLE |
188 | |
189 | BOOT: |
190 | INSTALL_SIMPLE_READER_WITH_KEY(Method::Accessor, associated_attribute, attribute); |
191 | INSTALL_SIMPLE_READER(Method::Accessor, accessor_type); |
192 | |
193 | |
194 | CV* |
353c6152 |
195 | _generate_accessor_method_xs(SV* self, void* instance_vtbl) |
a69b9501 |
196 | CODE: |
353c6152 |
197 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_accessor, instance_vtbl); |
a69b9501 |
198 | OUTPUT: |
199 | RETVAL |
200 | |
201 | CV* |
353c6152 |
202 | _generate_reader_method_xs(SV* self, void* instance_vtbl) |
a69b9501 |
203 | CODE: |
353c6152 |
204 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_reader, instance_vtbl); |
a69b9501 |
205 | OUTPUT: |
206 | RETVAL |
207 | |
208 | CV* |
353c6152 |
209 | _generate_writer_method_xs(SV* self, void* instance_vtbl) |
a69b9501 |
210 | CODE: |
353c6152 |
211 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_writer, instance_vtbl); |
a69b9501 |
212 | OUTPUT: |
213 | RETVAL |
214 | |
215 | CV* |
353c6152 |
216 | _generate_predicate_method_xs(SV* self, void* instance_vtbl) |
a69b9501 |
217 | CODE: |
353c6152 |
218 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_predicate, instance_vtbl); |
a69b9501 |
219 | OUTPUT: |
220 | RETVAL |
221 | |
222 | CV* |
353c6152 |
223 | _generate_clearer_method_xs(SV* self, void* instance_vtbl) |
a69b9501 |
224 | CODE: |
353c6152 |
225 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_clearer, instance_vtbl); |
a69b9501 |
226 | OUTPUT: |
227 | RETVAL |
228 | |