Initial version of Moose::XS
[gitmo/Moose.git] / Moose.xs
CommitLineData
1ea12c91 1#include "EXTERN.h"
2#include "perl.h"
3#include "XSUB.h"
4
5#define SLOT_WEAKEN 0x01
6
7/* FIXME
8 * needs to be made into Moose::XS::Meta::Instance and Meta::Slot for the
9 * metadata, with a proper destructor. XSANY still points to this struct, but
10 * it is shared by all functions of the same type.
11 *
12 * Instance contains SvSTASH, and SLOT slots[]
13 *
14 * On recreation of the meta instance we refresh the SLOT value of all the CVs
15 * we installed
16 *
17 * need a good way to handle time between invalidate and regeneration (just
18 * check XSANY and call get_meta_instance if null?)
19 */
20
21
22/* FIXME
23 * slot access is one of 4 values in flags:
24 * 0 == hash
25 * 1 == array
26 * 3 == fptr (allows access into C structs, etc)
27 * 4 == callsv (really a special case of fptr)
28 *
29 * for fptr case we have a pointer to a vtable for get/set/has/delete, all of which take the same args as set_slot_value
30 */
31
32/* FIXME
33 * type constraints are already implemented by konobi
34 * should be trivial to do coercions for the core types, too
35 *
36 * TypeConstraint::Class can compare SvSTASH by ptr, and if it's neq *then*
37 * call ->isa (should handle vast majority of cases)
38 *
39 * base parametrized types are also trivial
40 *
41 * ClassName is get_stathpvn
42 */
43
44/* FIXME
45 * for a constructor we have SLOT *slots, and iterate that, removing init_arg
46 * we can preallocate the structure to the right size (maybe even with the
47 * right HEs?), and do various other prehashing hacks to gain speed
48 * */
49
50/* FIXME
51 * delegations and attribute helpers:
52 *
53 * typedef struct {
54 * SLOT *slot;
55 * pv *method;
56 * } delegation;
57 *
58 * typedef struct {
59 * SLOT *slot;
60 * I32 *type; // hash, array, whatever + vtable for operation
61 * } attributehelper;
62 */
63
64typedef struct {
65 U32 hash;
66 SV *sv;
67 U32 flags /* slot type, TC behavior, coerce, weaken, (no default | default, builder + lazy), auto_deref */
68 /* FIXME
69 * type constraint (pointer or enum union)
70 * default / builder ptr (or SV *)
71 * initializer
72 */
73} SLOT;
74
75#define dSLOT SLOT *slot = INT2PTR(SLOT *, XSANY.any_i32)
76
77/* utility functions */
78
79STATIC SLOT *new_slot_from_key (SV *key, U32 flags) {
80 SLOT *slot = (SLOT *)malloc(sizeof(SLOT));
81 U32 hash;
82 STRLEN len;
83 char *pv = SvPV(key, len);
84
85 PERL_HASH(hash, pv, len);
86 slot->sv = newSVpvn_share(pv, len, hash);
87 slot->hash = hash;
88 slot->flags = flags;
89
90 return slot;
91}
92
93STATIC void weaken(SV *sv) {
94#ifdef SvWEAKREF
95 sv_rvweaken(sv);
96#else
97 croak("weak references are not implemented in this release of perl");
98#endif
99}
100
101
102/* meta instance protocol */
103
104STATIC SV *get_slot_value(SV *self, SLOT *slot) {
105 HE *he;
106
107 assert(self);
108 assert(SvROK(self));
109 assert(SvTYPE(SvRV(self)) == SVt_PVHV);
110
111 if (he = hv_fetch_ent((HV *)SvRV(self), slot->sv, 0, slot->hash))
112 return HeVAL(he);
113 else
114 return NULL;
115}
116
117STATIC void set_slot_value(SV *self, SLOT *slot, SV *value) {
118 HE *he;
119
120 assert(self);
121 assert(SvROK(self));
122 assert(SvTYPE(SvRV(self)) == SVt_PVHV);
123
124 SvREFCNT_inc(value);
125
126 he = hv_store_ent((HV*)SvRV(self), slot->sv, value, slot->hash);
127 if (he != NULL) {
128 if ( slot->flags & SLOT_WEAKEN )
129 weaken(HeVAL(he));
130 } else {
131 croak("Hash store failed.");
132 }
133}
134
135STATIC bool has_slot_value(SV *self, SLOT *slot) {
136 assert(self);
137 assert(SvROK(self));
138 assert(SvTYPE(SvRV(self)) == SVt_PVHV);
139
140 return hv_exists_ent((HV *)SvRV(self), slot->sv, slot->hash);
141}
142
143
144/* simple high level api */
145
146STATIC XS(simple_getter);
147STATIC XS(simple_getter)
148{
149#ifdef dVAR
150 dVAR;
151#endif
152 dXSARGS;
153 dSLOT;
154 SV *value;
155
156 if (items != 1)
157 Perl_croak(aTHX_ "Usage: %s(%s)", GvNAME(CvGV(cv)), "self");
158
159 SP -= items;
160
161 value = get_slot_value(ST(0), slot);
162
163 if (value) {
164 ST(0) = sv_mortalcopy(value); /* mortalcopy because $_ .= "blah" for $foo->bar */
165 XSRETURN(1);
166 } else {
167 XSRETURN_UNDEF;
168 }
169}
170
171STATIC XS(simple_setter);
172STATIC XS(simple_setter)
173{
174#ifdef dVAR
175 dVAR;
176#endif
177 dXSARGS;
178 dSLOT;
179
180 if (items != 2)
181 Perl_croak(aTHX_ "Usage: %s(%s, %s)", GvNAME(CvGV(cv)), "self", "value");
182
183 SP -= items;
184
185 set_slot_value(ST(0), slot, ST(1));
186
187 ST(0) = ST(1); /* return value */
188 XSRETURN(1);
189}
190
191STATIC XS(simple_accessor);
192STATIC XS(simple_accessor)
193{
194#ifdef dVAR
195 dVAR;
196#endif
197 dXSARGS;
198 dSLOT;
199
200 if (items < 1)
201 Perl_croak(aTHX_ "Usage: %s(%s, [ %s ])", GvNAME(CvGV(cv)), "self", "value");
202
203 SP -= items;
204
205 if (items > 1) {
206 set_slot_value(ST(0), slot, ST(1));
207 ST(0) = ST(1); /* return value */
208 } else {
209 SV *value = get_slot_value(ST(0), slot);
210 if ( value ) {
211 ST(0) = value;
212 } else {
213 XSRETURN_UNDEF;
214 }
215 }
216
217 XSRETURN(1);
218}
219
220STATIC XS(predicate);
221STATIC XS(predicate)
222{
223#ifdef dVAR
224 dVAR;
225#endif
226 dXSARGS;
227 dSLOT;
228
229 if (items != 1)
230 Perl_croak(aTHX_ "Usage: %s(%s)", GvNAME(CvGV(cv)), "self");
231
232 SP -= items;
233
234 if ( has_slot_value(ST(0), slot) )
235 XSRETURN_YES;
236 else
237 XSRETURN_NO;
238}
239
240enum xs_body {
241 xs_body_simple_getter = 0,
242 xs_body_simple_setter,
243 xs_body_simple_accessor,
244 xs_body_predicate,
245 max_xs_body
246};
247
248STATIC XSPROTO ((*xs_bodies[])) = {
249 simple_getter,
250 simple_setter,
251 simple_accessor,
252 predicate,
253};
254
255MODULE = Moose PACKAGE = Moose::XS
256
257CV *
258install_sub(name, key)
259 INPUT:
260 char *name;
261 SV *key;
262 ALIAS:
263 install_simple_getter = xs_body_simple_getter
264 install_simple_setter = xs_body_simple_setter
265 install_simple_accessor = xs_body_simple_accessor
266 install_predicate = xs_body_predicate
267 PREINIT:
268 CV * cv;
269 CODE:
270 if ( ix >= max_xs_body )
271 croak("Unknown Moose::XS body type");
272
273 cv = newXS(name, xs_bodies[ix], __FILE__);
274
275 if (cv == NULL)
276 croak("Oi vey!");
277
278 /* FIXME leaks, fail for anon classes */
279 XSANY.any_i32 = PTR2IV(new_slot_from_key(key, 0));
280
281 RETVAL = cv;
282 OUTPUT:
283 RETVAL
284
285