No -T in tests
[gitmo/Mouse.git] / xs-src / MouseUtil.xs
CommitLineData
646c0371 1#include "mouse.h"
2
3#define ISA_CACHE "::LINEALIZED_ISA_CACHE::"
4
5#ifdef no_mro_get_linear_isa
6AV*
7mouse_mro_get_linear_isa(pTHX_ HV* const stash){
6582d0e3 8 GV* const cachegv = *(GV**)hv_fetchs(stash, ISA_CACHE, TRUE);
9 AV* isa;
10 SV* gen;
11 CV* get_linear_isa;
12
13 if(!isGV(cachegv))
14 gv_init(cachegv, stash, ISA_CACHE, sizeof(ISA_CACHE)-1, TRUE);
15
16 isa = GvAVn(cachegv);
17 gen = GvSVn(cachegv);
18
19
20 if(SvIOK(gen) && SvIVX(gen) == (IV)mro_get_pkg_gen(stash)){
21 return isa; /* returns the cache if available */
22 }
23 else{
cd658d1f 24 SvREFCNT_dec(isa);
25 GvAV(cachegv) = isa = newAV();
6582d0e3 26 }
27
28 get_linear_isa = get_cv("Mouse::Util::get_linear_isa", TRUE);
29
30 {
31 SV* avref;
32 dSP;
33
34 ENTER;
35 SAVETMPS;
36
37 PUSHMARK(SP);
38 mXPUSHp(HvNAME_get(stash), HvNAMELEN_get(stash));
39 PUTBACK;
40
41 call_sv((SV*)get_linear_isa, G_SCALAR);
42
43 SPAGAIN;
44 avref = POPs;
45 PUTBACK;
46
80aa5731 47 if(IsArrayRef(avref)){
6582d0e3 48 AV* const av = (AV*)SvRV(avref);
49 I32 const len = AvFILLp(av) + 1;
50 I32 i;
51
52 for(i = 0; i < len; i++){
53 HV* const stash = gv_stashsv(AvARRAY(av)[i], FALSE);
54 if(stash)
55 av_push(isa, newSVpv(HvNAME(stash), 0));
56 }
57 SvREADONLY_on(isa);
58 }
59 else{
60 Perl_croak(aTHX_ "Mouse:Util::get_linear_isa() didn't return an ARRAY reference");
61 }
62
63 FREETMPS;
64 LEAVE;
65 }
66
67 sv_setiv(gen, (IV)mro_get_pkg_gen(stash));
cd658d1f 68 return isa;
646c0371 69}
70#endif /* !no_mor_get_linear_isa */
71
72#ifdef DEBUGGING
73SV**
74mouse_av_at_safe(pTHX_ AV* const av, I32 const ix){
75 assert(av);
76 assert(SvTYPE(av) == SVt_PVAV);
77 assert(AvMAX(av) >= ix);
78 return &AvARRAY(av)[ix];
79}
80#endif
81
82void
83mouse_throw_error(SV* const metaobject, SV* const data /* not used */, const char* const fmt, ...){
84 dTHX;
85 va_list args;
86 SV* message;
87
88 PERL_UNUSED_ARG(data); /* for moose-compat */
89
90 assert(metaobject);
91 assert(fmt);
92
93 va_start(args, fmt);
94 message = vnewSVpvf(fmt, &args);
95 va_end(args);
96
97 {
98 dSP;
99 PUSHMARK(SP);
100 EXTEND(SP, 4);
101
102 PUSHs(metaobject);
103 mPUSHs(message);
104
105 mPUSHs(newSVpvs("depth"));
106 mPUSHi(-1);
107
108 PUTBACK;
109
110 call_method("throw_error", G_VOID);
111 croak("throw_error() did not throw the error (%"SVf")", message);
112 }
113}
114
646c0371 115bool
116mouse_is_class_loaded(pTHX_ SV * const klass){
117 HV *stash;
118 GV** gvp;
119 HE* he;
120
121 if (!(SvPOKp(klass) && SvCUR(klass))) { /* XXX: SvPOK does not work with magical scalars */
122 return FALSE;
123 }
124
125 stash = gv_stashsv(klass, FALSE);
126 if (!stash) {
127 return FALSE;
128 }
129
130 if (( gvp = (GV**)hv_fetchs(stash, "VERSION", FALSE) )) {
131 if(isGV(*gvp) && GvSV(*gvp) && SvOK(GvSV(*gvp))){
132 return TRUE;
133 }
134 }
135
136 if (( gvp = (GV**)hv_fetchs(stash, "ISA", FALSE) )) {
137 if(isGV(*gvp) && GvAV(*gvp) && av_len(GvAV(*gvp)) != -1){
138 return TRUE;
139 }
140 }
141
142 hv_iterinit(stash);
143 while(( he = hv_iternext(stash) )){
144 GV* const gv = (GV*)HeVAL(he);
145
146 if(isGV(gv)){
147 if(GvCVu(gv)){
148 return TRUE;
149 }
150 }
151 else if(SvOK(gv)){
152 return TRUE;
153 }
154 }
155 return FALSE;
156}
157
158
0aad0266 159SV*
160mouse_call0 (pTHX_ SV* const self, SV* const method) {
646c0371 161 dSP;
162 SV *ret;
163
164 PUSHMARK(SP);
165 XPUSHs(self);
166 PUTBACK;
167
168 call_sv(method, G_SCALAR | G_METHOD);
169
170 SPAGAIN;
171 ret = POPs;
172 PUTBACK;
173
174 return ret;
175}
176
0aad0266 177SV*
178mouse_call1 (pTHX_ SV* const self, SV* const method, SV* const arg1) {
646c0371 179 dSP;
180 SV *ret;
181
182 PUSHMARK(SP);
183 EXTEND(SP, 2);
184 PUSHs(self);
185 PUSHs(arg1);
186 PUTBACK;
187
188 call_sv(method, G_SCALAR | G_METHOD);
189
190 SPAGAIN;
191 ret = POPs;
192 PUTBACK;
193
194 return ret;
195}
196
0aad0266 197int
198mouse_predicate_call(pTHX_ SV* const self, SV* const method) {
199 SV* const value = mcall0(self, method);
200 return SvTRUE(value);
201}
202
a39e9541 203SV*
aa2d2e2c 204mouse_get_metaclass(pTHX_ SV* metaclass_name){
a39e9541 205 CV* const get_metaclass = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE);
206 SV* metaclass;
207 dSP;
208
aa2d2e2c 209 assert(metaclass_name);
210 if(IsObject(metaclass_name)){
211 HV* const stash = SvSTASH(metaclass_name);
212
213 metaclass_name = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U);
214 sv_2mortal(metaclass_name);
215 }
216
a39e9541 217 PUSHMARK(SP);
218 XPUSHs(metaclass_name);
219 PUTBACK;
220
221 call_sv((SV*)get_metaclass, G_SCALAR);
222
223 SPAGAIN;
224 metaclass = POPs;
225 PUTBACK;
226
227 return metaclass;
228}
229
646c0371 230MAGIC*
231mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){
232 MAGIC* mg;
233
234 assert(sv != NULL);
235 for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){
236 if(mg->mg_virtual == vtbl){
237 return mg;
238 }
239 }
240
241 if(flags & MOUSEf_DIE_ON_FAIL){
242 croak("mouse_mg_find: no MAGIC found for %"SVf, sv_2mortal(newRV_inc(sv)));
243 }
244 return NULL;
245}
246
a39e9541 247GV*
248mouse_stash_fetch(pTHX_ HV* const stash, const char* const name, I32 const namelen, I32 const create) {
249 GV** const gvp = (GV**)hv_fetch(stash, name, namelen, create);
250
251 if(gvp){
252 if(!isGV(*gvp)){
253 gv_init(*gvp, stash, name, namelen, GV_ADDMULTI);
254 }
255 return *gvp;
256 }
257 else{
258 return NULL;
259 }
260}
261
646c0371 262MODULE = Mouse::Util PACKAGE = Mouse::Util
263
264PROTOTYPES: DISABLE
265VERSIONCHECK: DISABLE
266
267bool
268is_class_loaded(SV* sv)
269
270void
271get_code_info(CV* code)
272PREINIT:
273 GV* gv;
274 HV* stash;
275PPCODE:
276 if((gv = CvGV(code)) && isGV(gv) && (stash = GvSTASH(gv))){
277 EXTEND(SP, 2);
278 mPUSHs(newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U));
279 mPUSHs(newSVpvn_share(GvNAME_get(gv), GvNAMELEN_get(gv), 0U));
280 }
281
282SV*
283get_code_package(CV* code)
284PREINIT:
285 HV* stash;
286CODE:
287 if(CvGV(code) && isGV(CvGV(code)) && (stash = GvSTASH(CvGV(code)))){
288 RETVAL = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U);
289 }
290 else{
291 RETVAL = &PL_sv_no;
292 }
293OUTPUT:
294 RETVAL
295
296CV*
297get_code_ref(SV* package, SV* name)
298CODE:
299{
300 HV* stash;
a39e9541 301 STRLEN name_len;
302 const char* name_pv;
303 GV* gv;
646c0371 304
305 if(!SvOK(package)){
306 croak("You must define a package name");
307 }
308 if(!SvOK(name)){
309 croak("You must define a subroutine name");
310 }
311
312 stash = gv_stashsv(package, FALSE);
313 if(!stash){
314 XSRETURN_UNDEF;
315 }
a39e9541 316
317 name_pv = SvPV_const(name, name_len);
318 gv = stash_fetch(stash, name_pv, name_len, FALSE);
319 RETVAL = gv ? GvCVu(gv) : NULL;
646c0371 320
321 if(!RETVAL){
322 XSRETURN_UNDEF;
323 }
324}
325OUTPUT:
326 RETVAL
327
328void
441964ce 329generate_isa_predicate_for(SV* klass, SV* predicate_name = NULL)
646c0371 330PPCODE:
331{
441964ce 332 const char* name_pv = NULL;
646c0371 333 CV* xsub;
334
441964ce 335 SvGETMAGIC(klass);
336
646c0371 337 if(!SvOK(klass)){
441964ce 338 croak("You must define a class name");
646c0371 339 }
646c0371 340
441964ce 341 if(predicate_name){
342 SvGETMAGIC(predicate_name);
343 if(!SvOK(predicate_name)){
344 croak("You must define a predicate_name");
345 }
346 name_pv = SvPV_nolen_const(predicate_name);
646c0371 347 }
348
672bde7c 349 xsub = mouse_generate_isa_predicate_for(aTHX_ klass, name_pv);
441964ce 350
646c0371 351 if(predicate_name == NULL){ /* anonymous predicate */
352 XPUSHs( newRV_noinc((SV*)xsub) );
353 }
354}