Commit | Line | Data |
646c0371 |
1 | #include "mouse.h" |
2 | |
3 | #define CHECK_INSTANCE(instance) STMT_START{ \ |
4 | if(!(SvROK(instance) && SvTYPE(SvRV(instance)) == SVt_PVHV)){ \ |
76770976 |
5 | croak("Invalid object instance"); \ |
646c0371 |
6 | } \ |
7 | } STMT_END |
8 | |
9 | /* Moose XS Attribute object */ |
10 | enum mouse_xa_ix_t{ |
11 | MOUSE_XA_ATTRIBUTE, |
12 | MOUSE_XA_TC, |
13 | MOUSE_XA_TC_CODE, |
14 | |
15 | MOUSE_XA_last |
16 | }; |
17 | |
18 | #define MOUSE_xa_attribute(m) MOUSE_av_at(m, MOUSE_XA_ATTRIBUTE) |
19 | #define MOUSE_xa_tc(m) MOUSE_av_at(m, MOUSE_XA_TC) |
20 | #define MOUSE_xa_tc_code(m) MOUSE_av_at(m, MOUSE_XA_TC_CODE) |
21 | |
22 | #define MOUSE_mg_attribute(mg) MOUSE_xa_attribute(MOUSE_mg_xa(mg)) |
23 | |
24 | enum mouse_xa_flags_t{ |
25 | MOUSEf_ATTR_HAS_TC = 0x0001, |
26 | MOUSEf_ATTR_HAS_DEFAULT = 0x0002, |
27 | MOUSEf_ATTR_HAS_BUILDER = 0x0004, |
28 | MOUSEf_ATTR_HAS_INITIALIZER = 0x0008, /* not used in Mouse */ |
29 | MOUSEf_ATTR_HAS_TRIGGER = 0x0010, |
30 | |
31 | MOUSEf_ATTR_IS_LAZY = 0x0020, |
32 | MOUSEf_ATTR_IS_WEAK_REF = 0x0040, |
33 | MOUSEf_ATTR_IS_REQUIRED = 0x0080, |
34 | |
35 | MOUSEf_ATTR_SHOULD_COERCE = 0x0100, |
36 | |
37 | MOUSEf_ATTR_SHOULD_AUTO_DEREF |
38 | = 0x0200, |
39 | MOUSEf_TC_IS_ARRAYREF = 0x0400, |
40 | MOUSEf_TC_IS_HASHREF = 0x0800, |
41 | |
42 | MOUSEf_OTHER1 = 0x1000, |
43 | MOUSEf_OTHER2 = 0x2000, |
44 | MOUSEf_OTHER3 = 0x4000, |
45 | MOUSEf_OTHER4 = 0x8000, |
46 | |
47 | MOUSEf_MOUSE_MASK = 0xFFFF /* not used */ |
48 | }; |
49 | |
50 | static MGVTBL mouse_accessor_vtbl; /* MAGIC identity */ |
51 | |
52 | |
53 | SV* |
54 | mouse_accessor_get_self(pTHX_ I32 const ax, I32 const items, CV* const cv) { |
646c0371 |
55 | if(items < 1){ |
56 | croak("Too few arguments for %s", GvNAME(CvGV(cv))); |
57 | } |
58 | |
59 | /* NOTE: If self has GETMAGIC, $self->accessor will invoke GETMAGIC |
60 | * before calling methods, so SvGETMAGIC(self) is not necessarily needed here. |
61 | */ |
62 | |
76770976 |
63 | return ST(0); |
646c0371 |
64 | } |
65 | |
66 | |
67 | CV* |
68 | mouse_instantiate_xs_accessor(pTHX_ SV* const attr, XSUBADDR_t const accessor_impl){ |
69 | SV* const slot = mcall0(attr, mouse_name); |
70 | AV* const xa = newAV(); |
71 | CV* xsub; |
72 | MAGIC* mg; |
73 | U16 flags = 0; |
74 | |
75 | sv_2mortal((SV*)xa); |
76 | |
77 | xsub = newXS(NULL, accessor_impl, __FILE__); |
78 | sv_2mortal((SV*)xsub); |
79 | |
80 | mg = sv_magicext((SV*)xsub, slot, PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY); |
81 | |
82 | /* NOTE: |
83 | * although we use MAGIC for gc, we also store mg to CvXSUBANY for efficiency (gfx) |
84 | */ |
85 | CvXSUBANY(xsub).any_ptr = (void*)mg; |
86 | |
87 | av_extend(xa, MOUSE_XA_last - 1); |
88 | |
89 | av_store(xa, MOUSE_XA_ATTRIBUTE, newSVsv(attr)); |
90 | |
91 | /* prepare attribute status */ |
92 | /* XXX: making it lazy is a good way? */ |
93 | |
94 | if(SvTRUEx(mcall0s(attr, "has_type_constraint"))){ |
95 | SV* tc; |
96 | flags |= MOUSEf_ATTR_HAS_TC; |
97 | |
98 | ENTER; |
99 | SAVETMPS; |
100 | |
101 | tc = mcall0s(attr, "type_constraint"); |
102 | av_store(xa, MOUSE_XA_TC, newSVsv(tc)); |
103 | |
104 | if(SvTRUEx(mcall0s(attr, "should_auto_deref"))){ |
105 | flags |= MOUSEf_ATTR_SHOULD_AUTO_DEREF; |
106 | if( SvTRUEx(mcall1s(tc, "is_a_type_of", newSVpvs_flags("ArrayRef", SVs_TEMP))) ){ |
107 | flags |= MOUSEf_TC_IS_ARRAYREF; |
108 | } |
109 | else if( SvTRUEx(mcall1s(tc, "is_a_type_of", newSVpvs_flags("HashRef", SVs_TEMP))) ){ |
110 | flags |= MOUSEf_TC_IS_HASHREF; |
111 | } |
112 | else{ |
113 | mouse_throw_error(attr, tc, |
114 | "Can not auto de-reference the type constraint '%"SVf"'", |
115 | mcall0(tc, mouse_name)); |
116 | } |
117 | } |
118 | |
119 | if(SvTRUEx(mcall0s(attr, "should_coerce"))){ |
120 | flags |= MOUSEf_ATTR_SHOULD_COERCE; |
121 | } |
122 | |
123 | FREETMPS; |
124 | LEAVE; |
125 | } |
126 | |
127 | if(SvTRUEx(mcall0s(attr, "has_trigger"))){ |
128 | flags |= MOUSEf_ATTR_HAS_TRIGGER; |
129 | } |
130 | |
131 | if(SvTRUEx(mcall0s(attr, "is_lazy"))){ |
132 | flags |= MOUSEf_ATTR_IS_LAZY; |
133 | |
134 | if(SvTRUEx(mcall0s(attr, "has_builder"))){ |
135 | flags |= MOUSEf_ATTR_HAS_BUILDER; |
136 | } |
137 | else if(SvTRUEx(mcall0s(attr, "has_default"))){ |
138 | flags |= MOUSEf_ATTR_HAS_DEFAULT; |
139 | } |
140 | } |
141 | |
142 | if(SvTRUEx(mcall0s(attr, "is_weak_ref"))){ |
143 | flags |= MOUSEf_ATTR_IS_WEAK_REF; |
144 | } |
145 | |
146 | if(SvTRUEx(mcall0s(attr, "is_required"))){ |
147 | flags |= MOUSEf_ATTR_IS_REQUIRED; |
148 | } |
149 | |
150 | MOUSE_mg_flags(mg) = flags; |
151 | |
152 | return xsub; |
153 | } |
154 | |
155 | static SV* |
156 | mouse_apply_type_constraint(pTHX_ AV* const xa, SV* value, U16 const flags){ |
157 | SV* const tc = MOUSE_xa_tc(xa); |
158 | SV* tc_code; |
159 | |
160 | if(flags & MOUSEf_ATTR_SHOULD_COERCE){ |
161 | value = mcall1s(tc, "coerce", value); |
162 | } |
163 | |
164 | if(!SvOK(MOUSE_xa_tc_code(xa))){ |
646c0371 |
165 | tc_code = mcall0s(tc, "_compiled_type_constraint"); |
d33d8840 |
166 | av_store(xa, MOUSE_XA_TC_CODE, newSVsv(tc_code)); |
263728b5 |
167 | |
80aa5731 |
168 | if(!IsCodeRef(tc_code)){ |
d33d8840 |
169 | mouse_throw_error(MOUSE_xa_attribute(xa), tc, "Not a CODE reference"); |
646c0371 |
170 | } |
171 | } |
172 | else{ |
173 | tc_code = MOUSE_xa_tc_code(xa); |
174 | } |
175 | |
176 | if(!mouse_tc_check(aTHX_ tc_code, value)){ |
177 | mouse_throw_error(MOUSE_xa_attribute(xa), value, |
178 | "Attribute (%"SVf") does not pass the type constraint because: %"SVf, |
179 | mcall0(MOUSE_xa_attribute(xa), mouse_name), |
180 | mcall1s(tc, "get_message", value)); |
181 | } |
182 | |
183 | return value; |
184 | } |
185 | |
208ffaeb |
186 | #define PUSH_VALUE(value, flags) STMT_START { \ |
187 | if((flags) & MOUSEf_ATTR_SHOULD_AUTO_DEREF && GIMME_V == G_ARRAY){ \ |
188 | mouse_push_values(aTHX_ value, (flags)); \ |
189 | } \ |
190 | else{ \ |
191 | dSP; \ |
192 | XPUSHs(value ? value : &PL_sv_undef); \ |
193 | PUTBACK; \ |
194 | } \ |
195 | } STMT_END \ |
646c0371 |
196 | |
197 | /* pushes return values, does auto-deref if needed */ |
198 | static void |
199 | mouse_push_values(pTHX_ SV* const value, U16 const flags){ |
200 | dSP; |
201 | |
208ffaeb |
202 | assert( flags & MOUSEf_ATTR_SHOULD_AUTO_DEREF && GIMME_V == G_ARRAY ); |
646c0371 |
203 | |
208ffaeb |
204 | if(!(value && SvOK(value))){ |
205 | return; |
206 | } |
646c0371 |
207 | |
208ffaeb |
208 | if(flags & MOUSEf_TC_IS_ARRAYREF){ |
80aa5731 |
209 | AV* av; |
208ffaeb |
210 | I32 len; |
211 | I32 i; |
646c0371 |
212 | |
80aa5731 |
213 | if(!IsArrayRef(value)){ |
208ffaeb |
214 | croak("Mouse-panic: Not an ARRAY reference"); |
646c0371 |
215 | } |
646c0371 |
216 | |
80aa5731 |
217 | av = (AV*)SvRV(value); |
208ffaeb |
218 | len = av_len(av) + 1; |
219 | EXTEND(SP, len); |
220 | for(i = 0; i < len; i++){ |
221 | SV** const svp = av_fetch(av, i, FALSE); |
222 | PUSHs(svp ? *svp : &PL_sv_undef); |
646c0371 |
223 | } |
224 | } |
208ffaeb |
225 | else if(flags & MOUSEf_TC_IS_HASHREF){ |
80aa5731 |
226 | HV* hv; |
208ffaeb |
227 | HE* he; |
228 | |
80aa5731 |
229 | if(!IsHashRef(value)){ |
208ffaeb |
230 | croak("Mouse-panic: Not a HASH reference"); |
231 | } |
232 | |
80aa5731 |
233 | hv = (HV*)SvRV(value); |
208ffaeb |
234 | hv_iterinit(hv); |
235 | while((he = hv_iternext(hv))){ |
236 | EXTEND(SP, 2); |
237 | PUSHs(hv_iterkeysv(he)); |
238 | PUSHs(hv_iterval(hv, he)); |
239 | } |
646c0371 |
240 | } |
241 | |
242 | PUTBACK; |
243 | } |
244 | |
245 | static void |
246 | mouse_attr_get(pTHX_ SV* const self, MAGIC* const mg){ |
247 | U16 const flags = MOUSE_mg_flags(mg); |
248 | SV* const slot = MOUSE_mg_slot(mg); |
249 | SV* value; |
250 | |
6fe2272b |
251 | value = get_slot(self, slot); |
646c0371 |
252 | |
253 | /* check_lazy */ |
254 | if( !value && flags & MOUSEf_ATTR_IS_LAZY ){ |
8fa5f9b8 |
255 | AV* const xa = MOUSE_mg_xa(mg); |
646c0371 |
256 | SV* const attr = MOUSE_xa_attribute(xa); |
257 | |
8fa5f9b8 |
258 | /* get default value by $attr->builder or $attr->default */ |
259 | if(flags & MOUSEf_ATTR_HAS_BUILDER){ |
260 | SV* const builder = mcall0s(attr, "builder"); |
261 | value = mcall0(self, builder); |
262 | } |
263 | else { |
646c0371 |
264 | value = mcall0s(attr, "default"); |
265 | |
80aa5731 |
266 | if(IsCodeRef(value)){ |
646c0371 |
267 | value = mcall0(self, value); |
268 | } |
269 | } |
646c0371 |
270 | |
271 | /* apply coerce and type constraint */ |
272 | if(flags & MOUSEf_ATTR_HAS_TC){ |
273 | value = mouse_apply_type_constraint(aTHX_ xa, value, flags); |
274 | } |
275 | |
276 | /* store value to slot */ |
6fe2272b |
277 | value = set_slot(self, slot, value); |
646c0371 |
278 | } |
279 | |
208ffaeb |
280 | PUSH_VALUE(value, flags); |
646c0371 |
281 | } |
282 | |
283 | static void |
284 | mouse_attr_set(pTHX_ SV* const self, MAGIC* const mg, SV* value){ |
285 | U16 const flags = MOUSE_mg_flags(mg); |
286 | SV* const slot = MOUSE_mg_slot(mg); |
287 | |
288 | if(flags & MOUSEf_ATTR_HAS_TC){ |
289 | value = mouse_apply_type_constraint(aTHX_ MOUSE_mg_xa(mg), value, flags); |
290 | } |
291 | |
6fe2272b |
292 | set_slot(self, slot, value); |
646c0371 |
293 | |
294 | if(flags & MOUSEf_ATTR_IS_WEAK_REF){ |
6fe2272b |
295 | weaken_slot(self, slot); |
646c0371 |
296 | } |
297 | |
298 | if(flags & MOUSEf_ATTR_HAS_TRIGGER){ |
299 | SV* const trigger = mcall0s(MOUSE_mg_attribute(mg), "trigger"); |
300 | dSP; |
301 | |
302 | PUSHMARK(SP); |
303 | EXTEND(SP, 2); |
304 | PUSHs(self); |
305 | PUSHs(value); |
306 | |
307 | PUTBACK; |
308 | call_sv(trigger, G_VOID | G_DISCARD); |
309 | /* need not SPAGAIN */ |
310 | } |
311 | |
208ffaeb |
312 | PUSH_VALUE(value, flags); |
646c0371 |
313 | } |
314 | |
30e11004 |
315 | XS(XS_Mouse_accessor) |
646c0371 |
316 | { |
317 | dVAR; dXSARGS; |
318 | dMOUSE_self; |
319 | MAGIC* const mg = (MAGIC*)XSANY.any_ptr; |
320 | |
321 | SP -= items; /* PPCODE */ |
322 | PUTBACK; |
323 | |
324 | if(items == 1){ /* reader */ |
325 | mouse_attr_get(aTHX_ self, mg); |
326 | } |
327 | else if (items == 2){ /* writer */ |
328 | mouse_attr_set(aTHX_ self, mg, ST(1)); |
329 | } |
330 | else{ |
331 | mouse_throw_error(MOUSE_mg_attribute(mg), NULL, |
332 | "Expected exactly one or two argument for an accessor"); |
333 | } |
334 | } |
335 | |
336 | |
30e11004 |
337 | XS(XS_Mouse_reader) |
646c0371 |
338 | { |
339 | dVAR; dXSARGS; |
340 | dMOUSE_self; |
341 | MAGIC* const mg = (MAGIC*)XSANY.any_ptr; |
342 | |
343 | if (items != 1) { |
344 | mouse_throw_error(MOUSE_mg_attribute(mg), NULL, |
345 | "Cannot assign a value to a read-only accessor"); |
346 | } |
347 | |
348 | SP -= items; /* PPCODE */ |
349 | PUTBACK; |
350 | |
351 | mouse_attr_get(aTHX_ self, mg); |
352 | } |
353 | |
30e11004 |
354 | XS(XS_Mouse_writer) |
646c0371 |
355 | { |
356 | dVAR; dXSARGS; |
357 | dMOUSE_self; |
358 | MAGIC* const mg = (MAGIC*)XSANY.any_ptr; |
359 | |
360 | if (items != 2) { |
361 | mouse_throw_error(MOUSE_mg_attribute(mg), NULL, |
362 | "Too few arguments for a write-only accessor"); |
363 | } |
364 | |
365 | SP -= items; /* PPCODE */ |
366 | PUTBACK; |
367 | |
368 | mouse_attr_set(aTHX_ self, mg, ST(1)); |
369 | } |
370 | |
371 | /* simple accessors */ |
372 | |
373 | /* |
374 | static MAGIC* |
375 | mouse_accessor_get_mg(pTHX_ CV* const xsub){ |
376 | return moose_mg_find(aTHX_ (SV*)xsub, &mouse_simple_accessor_vtbl, MOOSEf_DIE_ON_FAIL); |
377 | } |
378 | */ |
379 | |
380 | CV* |
381 | mouse_install_simple_accessor(pTHX_ const char* const fq_name, const char* const key, I32 const keylen, XSUBADDR_t const accessor_impl){ |
382 | CV* const xsub = newXS((char*)fq_name, accessor_impl, __FILE__); |
383 | SV* const slot = newSVpvn_share(key, keylen, 0U); |
384 | MAGIC* mg; |
385 | |
386 | if(!fq_name){ |
387 | /* anonymous xsubs need sv_2mortal */ |
388 | sv_2mortal((SV*)xsub); |
389 | } |
390 | |
391 | mg = sv_magicext((SV*)xsub, slot, PERL_MAGIC_ext, &mouse_accessor_vtbl, NULL, 0); |
392 | SvREFCNT_dec(slot); /* sv_magicext() increases refcnt in mg_obj */ |
393 | |
394 | /* NOTE: |
395 | * although we use MAGIC for gc, we also store mg to CvXSUBANY for efficiency (gfx) |
396 | */ |
397 | CvXSUBANY(xsub).any_ptr = (void*)mg; |
398 | |
399 | return xsub; |
400 | } |
401 | |
30e11004 |
402 | XS(XS_Mouse_simple_reader) |
646c0371 |
403 | { |
404 | dVAR; dXSARGS; |
405 | dMOUSE_self; |
406 | SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); |
407 | SV* value; |
408 | |
409 | if (items != 1) { |
410 | croak("Expected exactly one argument for a reader for '%"SVf"'", slot); |
411 | } |
412 | |
6fe2272b |
413 | value = get_slot(self, slot); |
646c0371 |
414 | ST(0) = value ? value : &PL_sv_undef; |
415 | XSRETURN(1); |
416 | } |
417 | |
418 | |
30e11004 |
419 | XS(XS_Mouse_simple_writer) |
646c0371 |
420 | { |
421 | dVAR; dXSARGS; |
422 | dMOUSE_self; |
423 | SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); |
424 | |
425 | if (items != 2) { |
426 | croak("Expected exactly two argument for a writer for '%"SVf"'", slot); |
427 | } |
428 | |
6fe2272b |
429 | ST(0) = set_slot(self, slot, ST(1)); |
646c0371 |
430 | XSRETURN(1); |
431 | } |
432 | |
30e11004 |
433 | XS(XS_Mouse_simple_clearer) |
646c0371 |
434 | { |
435 | dVAR; dXSARGS; |
436 | dMOUSE_self; |
437 | SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); |
438 | SV* value; |
439 | |
440 | if (items != 1) { |
441 | croak("Expected exactly one argument for a clearer for '%"SVf"'", slot); |
442 | } |
443 | |
6fe2272b |
444 | value = delete_slot(self, slot); |
646c0371 |
445 | ST(0) = value ? value : &PL_sv_undef; |
446 | XSRETURN(1); |
447 | } |
448 | |
30e11004 |
449 | XS(XS_Mouse_simple_predicate) |
646c0371 |
450 | { |
451 | dVAR; dXSARGS; |
452 | dMOUSE_self; |
453 | SV* const slot = MOUSE_mg_slot((MAGIC*)XSANY.any_ptr); |
454 | |
455 | if (items != 1) { |
456 | croak("Expected exactly one argument for a predicate for '%"SVf"'", slot); |
457 | } |
458 | |
6fe2272b |
459 | ST(0) = boolSV( has_slot(self, slot) ); |
646c0371 |
460 | XSRETURN(1); |
461 | } |
462 | |
76770976 |
463 | /* simple instance slot accessor (or Mouse::Meta::Instance) */ |
646c0371 |
464 | |
465 | SV* |
466 | mouse_instance_create(pTHX_ HV* const stash) { |
467 | assert(stash); |
468 | return sv_bless( newRV_noinc((SV*)newHV()), stash ); |
469 | } |
470 | |
471 | SV* |
472 | mouse_instance_clone(pTHX_ SV* const instance) { |
473 | HV* proto; |
474 | assert(instance); |
475 | |
476 | CHECK_INSTANCE(instance); |
477 | proto = newHVhv((HV*)SvRV(instance)); |
478 | return sv_bless( newRV_noinc((SV*)proto), SvSTASH(SvRV(instance)) ); |
479 | } |
480 | |
481 | bool |
482 | mouse_instance_has_slot(pTHX_ SV* const instance, SV* const slot) { |
483 | assert(instance); |
484 | assert(slot); |
485 | CHECK_INSTANCE(instance); |
486 | return hv_exists_ent((HV*)SvRV(instance), slot, 0U); |
487 | } |
488 | |
489 | SV* |
490 | mouse_instance_get_slot(pTHX_ SV* const instance, SV* const slot) { |
491 | HE* he; |
492 | assert(instance); |
493 | assert(slot); |
494 | CHECK_INSTANCE(instance); |
495 | he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U); |
496 | return he ? HeVAL(he) : NULL; |
497 | } |
498 | |
499 | SV* |
500 | mouse_instance_set_slot(pTHX_ SV* const instance, SV* const slot, SV* const value) { |
501 | HE* he; |
502 | SV* sv; |
503 | assert(instance); |
504 | assert(slot); |
505 | assert(value); |
506 | CHECK_INSTANCE(instance); |
507 | he = hv_fetch_ent((HV*)SvRV(instance), slot, TRUE, 0U); |
508 | sv = HeVAL(he); |
509 | sv_setsv_mg(sv, value); |
510 | return sv; |
511 | } |
512 | |
513 | SV* |
514 | mouse_instance_delete_slot(pTHX_ SV* const instance, SV* const slot) { |
515 | assert(instance); |
516 | assert(slot); |
517 | CHECK_INSTANCE(instance); |
518 | return hv_delete_ent((HV*)SvRV(instance), slot, 0, 0U); |
519 | } |
520 | |
521 | void |
522 | mouse_instance_weaken_slot(pTHX_ SV* const instance, SV* const slot) { |
523 | HE* he; |
524 | assert(instance); |
525 | assert(slot); |
526 | CHECK_INSTANCE(instance); |
527 | he = hv_fetch_ent((HV*)SvRV(instance), slot, FALSE, 0U); |
528 | if(he){ |
529 | sv_rvweaken(HeVAL(he)); |
530 | } |
531 | } |
532 | \r |
533 | MODULE = Mouse::Meta::Method::Accessor::XS PACKAGE = Mouse::Meta::Method::Accessor::XS |
534 | |
535 | PROTOTYPES: DISABLE |
536 | VERSIONCHECK: DISABLE |
537 | |
538 | CV* |
539 | _generate_accessor(klass, SV* attr, metaclass) |
540 | CODE: |
541 | { |
30e11004 |
542 | RETVAL = mouse_instantiate_xs_accessor(aTHX_ attr, XS_Mouse_accessor); |
646c0371 |
543 | } |
544 | OUTPUT: |
545 | RETVAL |
546 | |
547 | CV* |
548 | _generate_reader(klass, SV* attr, metaclass) |
549 | CODE: |
550 | { |
30e11004 |
551 | RETVAL = mouse_instantiate_xs_accessor(aTHX_ attr, XS_Mouse_reader); |
646c0371 |
552 | } |
553 | OUTPUT: |
554 | RETVAL |
555 | |
556 | CV* |
557 | _generate_writer(klass, SV* attr, metaclass) |
558 | CODE: |
559 | { |
30e11004 |
560 | RETVAL = mouse_instantiate_xs_accessor(aTHX_ attr, XS_Mouse_writer); |
646c0371 |
561 | } |
562 | OUTPUT: |
563 | RETVAL |
564 | |
565 | CV* |
566 | _generate_clearer(klass, SV* attr, metaclass) |
567 | CODE: |
568 | { |
569 | SV* const slot = mcall0s(attr, "name"); |
570 | STRLEN len; |
571 | const char* const pv = SvPV_const(slot, len); |
30e11004 |
572 | RETVAL = mouse_install_simple_accessor(aTHX_ NULL, pv, len, XS_Mouse_simple_clearer); |
646c0371 |
573 | } |
574 | OUTPUT: |
575 | RETVAL |
576 | |
577 | CV* |
578 | _generate_predicate(klass, SV* attr, metaclass) |
579 | CODE: |
580 | { |
581 | SV* const slot = mcall0s(attr, "name"); |
582 | STRLEN len; |
583 | const char* const pv = SvPV_const(slot, len); |
30e11004 |
584 | RETVAL = mouse_install_simple_accessor(aTHX_ NULL, pv, len, XS_Mouse_simple_predicate); |
646c0371 |
585 | } |
586 | OUTPUT: |
587 | RETVAL |
588 | |