Mouse::Util::does_role() respects $thing->does() method
[gitmo/Mouse.git] / xs-src / MouseUtil.xs
1 #include "mouse.h"
2
3 #define MY_CXT_KEY "Mouse::Util::_guts" XS_VERSION
4 typedef struct {
5     HV* metas;
6 } my_cxt_t;
7 START_MY_CXT
8
9 #define ISA_CACHE "::LINEALIZED_ISA_CACHE::"
10
11 #ifdef no_mro_get_linear_isa
12 AV*
13 mouse_mro_get_linear_isa(pTHX_ HV* const stash){
14     GV* const cachegv = *(GV**)hv_fetchs(stash, ISA_CACHE, TRUE);
15     AV* isa;
16     SV* gen;
17     CV* get_linear_isa;
18
19     if(!isGV(cachegv))
20         gv_init(cachegv, stash, ISA_CACHE, sizeof(ISA_CACHE)-1, TRUE);
21
22     isa = GvAVn(cachegv);
23     gen = GvSVn(cachegv);
24
25
26     if(SvIOK(gen) && SvIVX(gen) == (IV)mro_get_pkg_gen(stash)){
27         return isa; /* returns the cache if available */
28     }
29     else{
30         SvREFCNT_dec(isa);
31         GvAV(cachegv) = isa = newAV();
32     }
33
34     get_linear_isa = get_cv("Mouse::Util::get_linear_isa", TRUE);
35
36     {
37         SV* avref;
38         dSP;
39
40         ENTER;
41         SAVETMPS;
42
43         PUSHMARK(SP);
44         mXPUSHp(HvNAME_get(stash), HvNAMELEN_get(stash));
45         PUTBACK;
46
47         call_sv((SV*)get_linear_isa, G_SCALAR);
48
49         SPAGAIN;
50         avref = POPs;
51         PUTBACK;
52
53         if(IsArrayRef(avref)){
54             AV* const av  = (AV*)SvRV(avref);
55             I32 const len = AvFILLp(av) + 1;
56             I32 i;
57
58             for(i = 0; i < len; i++){
59                 HV* const stash = gv_stashsv(AvARRAY(av)[i], FALSE);
60                 if(stash)
61                     av_push(isa, newSVpv(HvNAME(stash), 0));
62             }
63             SvREADONLY_on(isa);
64         }
65         else{
66             Perl_croak(aTHX_ "Mouse:Util::get_linear_isa() didn't return an ARRAY reference");
67         }
68
69         FREETMPS;
70         LEAVE;
71     }
72
73     sv_setiv(gen, (IV)mro_get_pkg_gen(stash));
74     return isa;
75 }
76 #endif /* !no_mor_get_linear_isa */
77
78 #ifdef DEBUGGING
79 SV**
80 mouse_av_at_safe(pTHX_ AV* const av, I32 const ix){
81     assert(av);
82     assert(SvTYPE(av) == SVt_PVAV);
83     assert(AvMAX(av) >= ix);
84     return &AvARRAY(av)[ix];
85 }
86 #endif
87
88 void
89 mouse_throw_error(SV* const metaobject, SV* const data /* not used */, const char* const fmt, ...){
90     dTHX;
91     va_list args;
92     SV* message;
93
94     assert(metaobject);
95     assert(fmt);
96
97     va_start(args, fmt);
98     message = vnewSVpvf(fmt, &args);
99     va_end(args);
100
101     {
102         dSP;
103         PUSHMARK(SP);
104         EXTEND(SP, 6);
105
106         PUSHs(metaobject);
107         mPUSHs(message);
108
109         if(data){ /* extra arg, might be useful for debugging */
110             mPUSHs(newSVpvs("data"));
111             PUSHs(data);
112             mPUSHs(newSVpvs("depth"));
113             mPUSHi(-1);
114         }
115         PUTBACK;
116         if(SvOK(metaobject)) {
117             call_method("throw_error", G_VOID);
118         }
119         else {
120             call_pv("Mouse::Util::throw_error", G_VOID);
121         }
122         croak("throw_error() did not throw the error (%"SVf")", message);
123     }
124 }
125
126 /* workaround Perl-RT #69939 */
127 I32
128 mouse_call_sv_safe(pTHX_ SV* const sv, I32 const flags) {
129     I32 count;
130     ENTER;
131     /* Don't do SAVETMPS */
132
133     SAVESPTR(ERRSV);
134     ERRSV = sv_newmortal();
135
136     count = Perl_call_sv(aTHX_ sv, flags | G_EVAL);
137
138     if(sv_true(ERRSV)){
139         SV* const err = sv_mortalcopy(ERRSV);
140         LEAVE;
141         sv_setsv(ERRSV, err);
142         croak(NULL); /* rethrow */
143     }
144
145     LEAVE;
146
147     return count;
148 }
149
150 void
151 mouse_must_defined(pTHX_ SV* const value, const char* const name) {
152     assert(value);
153     assert(name);
154
155     SvGETMAGIC(value);
156     if(!SvOK(value)){
157         croak("You must define %s", name);
158     }
159 }
160
161 void
162 mouse_must_ref(pTHX_ SV* const value, const char* const name, svtype const t) {
163     assert(value);
164     assert(name);
165
166     SvGETMAGIC(value);
167     if(!(SvROK(value) && (t == SVt_NULL || SvTYPE(SvRV(value)) == t))) {
168         croak("You must pass %s, not %s",
169             name, SvOK(value) ? SvPV_nolen(value) : "undef");
170     }
171 }
172
173
174 bool
175 mouse_is_class_loaded(pTHX_ SV * const klass){
176     HV *stash;
177     GV** gvp;
178     HE* he;
179
180     if (!(SvPOKp(klass) && SvCUR(klass))) { /* XXX: SvPOK does not work with magical scalars */
181         return FALSE;
182     }
183
184     stash = gv_stashsv(klass, FALSE);
185     if (!stash) {
186         return FALSE;
187     }
188
189     if (( gvp = (GV**)hv_fetchs(stash, "VERSION", FALSE) )) {
190         if(isGV(*gvp) && GvSV(*gvp) && SvOK(GvSV(*gvp))){
191             return TRUE;
192         }
193     }
194
195     if (( gvp = (GV**)hv_fetchs(stash, "ISA", FALSE) )) {
196         if(isGV(*gvp) && GvAV(*gvp) && av_len(GvAV(*gvp)) != -1){
197             return TRUE;
198         }
199     }
200
201     hv_iterinit(stash);
202     while(( he = hv_iternext(stash) )){
203         GV* const gv = (GV*)HeVAL(he);
204
205         if(isGV(gv)){
206             if(GvCVu(gv)){ /* is GV and has CV */
207                 hv_iterinit(stash); /* reset */
208                 return TRUE;
209             }
210         }
211         else if(SvOK(gv)){ /* is a stub or constant */
212             hv_iterinit(stash); /* reset */
213             return TRUE;
214         }
215     }
216     return FALSE;
217 }
218
219
220 SV*
221 mouse_call0 (pTHX_ SV* const self, SV* const method) {
222     dSP;
223     SV *ret;
224
225     PUSHMARK(SP);
226     XPUSHs(self);
227     PUTBACK;
228
229     call_sv_safe(method, G_SCALAR | G_METHOD);
230
231     SPAGAIN;
232     ret = POPs;
233     PUTBACK;
234
235     return ret;
236 }
237
238 SV*
239 mouse_call1 (pTHX_ SV* const self, SV* const method, SV* const arg1) {
240     dSP;
241     SV *ret;
242
243     PUSHMARK(SP);
244     EXTEND(SP, 2);
245     PUSHs(self);
246     PUSHs(arg1);
247     PUTBACK;
248
249     call_sv_safe(method, G_SCALAR | G_METHOD);
250
251     SPAGAIN;
252     ret = POPs;
253     PUTBACK;
254
255     return ret;
256 }
257
258 int
259 mouse_predicate_call(pTHX_ SV* const self, SV* const method) {
260     return sv_true( mcall0(self, method) );
261 }
262
263 SV*
264 mouse_get_metaclass(pTHX_ SV* metaclass_name){
265     dMY_CXT;
266     HE* he;
267
268     assert(metaclass_name);
269     assert(MY_CXT.metas);
270
271     if(IsObject(metaclass_name)){
272         HV* const stash = SvSTASH(SvRV(metaclass_name));
273
274         metaclass_name = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U);
275         sv_2mortal(metaclass_name);
276     }
277
278     he = hv_fetch_ent(MY_CXT.metas, metaclass_name, FALSE, 0U);
279
280     return he ? HeVAL(he) : &PL_sv_undef;
281 }
282
283 MAGIC*
284 mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){
285     MAGIC* mg;
286
287     assert(sv != NULL);
288     for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){
289         if(mg->mg_virtual == vtbl){
290             return mg;
291         }
292     }
293
294     if(flags & MOUSEf_DIE_ON_FAIL){
295         croak("mouse_mg_find: no MAGIC found for %"SVf, sv_2mortal(newRV_inc(sv)));
296     }
297     return NULL;
298 }
299
300 GV*
301 mouse_stash_fetch(pTHX_ HV* const stash, const char* const name, I32 const namelen, I32 const create) {
302     GV** const gvp = (GV**)hv_fetch(stash, name, namelen, create);
303
304     if(gvp){
305         if(!isGV(*gvp)){
306             gv_init(*gvp, stash, name, namelen, GV_ADDMULTI);
307         }
308         return *gvp;
309     }
310     else{
311         return NULL;
312     }
313 }
314
315 void
316 mouse_install_sub(pTHX_ GV* const gv, SV* const code_ref) {
317     CV* cv;
318
319     assert(gv != NULL);
320     assert(code_ref != NULL);
321     assert(isGV(gv));
322     assert(IsCodeRef(code_ref));
323
324     if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */
325         SvREFCNT_dec(GvCV(gv));
326         GvCV_set(gv, NULL);
327     }
328
329     sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */
330
331     /* name the CODE ref if it's anonymous */
332     cv = (CV*)SvRV(code_ref);
333     if(CvANON(cv)
334         && CvGV(cv) /* a cv under construction has no gv */ ){
335         HV* dbsub;
336
337         /* update %DB::sub to make NYTProf happy */
338         if((PL_perldb & (PERLDBf_SUBLINE|PERLDB_NAMEANON))
339             && PL_DBsub && (dbsub = GvHV(PL_DBsub))
340         ){
341             /* see Perl_newATTRSUB() in op.c */
342             SV* const subname = sv_newmortal();
343             HE* orig;
344
345             gv_efullname3(subname, CvGV(cv), NULL);
346             orig = hv_fetch_ent(dbsub, subname, FALSE, 0U);
347             if(orig){
348                 gv_efullname3(subname, gv, NULL);
349                 (void)hv_store_ent(dbsub, subname, HeVAL(orig), 0U);
350                 SvREFCNT_inc_simple_void_NN(HeVAL(orig));
351             }
352         }
353
354         CvGV_set(cv, gv);
355         CvANON_off(cv);
356     }
357 }
358
359 MODULE = Mouse::Util  PACKAGE = Mouse::Util
360
361 PROTOTYPES:   DISABLE
362 VERSIONCHECK: DISABLE
363
364 BOOT:
365 {
366     MY_CXT_INIT;
367     MY_CXT.metas = NULL;
368 }
369
370 void
371 __register_metaclass_storage(HV* metas, bool cloning)
372 CODE:
373 {
374     if(cloning){
375         MY_CXT_CLONE;
376         MY_CXT.metas = NULL;
377     }
378     {
379         dMY_CXT;
380         if(MY_CXT.metas && ckWARN(WARN_REDEFINE)){
381             Perl_warner(aTHX_ packWARN(WARN_REDEFINE), "Metaclass storage more than once");
382         }
383         MY_CXT.metas = metas;
384         SvREFCNT_inc_simple_void_NN(metas);
385     }
386 }
387
388 bool
389 is_valid_class_name(SV* sv)
390 CODE:
391 {
392     SvGETMAGIC(sv);
393     if(SvPOKp(sv) && SvCUR(sv) > 0){
394         UV i;
395         RETVAL = TRUE;
396         for(i = 0; i < SvCUR(sv); i++){
397             char const c = SvPVX(sv)[i];
398             if(!(isALNUM(c) || c == ':')){
399                 RETVAL = FALSE;
400                 break;
401             }
402         }
403     }
404     else{
405         RETVAL = SvNIOKp(sv) ? TRUE : FALSE;
406     }
407 }
408 OUTPUT:
409     RETVAL
410
411 bool
412 is_class_loaded(SV* sv)
413
414 void
415 get_code_info(CV* code)
416 PREINIT:
417     GV* gv;
418     HV* stash;
419 PPCODE:
420     if((gv = CvGV(code)) && isGV(gv) && (stash = GvSTASH(gv))){
421         EXTEND(SP, 2);
422         mPUSHs(newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U));
423         mPUSHs(newSVpvn_share(GvNAME_get(gv), GvNAMELEN_get(gv), 0U));
424     }
425
426 SV*
427 get_code_package(CV* code)
428 PREINIT:
429     HV* stash;
430 CODE:
431     if(CvGV(code) && isGV(CvGV(code)) && (stash = GvSTASH(CvGV(code)))){
432         RETVAL = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U);
433     }
434     else{
435         RETVAL = &PL_sv_no;
436     }
437 OUTPUT:
438     RETVAL
439
440 CV*
441 get_code_ref(SV* package, SV* name)
442 CODE:
443 {
444     HV* stash;
445     STRLEN name_len;
446     const char* name_pv;
447     GV* gv;
448
449     must_defined(package, "a package name");
450     must_defined(name,    "a subroutine name");
451
452     stash = gv_stashsv(package, FALSE);
453     if(!stash){
454         XSRETURN_UNDEF;
455     }
456
457     name_pv = SvPV_const(name, name_len);
458     gv = stash_fetch(stash, name_pv, name_len, FALSE);
459     RETVAL = gv ? GvCVu(gv) : NULL;
460
461     if(!RETVAL){
462         XSRETURN_UNDEF;
463     }
464 }
465 OUTPUT:
466     RETVAL
467
468 void
469 generate_isa_predicate_for(SV* arg, SV* predicate_name = NULL)
470 ALIAS:
471     generate_isa_predicate_for = 0
472     generate_can_predicate_for = 1
473 PPCODE:
474 {
475     const char* name_pv = NULL;
476     CV* xsub;
477
478     must_defined(arg, ix == 0 ? "a class_name" : "method names");
479
480     if(predicate_name){
481         must_defined(predicate_name, "a predicate name");
482         name_pv = SvPV_nolen_const(predicate_name);
483     }
484
485     if(ix == 0){
486         xsub = mouse_generate_isa_predicate_for(aTHX_ arg, name_pv);
487     }
488     else{
489         xsub = mouse_generate_can_predicate_for(aTHX_ arg, name_pv);
490     }
491
492     if(predicate_name == NULL){ /* anonymous predicate */
493         mXPUSHs( newRV_inc((SV*)xsub) );
494     }
495 }
496
497 # This xsub will redefine &Mouse::Util::install_subroutines()
498 void
499 install_subroutines(SV* into, ...)
500 CODE:
501 {
502     HV* stash;
503     I32 i;
504
505     must_defined(into, "a package name");
506     stash = gv_stashsv(into, TRUE);
507
508     if( ((items-1) % 2) != 0 ){
509         croak_xs_usage(cv, "into, name => coderef [, other_name, other_coderef ...]");
510     }
511
512     for(i = 1; i < items; i += 2) {
513         SV* const name = ST(i);
514         SV* const code = ST(i+1);
515         STRLEN len;
516         const char* pv;
517         GV* gv;
518
519         must_defined(name, "a subroutine name");
520         must_ref(code, "a CODE reference", SVt_PVCV);
521
522         pv = SvPV_const(name, len);
523         gv = stash_fetch(stash, pv, len, TRUE);
524
525         mouse_install_sub(aTHX_ gv, code);
526     }
527 }