add strict_constructor => Bool optin to make_immutable (EXPERIMENTAL)
[gitmo/Mouse.git] / xs-src / Mouse.xs
CommitLineData
1b812057 1#define NEED_newSVpvn_flags_GLOBAL
df6dd016 2#include "mouse.h"
3
cccb83de 4SV* mouse_package;
5SV* mouse_namespace;
3e44140b 6SV* mouse_methods;
a5df48e5 7SV* mouse_name;
047d7af0 8SV* mouse_get_attribute;
9SV* mouse_get_attribute_list;
cccb83de 10
4e7e3250 11#define MOUSE_xc_flags(a) SvUVX(MOUSE_av_at((a), MOUSE_XC_FLAGS))
a39e9541 12#define MOUSE_xc_gen(a) MOUSE_av_at((a), MOUSE_XC_GEN)
aa2d2e2c 13#define MOUSE_xc_stash(a) ( (HV*)MOUSE_av_at((a), MOUSE_XC_STASH) )
a39e9541 14#define MOUSE_xc_attrall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_ATTRALL) )
15#define MOUSE_xc_buildall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_BUILDALL) )
9974d611 16#define MOUSE_xc_demolishall(a) ( (AV*)MOUSE_av_at((a), MOUSE_XC_DEMOLISHALL) )
a39e9541 17
aa2d2e2c 18enum mouse_xc_flags_t {
19 MOUSEf_XC_IS_IMMUTABLE = 0x0001,
20 MOUSEf_XC_IS_ANON = 0x0002,
21 MOUSEf_XC_HAS_BUILDARGS = 0x0004,
22
d305e107 23 MOUSEf_XC_HAS_STRICT_CONSTRUCTOR
24 = 0x0008,
25
aa2d2e2c 26 MOUSEf_XC_mask = 0xFFFF /* not used */
27};
28
a39e9541 29/* Mouse XS Metaclass object */
30enum mouse_xc_ix_t{
4e7e3250 31 MOUSE_XC_FLAGS,
32
a39e9541 33 MOUSE_XC_GEN, /* class generation */
aa2d2e2c 34 MOUSE_XC_STASH, /* symbol table hash */
aa2d2e2c 35
a39e9541 36 MOUSE_XC_ATTRALL, /* all the attributes */
37 MOUSE_XC_BUILDALL, /* all the BUILD methods */
38 MOUSE_XC_DEMOLISHALL, /* all the DEMOLISH methods */
39
40 MOUSE_XC_last
41};
42
43static MGVTBL mouse_xc_vtbl; /* for identity */
44
45static void
46mouse_class_push_attribute_list(pTHX_ SV* const metaclass, AV* const attrall, HV* const seen){
47 dSP;
48 I32 n;
49
50 /* $meta->get_attribute_list */
51 PUSHMARK(SP);
52 XPUSHs(metaclass);
53 PUTBACK;
54
047d7af0 55 n = call_sv(mouse_get_attribute_list, G_ARRAY | G_METHOD);
a39e9541 56 for(NOOP; n > 0; n--){
57 SV* name;
58
59 SPAGAIN;
60 name = POPs;
61 PUTBACK;
62
63 if(hv_exists_ent(seen, name, 0U)){
64 continue;
65 }
66 (void)hv_store_ent(seen, name, &PL_sv_undef, 0U);
da4432f3 67
047d7af0 68 av_push(attrall, newSVsv( mcall1(metaclass, mouse_get_attribute, name) ));
a39e9541 69 }
70}
743ca82e 71
aa2d2e2c 72static int
73mouse_class_has_custom_buildargs(pTHX_ HV* const stash) {
74 XS(XS_Mouse__Object_BUILDARGS); /* prototype */
75
76 GV* const buildargs = gv_fetchmeth_autoload(stash, "BUILDARGS", sizeof("BUILDARGS")-1, 0);
aa2d2e2c 77
12872cc1 78 return buildargs && CvXSUB(GvCV(buildargs)) != XS_Mouse__Object_BUILDARGS;
aa2d2e2c 79}
80
a39e9541 81static void
82mouse_class_update_xc(pTHX_ SV* const metaclass PERL_UNUSED_DECL, HV* const stash, AV* const xc) {
83 AV* const linearized_isa = mro_get_linear_isa(stash);
84 I32 const len = AvFILLp(linearized_isa);
85 I32 i;
aa2d2e2c 86 U32 flags = 0x00;
a39e9541 87 AV* const attrall = newAV();
88 AV* const buildall = newAV();
89 AV* const demolishall = newAV();
90 HV* const seen = newHV(); /* for attributes */
da4432f3 91
a39e9541 92 ENTER;
93 SAVETMPS;
da4432f3 94
a39e9541 95 sv_2mortal((SV*)seen);
da4432f3 96
a39e9541 97 /* old data will be delete at the end of the perl scope */
98 av_delete(xc, MOUSE_XC_DEMOLISHALL, 0x00);
99 av_delete(xc, MOUSE_XC_BUILDALL, 0x00);
100 av_delete(xc, MOUSE_XC_ATTRALL, 0x00);
743ca82e 101
a39e9541 102 SvREFCNT_inc_simple_void_NN(linearized_isa);
103 sv_2mortal((SV*)linearized_isa);
da4432f3 104
a39e9541 105 /* update */
da4432f3 106
4e7e3250 107 if(predicate_calls(metaclass, "is_immutable")){
aa2d2e2c 108 flags |= MOUSEf_XC_IS_IMMUTABLE;
109 }
110
4e7e3250 111 if(predicate_calls(metaclass, "is_anon_class")){
112 flags |= MOUSEf_XC_IS_ANON;
113 }
114
aa2d2e2c 115 if(mouse_class_has_custom_buildargs(aTHX_ stash)){
116 flags |= MOUSEf_XC_HAS_BUILDARGS;
117 }
118
d305e107 119 if(predicate_calls(metaclass, "_has_strict_constructor")){
120 flags |= MOUSEf_XC_HAS_STRICT_CONSTRUCTOR;
121 }
122
4e7e3250 123 av_store(xc, MOUSE_XC_FLAGS, newSVuv(flags));
a39e9541 124 av_store(xc, MOUSE_XC_ATTRALL, (SV*)attrall);
125 av_store(xc, MOUSE_XC_BUILDALL, (SV*)buildall);
126 av_store(xc, MOUSE_XC_DEMOLISHALL, (SV*)demolishall);
da4432f3 127
a39e9541 128 for(i = 0; i < len; i++){
047d7af0 129 SV* const klass = MOUSE_av_at(linearized_isa, i);
074a414d 130 HV* const st = gv_stashsv(klass, TRUE);
a39e9541 131 SV* meta;
132 GV* gv;
da4432f3 133
074a414d 134 gv = stash_fetchs(st, "BUILD", FALSE);
a39e9541 135 if(gv && GvCVu(gv)){
074a414d 136 av_unshift(buildall, 1);
137 av_store(buildall, 0, newRV_inc((SV*)GvCV(gv)));
a39e9541 138 }
da4432f3 139
074a414d 140 gv = stash_fetchs(st, "DEMOLISH", FALSE);
a39e9541 141 if(gv && GvCVu(gv)){
142 av_push(demolishall, newRV_inc((SV*)GvCV(gv)));
143 }
da4432f3 144
a39e9541 145 /* ATTRIBUTES */
aa2d2e2c 146 meta = get_metaclass(klass);
a39e9541 147 if(!SvOK(meta)){
148 continue; /* skip non-Mouse classes */
149 }
da4432f3 150
a39e9541 151 mouse_class_push_attribute_list(aTHX_ meta, attrall, seen);
152 }
da4432f3 153
a39e9541 154 FREETMPS;
155 LEAVE;
da4432f3 156
a39e9541 157 sv_setuv(MOUSE_xc_gen(xc), mro_get_pkg_gen(stash));
158}
da4432f3 159
3001d9ac 160static AV*
a39e9541 161mouse_get_xc(pTHX_ SV* const metaclass) {
162 AV* xc;
163 SV* gen;
164 HV* stash;
165 MAGIC* mg;
166
167 if(!IsObject(metaclass)){
168 croak("Not a Mouse metaclass");
169 }
da4432f3 170
a39e9541 171 mg = mouse_mg_find(aTHX_ SvRV(metaclass), &mouse_xc_vtbl, 0x00);
172 if(!mg){
173 SV* const package = get_slot(metaclass, mouse_package);
aa2d2e2c 174 STRLEN len;
175 const char* const pv = SvPV_const(package, len);
da4432f3 176
aa2d2e2c 177 stash = gv_stashpvn(pv, len, TRUE);
a39e9541 178 xc = newAV();
da4432f3 179
aa2d2e2c 180 mg = sv_magicext(SvRV(metaclass), (SV*)xc, PERL_MAGIC_ext, &mouse_xc_vtbl, pv, len);
a39e9541 181 SvREFCNT_dec(xc); /* refcnt++ in sv_magicext */
da4432f3 182
a39e9541 183 av_extend(xc, MOUSE_XC_last - 1);
aa2d2e2c 184
a5c683f6 185 av_store(xc, MOUSE_XC_GEN, newSVuv(0U));
aa2d2e2c 186 av_store(xc, MOUSE_XC_STASH, (SV*)stash);
4e7e3250 187
aa2d2e2c 188 SvREFCNT_inc_simple_void_NN(stash);
da4432f3 189 }
a39e9541 190 else{
a39e9541 191 xc = (AV*)MOUSE_mg_obj(mg);
da4432f3 192
a39e9541 193 assert(xc);
194 assert(SvTYPE(xc) == SVt_PVAV);
195 }
da4432f3 196
aa2d2e2c 197 gen = MOUSE_xc_gen(xc);
a5c683f6 198
199 if(SvUVX(gen) != 0U && MOUSE_xc_flags(xc) & MOUSEf_XC_IS_IMMUTABLE){
200 return xc;
201 }
202
aa2d2e2c 203 stash = MOUSE_xc_stash(xc);
204
a5c683f6 205 if(SvUVX(gen) != mro_get_pkg_gen(stash)){
a39e9541 206 mouse_class_update_xc(aTHX_ metaclass, stash, xc);
da4432f3 207 }
a39e9541 208
209 return xc;
210}
211
3001d9ac 212static HV*
074a414d 213mouse_buildargs(pTHX_ SV* metaclass, SV* const klass, I32 ax, I32 items) {
aa2d2e2c 214 HV* args;
074a414d 215
216 /* shift @_ */
217 ax++;
218 items--;
219
220 if(items == 1){
221 SV* const args_ref = ST(0);
aa2d2e2c 222 if(!IsHashRef(args_ref)){
223 if(!metaclass){ metaclass = get_metaclass(klass); }
224 mouse_throw_error(metaclass, NULL, "Single parameters to new() must be a HASH ref");
225 }
226 args = newHVhv((HV*)SvRV(args_ref));
227 sv_2mortal((SV*)args);
228 }
229 else{
230 I32 i;
231
6fab29c6 232 args = newHV_mortal();
aa2d2e2c 233
074a414d 234 if( (items % 2) != 0 ){
aa2d2e2c 235 if(!metaclass){ metaclass = get_metaclass(klass); }
236 mouse_throw_error(metaclass, NULL, "Odd number of parameters to new()");
237 }
238
074a414d 239 for(i = 0; i < items; i += 2){
aa2d2e2c 240 (void)hv_store_ent(args, ST(i), newSVsv(ST(i+1)), 0U);
241 }
242
243 }
244 return args;
245}
246
3001d9ac 247static void
6fd8aa82 248mouse_report_unmatched_keys(pTHX_ SV* const meta, AV* const attrs, HV* const args) {
249 HV* const attr_map = newHV_mortal();
250 I32 const len = AvFILLp(attrs) + 1;
251 I32 i;
252 SV* const unknown = newSVpvs_flags("", SVs_TEMP);
253 HE* he;
254
255 for(i = 0; i < len; i++){
256 SV* const attr = MOUSE_av_at(attrs, i);
257 (void)hv_store_ent(attr_map, mcall0(attr, mouse_name), &PL_sv_yes, 0U);
258 }
259
260 hv_iterinit(args);
261 while((he = hv_iternext(args))){
262 SV* const key = hv_iterkeysv(he);
263 if(!hv_exists_ent(attr_map, key, 0U)){
264 sv_catpvf(unknown, " %"SVf",", key);
265 }
266 }
267 SvCUR(unknown)--; /* chop "," */
268 mouse_throw_error(meta, NULL,
269 "Unknown attribute init_arg passed to the constructor of %"SVf": %"SVf,
270 mcall0(meta, mouse_name), unknown);
271}
272
273static void
d4712779 274mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const args, bool const ignore_triggers) {
275 AV* const xc = mouse_get_xc(aTHX_ meta);
276 AV* const attrs = MOUSE_xc_attrall(xc);
4e7e3250 277 I32 len = AvFILLp(attrs) + 1;
d4712779 278 I32 i;
6fd8aa82 279 I32 used = 0;
4e7e3250 280 AV* triggers_queue = NULL;
281
074a414d 282 assert(meta || object);
283 assert(args);
284 assert(SvTYPE(args) == SVt_PVHV);
285
4e7e3250 286 ENTER;
287 SAVETMPS;
288
289 if(!ignore_triggers){
290 triggers_queue = newAV_mortal();
291 }
0aad0266 292
d4712779 293 for(i = 0; i < len; i++){
6bc5b495 294 SV* const attr = MOUSE_av_at(attrs, i);
295 AV* const xa = mouse_get_xa(aTHX_ attr);
4e7e3250 296
297 SV* const slot = MOUSE_xa_slot(xa);
298 U16 const flags = (U16)MOUSE_xa_flags(xa);
299 SV* const init_arg = MOUSE_xa_init_arg(xa);
300 HE* he;
301
302 if(SvOK(init_arg) && ( he = hv_fetch_ent(args, init_arg, FALSE, 0U) ) ){
303 SV* value = HeVAL(he);
304 if(flags & MOUSEf_ATTR_HAS_TC){
305 value = mouse_xa_apply_type_constraint(aTHX_ xa, value, flags);
306 }
307 set_slot(object, slot, value);
308 if(SvROK(value) && flags & MOUSEf_ATTR_IS_WEAK_REF){
309 weaken_slot(object, slot);
310 }
311 if(flags & MOUSEf_ATTR_HAS_TRIGGER && triggers_queue){
312 AV* const pair = newAV();
313 av_push(pair, newSVsv( mcall0s(attr, "trigger") ));
314 av_push(pair, newSVsv(value));
315
316 av_push(triggers_queue, (SV*)pair);
317 }
6fd8aa82 318
319 used++;
4e7e3250 320 }
321 else { /* no init arg */
322 if(flags & (MOUSEf_ATTR_HAS_DEFAULT | MOUSEf_ATTR_HAS_BUILDER)){
323 if(!(flags & MOUSEf_ATTR_IS_LAZY)){
324 mouse_xa_set_default(aTHX_ xa, object);
325 }
326 }
327 else if(flags & MOUSEf_ATTR_IS_REQUIRED) {
328 mouse_throw_error(attr, NULL, "Attribute (%"SVf") is required", slot);
329 }
330 }
331 } /* for each attributes */
332
333 if(triggers_queue){
334 len = AvFILLp(triggers_queue) + 1;
335 for(i = 0; i < len; i++){
336 AV* const pair = (AV*)AvARRAY(triggers_queue)[i];
337 SV* const trigger = AvARRAY(pair)[0];
338 SV* const value = AvARRAY(pair)[1];
339
340 mcall1(object, trigger, value);
341 }
342 }
343
d305e107 344 if(MOUSE_xc_flags(xc) & MOUSEf_XC_HAS_STRICT_CONSTRUCTOR && used < HvUSEDKEYS(args)){
6fd8aa82 345 mouse_report_unmatched_keys(aTHX_ meta, attrs, args);
346 }
347
4e7e3250 348 if(MOUSE_xc_flags(xc) & MOUSEf_XC_IS_ANON){
36d75a0a 349 set_slot(object, newSVpvs_flags("__METACLASS__", SVs_TEMP), meta);
d4712779 350 }
4e7e3250 351
352 FREETMPS;
353 LEAVE;
aa2d2e2c 354}
355
a5c683f6 356static SV*
1bbf8369 357mouse_initialize_metaclass(pTHX_ SV* const klass) {
358 SV* meta = get_metaclass(klass);
359
360 if(!SvOK(meta)){
361 dSP;
362 PUSHMARK(SP);
363
364 EXTEND(SP, 2);
365 mPUSHp("Mouse::Meta::Class", sizeof("Mouse::Meta::Class")-1);
366 PUSHs(klass);
367 PUTBACK;
368
369 call_method("initialize", G_SCALAR);
370 SPAGAIN;
371 meta = POPs;
372 PUTBACK;
373 }
374
375 return meta;
376}
377
adb5eb76 378static void
379mouse_buildall(pTHX_ AV* const xc, SV* const object, SV* const args) {
380 AV* const buildall = MOUSE_xc_buildall(xc);
381 I32 const len = AvFILLp(buildall) + 1;
382 I32 i;
383 for(i = 0; i < len; i++){
384 dSP;
385
386 PUSHMARK(SP);
387 EXTEND(SP, 2);
388 PUSHs(object);
389 PUSHs(args);
390 PUTBACK;
391
392 call_sv(AvARRAY(buildall)[i], G_VOID | G_DISCARD);
393 }
394}
395
646c0371 396MODULE = Mouse PACKAGE = Mouse
df6dd016 397
398PROTOTYPES: DISABLE
399
cccb83de 400BOOT:
401 mouse_package = newSVpvs_share("package");
402 mouse_namespace = newSVpvs_share("namespace");
3e44140b 403 mouse_methods = newSVpvs_share("methods");
a5df48e5 404 mouse_name = newSVpvs_share("name");
3e44140b 405
047d7af0 406 mouse_get_attribute = newSVpvs_share("get_attribute");
407 mouse_get_attribute_list = newSVpvs_share("get_attribute_list");
da4432f3 408
646c0371 409 MOUSE_CALL_BOOT(Mouse__Util);
1d5ecd5f 410 MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints);
646c0371 411 MOUSE_CALL_BOOT(Mouse__Meta__Method__Accessor__XS);
aa2d2e2c 412 MOUSE_CALL_BOOT(Mouse__Meta__Attribute);
f48920c1 413
cccb83de 414
7d96ae4d 415MODULE = Mouse PACKAGE = Mouse::Meta::Module
416
417BOOT:
418 INSTALL_SIMPLE_READER_WITH_KEY(Module, name, package);
419 INSTALL_SIMPLE_READER_WITH_KEY(Module, _method_map, methods);
420 INSTALL_SIMPLE_READER_WITH_KEY(Module, _attribute_map, attributes);
421
422HV*
423namespace(SV* self)
424CODE:
425{
6a97bbda 426 SV* const package = get_slot(self, mouse_package);
7d96ae4d 427 if(!(package && SvOK(package))){
3e44140b 428 croak("No package name defined");
7d96ae4d 429 }
430 RETVAL = gv_stashsv(package, GV_ADDMULTI);
431}
432OUTPUT:
433 RETVAL
434
3e44140b 435# ignore extra arguments for extensibility
436void
437add_method(SV* self, SV* name, SV* code, ...)
438CODE:
439{
6a97bbda 440 SV* const package = get_slot(self, mouse_package); /* $self->{package} */
441 SV* const methods = get_slot(self, mouse_methods); /* $self->{methods} */
3e44140b 442 GV* gv;
443 SV* code_ref;
444
445 if(!(package && SvOK(package))){
446 croak("No package name defined");
447 }
448
449 SvGETMAGIC(name);
450 SvGETMAGIC(code);
451
452 if(!SvOK(name)){
453 mouse_throw_error(self, NULL, "You must define a method name");
454 }
455 if(!SvROK(code)){
456 mouse_throw_error(self, NULL, "You must define a CODE reference");
457 }
458
459 code_ref = code;
460 if(SvTYPE(SvRV(code_ref)) != SVt_PVCV){
461 SV* sv = code_ref; /* used in tryAMAGICunDEREF */
462 SV** sp = &sv; /* used in tryAMAGICunDEREF */
463 tryAMAGICunDEREF(to_cv); /* try \&{$code} */
24d5564d 464 if(!(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV)){
465 mouse_throw_error(self, NULL, "You must pass a CODE reference to add_method");
3e44140b 466 }
467 code_ref = sv;
468 }
469
470 /* *{$package . '::' . $name} -> *gv */
471 gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV);
472 if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */
473 SvREFCNT_dec(GvCV(gv));
474 GvCV(gv) = NULL;
475 }
476 sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */
477
6fe2272b 478 set_slot(methods, name, code); /* $self->{methods}{$name} = $code */
3e44140b 479
855eff0e 480 /* name the CODE ref if it's anonymous */
481 {
482 CV* const code_entity = (CV*)SvRV(code_ref);
483 if(CvANON(code_entity)
484 && CvGV(code_entity) /* a cv under construction has no gv */ ){
485
486 CvGV(code_entity) = gv;
487 CvANON_off(code_entity);
488 }
489 }
3e44140b 490}
491
43165725 492MODULE = Mouse PACKAGE = Mouse::Meta::Class
493
494BOOT:
495 INSTALL_SIMPLE_READER(Class, roles);
496 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id);
80efe911 497 INSTALL_SIMPLE_READER(Class, is_immutable);
d305e107 498 INSTALL_SIMPLE_READER_WITH_KEY(Class, has_strict_constructor, _strict_constructor);
a5c683f6 499
787f84c2 500 INSTALL_CLASS_HOLDER(Class, method_metaclass, "Mouse::Meta::Method");
501 INSTALL_CLASS_HOLDER(Class, attribute_metaclass, "Mouse::Meta::Attribute");
502 INSTALL_CLASS_HOLDER(Class, constructor_class, "Mouse::Meta::Method::Constructor::XS");
503 INSTALL_CLASS_HOLDER(Class, destructor_class, "Mouse::Meta::Method::Destructor::XS");
a5c683f6 504
505 newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Constructor::XS", TRUE), "_generate_constructor",
506 newRV_inc((SV*)get_cvs("Mouse::Object::new", TRUE)));
507 newCONSTSUB(gv_stashpvs("Mouse::Meta::Method::Destructor::XS", TRUE), "_generate_destructor",
508 newRV_inc((SV*)get_cvs("Mouse::Object::DESTROY", TRUE)));
509
43165725 510
cccb83de 511void
512linearized_isa(SV* self)
513PPCODE:
514{
515 SV* const stash_ref = mcall0(self, mouse_namespace); /* $self->namespace */
516 AV* linearized_isa;
517 I32 len;
518 I32 i;
519 if(!(SvROK(stash_ref) && SvTYPE(SvRV(stash_ref)) == SVt_PVHV)){
520 croak("namespace() didn't return a HASH reference");
521 }
522 linearized_isa = mro_get_linear_isa((HV*)SvRV(stash_ref));
523 len = AvFILLp(linearized_isa) + 1;
524 EXTEND(SP, len);
525 for(i = 0; i < len; i++){
526 PUSHs(AvARRAY(linearized_isa)[i]);
527 }
528}
529
da4432f3 530void
531get_all_attributes(SV* self)
532PPCODE:
533{
0aad0266 534 AV* const xc = mouse_get_xc(aTHX_ self);
ae34e077 535 AV* const all_attrs = MOUSE_xc_attrall(xc);
da4432f3 536 I32 const len = AvFILLp(all_attrs) + 1;
537 I32 i;
538
539 EXTEND(SP, len);
540 for(i = 0; i < len; i++){
541 PUSHs( MOUSE_av_at(all_attrs, i) );
542 }
543}
441964ce 544
aa2d2e2c 545SV*
ba153b33 546new_object(SV* meta, ...)
aa2d2e2c 547CODE:
548{
aa2d2e2c 549 AV* const xc = mouse_get_xc(aTHX_ meta);
074a414d 550 HV* const args = mouse_buildargs(aTHX_ meta, NULL, ax, items);
d4712779 551
aa2d2e2c 552 RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
d4712779 553 mouse_class_initialize_object(aTHX_ meta, RETVAL, args, FALSE);
aa2d2e2c 554}
ba153b33 555OUTPUT:
556 RETVAL
aa2d2e2c 557
558void
4e7e3250 559_initialize_object(SV* meta, SV* object, HV* args, bool ignore_triggers = FALSE)
aa2d2e2c 560CODE:
561{
d4712779 562 mouse_class_initialize_object(aTHX_ meta, object, args, ignore_triggers);
aa2d2e2c 563}
564
43165725 565MODULE = Mouse PACKAGE = Mouse::Meta::Role
566
567BOOT:
568 INSTALL_SIMPLE_READER_WITH_KEY(Role, get_roles, roles);
569 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Role, is_anon_role, anon_serial_id);
570
787f84c2 571 INSTALL_CLASS_HOLDER(Role, method_metaclass, "Mouse::Meta::Role::Method");
e058b279 572
aa2d2e2c 573MODULE = Mouse PACKAGE = Mouse::Object
43165725 574
074a414d 575SV*
576new(SV* klass, ...)
577CODE:
578{
1bbf8369 579 SV* const meta = mouse_initialize_metaclass(aTHX_ klass);
074a414d 580 AV* const xc = mouse_get_xc(aTHX_ meta);
581 UV const flags = MOUSE_xc_flags(xc);
582 SV* args;
074a414d 583
584 /* BUILDARGS */
585 if(flags & MOUSEf_XC_HAS_BUILDARGS){
adb5eb76 586 I32 i;
074a414d 587 SPAGAIN;
588
589 PUSHMARK(SP);
590 EXTEND(SP, items);
591 for(i = 0; i < items; i++){
592 PUSHs(ST(i));
593 }
594 //SP += items;
595 PUTBACK;
596 call_method("BUILDARGS", G_SCALAR);
597 SPAGAIN;
598 args = POPs;
599 PUTBACK;
600
601 if(!IsHashRef(args)){
602 croak("BUILDARGS did not return a HASH reference");
603 }
604 }
605 else{
606 args = newRV_inc((SV*)mouse_buildargs(aTHX_ meta, klass, ax, items));
607 sv_2mortal(args);
608 }
609
610 /* new_object */
611 RETVAL = mouse_instance_create(aTHX_ MOUSE_xc_stash(xc));
612 mouse_class_initialize_object(aTHX_ meta, RETVAL, (HV*)SvRV(args), FALSE);
613
adb5eb76 614 mouse_buildall(aTHX_ xc, RETVAL, args);
074a414d 615}
616OUTPUT:
617 RETVAL
618
a5c683f6 619void
620DESTROY(SV* object)
adb5eb76 621ALIAS:
622 DESTROY = 0
623 DEMOLISHALL = 1
aa2d2e2c 624CODE:
625{
a5c683f6 626 SV* const meta = get_metaclass(object);
627 AV* demolishall;
628 I32 len, i;
629
adb5eb76 630 PERL_UNUSED_VAR(ix);
631
a5c683f6 632 if(!IsObject(object)){
633 croak("You must not call DESTROY as a class method");
634 }
635
636 if(SvOK(meta)){
637 AV* const xc = mouse_get_xc(aTHX_ meta);
638
639 demolishall = MOUSE_xc_demolishall(xc);
640 }
adb5eb76 641 else { /* The metaclass is already destroyed */
a5c683f6 642 AV* const linearized_isa = mro_get_linear_isa(SvSTASH(SvRV(object)));
7efbc77d 643
a5c683f6 644 len = AvFILLp(linearized_isa) + 1;
7efbc77d 645
a5c683f6 646 demolishall = newAV_mortal();
647 for(i = 0; i < len; i++){
648 SV* const klass = MOUSE_av_at(linearized_isa, i);
649 HV* const st = gv_stashsv(klass, TRUE);
650 GV* const gv = stash_fetchs(st, "DEMOLISH", FALSE);
651 if(gv && GvCVu(gv)){
652 av_push(demolishall, newRV_inc((SV*)GvCV(gv)));
653 }
654 }
655 }
656
a5c683f6 657 len = AvFILLp(demolishall) + 1;
658 if(len > 0){
659 GV* const statusvalue = gv_fetchpvs("?", 0, SVt_PV);
660 SAVESPTR(GvSV(statusvalue)); /* local $? */
661 SAVESPTR(ERRSV); /* local $@ */
662
f8beb873 663 GvSV(statusvalue) = sv_newmortal();
664 ERRSV = newSVpvs_flags("", SVs_TEMP);
a5c683f6 665 for(i = 0; i < len; i++){
f8beb873 666 SPAGAIN;
a5c683f6 667
668 PUSHMARK(SP);
669 XPUSHs(object);
670 PUTBACK;
671
672 call_sv(AvARRAY(demolishall)[i], G_VOID | G_DISCARD | G_EVAL);
673 if(SvTRUE(ERRSV)){
674 SV* const e = newSVsv(ERRSV);
675
676 FREETMPS;
677 LEAVE;
678
679 sv_setsv(ERRSV, e);
680 SvREFCNT_dec(e);
681 croak(NULL); /* rethrow */
682 }
683 }
684 }
685}
686
687HV*
688BUILDARGS(SV* klass, ...)
7efbc77d 689CODE:
690{
a5c683f6 691 RETVAL = mouse_buildargs(aTHX_ NULL, klass, ax, items);
7efbc77d 692}
693OUTPUT:
694 RETVAL
695
a5c683f6 696
adb5eb76 697void
698BUILDALL(SV* self, SV* args)
699CODE:
700{
f50e50d6 701 SV* const meta = get_metaclass(self);
702 AV* const xc = mouse_get_xc(aTHX_ meta);
adb5eb76 703
704 if(!IsHashRef(args)){
705 croak("You must pass a HASH reference to BUILDALL");
706 }
707 if(mg_find(SvRV(args), PERL_MAGIC_tied)){
708 croak("You cannot use tie HASH reference as args");
709 }
710 mouse_buildall(aTHX_ xc, self, args);
711}