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