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 | |
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 |
36 | static CV* |
e989c0df |
37 | mop_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 | |
47 | SV* |
48 | mop_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 |
63 | SV** |
64 | mop_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 |
72 | XS(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 | |
93 | XS(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 | |
108 | XS(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 | |
121 | XS(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 | |
137 | XS(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 | |
151 | XS(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 | |
166 | MODULE = Class::MOP::Method::Accessor PACKAGE = Class::MOP::Method::Accessor |
167 | |
168 | PROTOTYPES: DISABLE |
169 | |
170 | BOOT: |
171 | INSTALL_SIMPLE_READER_WITH_KEY(Method::Accessor, associated_attribute, attribute); |
172 | INSTALL_SIMPLE_READER(Method::Accessor, accessor_type); |
173 | |
174 | |
175 | CV* |
e989c0df |
176 | _generate_accessor_method_xs(SV* self, void* instance_vtbl) |
206860b8 |
177 | CODE: |
e989c0df |
178 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_accessor, instance_vtbl); |
206860b8 |
179 | OUTPUT: |
180 | RETVAL |
181 | |
182 | CV* |
e989c0df |
183 | _generate_reader_method_xs(SV* self, void* instance_vtbl) |
206860b8 |
184 | CODE: |
e989c0df |
185 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_reader, instance_vtbl); |
206860b8 |
186 | OUTPUT: |
187 | RETVAL |
188 | |
189 | CV* |
e989c0df |
190 | _generate_writer_method_xs(SV* self, void* instance_vtbl) |
206860b8 |
191 | CODE: |
e989c0df |
192 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_writer, instance_vtbl); |
206860b8 |
193 | OUTPUT: |
194 | RETVAL |
195 | |
196 | CV* |
e989c0df |
197 | _generate_predicate_method_xs(SV* self, void* instance_vtbl) |
206860b8 |
198 | CODE: |
e989c0df |
199 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_predicate, instance_vtbl); |
206860b8 |
200 | OUTPUT: |
201 | RETVAL |
202 | |
203 | CV* |
e989c0df |
204 | _generate_clearer_method_xs(SV* self, void* instance_vtbl) |
206860b8 |
205 | CODE: |
e989c0df |
206 | RETVAL = mop_instantiate_xs_accessor(aTHX_ self, mop_xs_simple_clearer, instance_vtbl); |
206860b8 |
207 | OUTPUT: |
208 | RETVAL |
209 | |