Implement XS accessor generators
[gitmo/Mouse.git] / xs-src / mouse_util.xs
CommitLineData
df6dd016 1#include "mouse.h"
2
cccb83de 3#define ISA_CACHE "::LINEALIZED_ISA_CACHE::"
4
5#ifndef no_mro_get_linear_isa
6AV*
7mouse_mro_get_linear_isa(pTHX_ HV* const stash){
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{
24 SvREADONLY_off(isa);
25 av_clear(isa);
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
47 if(SvROK(avref) && SvTYPE(SvRV(avref)) == SVt_PVAV){
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));
68 return GvAV(cachegv);
69}
70#endif /* !no_mor_get_linear_isa */
71
93540011 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
cccb83de 115
df6dd016 116/* equivalent to "blessed($x) && $x->isa($klass)" */
117bool
118mouse_is_instance_of(pTHX_ SV* const sv, SV* const klass){
119 assert(sv);
120 assert(klass);
121
122 if(IsObject(sv) && SvOK(klass)){
123 bool ok;
124
125 ENTER;
126 SAVETMPS;
127
128 ok = SvTRUEx(mcall1s(sv, "isa", klass));
129
130 FREETMPS;
131 LEAVE;
132
133 return ok;
134 }
135
136 return FALSE;
137}
138
139
140bool
141mouse_is_class_loaded(pTHX_ SV * const klass){
142 HV *stash;
143 GV** gvp;
144 HE* he;
145
146 if (!(SvPOKp(klass) && SvCUR(klass))) { /* XXX: SvPOK does not work with magical scalars */
147 return FALSE;
148 }
149
150 stash = gv_stashsv(klass, FALSE);
151 if (!stash) {
152 return FALSE;
153 }
154
155 if (( gvp = (GV**)hv_fetchs(stash, "VERSION", FALSE) )) {
156 if(isGV(*gvp) && GvSV(*gvp) && SvOK(GvSV(*gvp))){
157 return TRUE;
158 }
159 }
160
161 if (( gvp = (GV**)hv_fetchs(stash, "ISA", FALSE) )) {
162 if(isGV(*gvp) && GvAV(*gvp) && av_len(GvAV(*gvp)) != -1){
163 return TRUE;
164 }
165 }
166
167 hv_iterinit(stash);
168 while(( he = hv_iternext(stash) )){
169 GV* const gv = (GV*)HeVAL(he);
170
171 if(isGV(gv)){
172 if(GvCVu(gv)){
173 return TRUE;
174 }
175 }
176 else if(SvOK(gv)){
177 return TRUE;
178 }
179 }
180 return FALSE;
181}
182
183
184SV *
185mouse_call0 (pTHX_ SV *const self, SV *const method)
186{
187 dSP;
188 SV *ret;
189
190 PUSHMARK(SP);
191 XPUSHs(self);
192 PUTBACK;
193
194 call_sv(method, G_SCALAR | G_METHOD);
195
196 SPAGAIN;
197 ret = POPs;
198 PUTBACK;
199
200 return ret;
201}
202
203SV *
204mouse_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1)
205{
206 dSP;
207 SV *ret;
208
209 PUSHMARK(SP);
210 EXTEND(SP, 2);
211 PUSHs(self);
212 PUSHs(arg1);
213 PUTBACK;
214
215 call_sv(method, G_SCALAR | G_METHOD);
216
217 SPAGAIN;
218 ret = POPs;
219 PUTBACK;
220
221 return ret;
222}
223
43165725 224MAGIC*
225mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){
226 MAGIC* mg;
227
228 assert(sv != NULL);
229 for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){
230 if(mg->mg_virtual == vtbl){
231 return mg;
232 }
233 }
234
235 if(flags & MOUSEf_DIE_ON_FAIL){
236 croak("mouse_mg_find: no MAGIC found for %"SVf, sv_2mortal(newRV_inc(sv)));
237 }
238 return NULL;
239}