Make is_class_loaded without any arguments fail loudly
[gitmo/Mouse.git] / xs-src / Mouse.xs
1 #include "mouse.h"
2
3 SV* mouse_package;
4 SV* mouse_namespace;
5 SV* mouse_methods;
6 SV* mouse_name;
7
8 MODULE = Mouse  PACKAGE = Mouse::Util
9
10 PROTOTYPES: DISABLE
11
12 BOOT:
13     mouse_package   = newSVpvs_share("package");
14     mouse_namespace = newSVpvs_share("namespace");
15     mouse_methods   = newSVpvs_share("methods");
16     mouse_name      = newSVpvs_share("name");
17
18     MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints);
19
20
21 bool
22 is_class_loaded(SV* sv)
23
24 void
25 get_code_info(CV* code)
26 PREINIT:
27     GV* gv;
28     HV* stash;
29 PPCODE:
30     if((gv = CvGV(code)) && isGV(gv) && (stash = GvSTASH(gv))){
31         EXTEND(SP, 2);
32         mPUSHs(newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U));
33         mPUSHs(newSVpvn_share(GvNAME_get(gv), GvNAMELEN_get(gv), 0U));
34     }
35
36 SV*
37 get_code_package(CV* code)
38 PREINIT:
39     HV* stash;
40 CODE:
41     if(CvGV(code) && isGV(CvGV(code)) && (stash = GvSTASH(CvGV(code)))){
42         RETVAL = newSVpvn_share(HvNAME_get(stash), HvNAMELEN_get(stash), 0U);
43     }
44     else{
45         RETVAL = &PL_sv_no;
46     }
47 OUTPUT:
48     RETVAL
49
50 CV*
51 get_code_ref(SV* package, SV* name)
52 CODE:
53 {
54     HV* stash;
55     HE* he;
56
57     if(!SvOK(package)){
58         croak("You must define a package name");
59     }
60     if(!SvOK(name)){
61         croak("You must define a subroutine name");
62     }
63
64     stash = gv_stashsv(package, FALSE);
65     if(!stash){
66         XSRETURN_UNDEF;
67     }
68     he = hv_fetch_ent(stash, name, FALSE, 0U);
69     if(he){
70         GV* const gv = (GV*)hv_iterval(stash, he);
71         if(!isGV(gv)){ /* special constant or stub */
72             STRLEN len;
73             const char* const pv = SvPV_const(name, len);
74             gv_init(gv, stash, pv, len, GV_ADDMULTI);
75         }
76         RETVAL = GvCVu(gv);
77     }
78     else{
79         RETVAL = NULL;
80     }
81
82     if(!RETVAL){
83         XSRETURN_UNDEF;
84     }
85 }
86 OUTPUT:
87     RETVAL
88
89
90 MODULE = Mouse  PACKAGE = Mouse::Meta::Module
91
92 BOOT:
93     INSTALL_SIMPLE_READER_WITH_KEY(Module, name, package);
94     INSTALL_SIMPLE_READER_WITH_KEY(Module, _method_map, methods);
95     INSTALL_SIMPLE_READER_WITH_KEY(Module, _attribute_map, attributes);
96
97 HV*
98 namespace(SV* self)
99 CODE:
100 {
101     SV* const package = mouse_instance_get_slot(aTHX_ self, mouse_package);
102     if(!(package && SvOK(package))){
103         croak("No package name defined");
104     }
105     RETVAL = gv_stashsv(package, GV_ADDMULTI);
106 }
107 OUTPUT:
108     RETVAL
109
110 # ignore extra arguments for extensibility
111 void
112 add_method(SV* self, SV* name, SV* code, ...)
113 CODE:
114 {
115     SV* const package = mouse_instance_get_slot(aTHX_ self, mouse_package); /* $self->{package} */
116     SV* const methods = mouse_instance_get_slot(aTHX_ self, mouse_methods); /* $self->{methods} */
117     GV* gv;
118     SV* code_ref;
119
120     if(!(package && SvOK(package))){
121         croak("No package name defined");
122     }
123
124     SvGETMAGIC(name);
125     SvGETMAGIC(code);
126
127     if(!SvOK(name)){
128         mouse_throw_error(self, NULL, "You must define a method name");
129     }
130     if(!SvROK(code)){
131         mouse_throw_error(self, NULL, "You must define a CODE reference");
132     }
133
134     code_ref = code;
135     if(SvTYPE(SvRV(code_ref)) != SVt_PVCV){
136         SV*  sv = code_ref;  /* used in tryAMAGICunDEREF */
137         SV** sp = &sv;       /* used in tryAMAGICunDEREF */
138         tryAMAGICunDEREF(to_cv); /* try \&{$code} */
139         if(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV){
140             mouse_throw_error(self, NULL, "Not a CODE reference");
141         }
142         code_ref = sv;
143     }
144
145     /*  *{$package . '::' . $name} -> *gv */
146     gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV);
147     if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */
148         SvREFCNT_dec(GvCV(gv));
149         GvCV(gv) = NULL;
150     }
151     sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */
152
153     mouse_instance_set_slot(aTHX_ methods, name, code); /* $self->{methods}{$name} = $code */
154
155     /* TODO: name the CODE ref if it's anonymous */
156     //code_entity = (CV*)SvRV(code_ref);
157     //if(CvANON(code_entity)
158     //    && CvGV(code_entity) /* a cv under construction has no gv */ ){
159
160     //    CvGV(code_entity) = gv;
161     //    CvANON_off(code_entity);
162     //}
163 }
164
165 MODULE = Mouse  PACKAGE = Mouse::Meta::Class
166
167 BOOT:
168     INSTALL_SIMPLE_READER(Class, roles);
169     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id);
170
171 void
172 linearized_isa(SV* self)
173 PPCODE:
174 {
175     SV* const stash_ref = mcall0(self, mouse_namespace); /* $self->namespace */
176     AV* linearized_isa;
177     I32 len;
178     I32 i;
179     if(!(SvROK(stash_ref) && SvTYPE(SvRV(stash_ref)) == SVt_PVHV)){
180         croak("namespace() didn't return a HASH reference");
181     }
182     linearized_isa = mro_get_linear_isa((HV*)SvRV(stash_ref));
183     len = AvFILLp(linearized_isa) + 1;
184     EXTEND(SP, len);
185     for(i = 0; i < len; i++){
186         PUSHs(AvARRAY(linearized_isa)[i]);
187     }
188 }
189
190 MODULE = Mouse  PACKAGE = Mouse::Meta::Role
191
192 BOOT:
193     INSTALL_SIMPLE_READER_WITH_KEY(Role, get_roles, roles);
194     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Role, is_anon_role, anon_serial_id);
195
196 MODULE = Mouse  PACKAGE = Mouse::Meta::Attribute
197
198 BOOT:
199     /* readers */
200     INSTALL_SIMPLE_READER(Attribute, name);
201     INSTALL_SIMPLE_READER(Attribute, associated_class);
202     INSTALL_SIMPLE_READER(Attribute, accessor);
203     INSTALL_SIMPLE_READER(Attribute, reader);
204     INSTALL_SIMPLE_READER(Attribute, writer);
205     INSTALL_SIMPLE_READER(Attribute, predicate);
206     INSTALL_SIMPLE_READER(Attribute, clearer);
207     INSTALL_SIMPLE_READER(Attribute, handles);
208
209     INSTALL_SIMPLE_READER_WITH_KEY(Attribute, _is_metadata, is);
210     INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_required, required);
211     INSTALL_SIMPLE_READER(Attribute, default);
212     INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy, lazy);
213     INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy_build, lazy_build);
214     INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_weak_ref, weak_ref);
215     INSTALL_SIMPLE_READER(Attribute, init_arg);
216     INSTALL_SIMPLE_READER(Attribute, type_constraint);
217     INSTALL_SIMPLE_READER(Attribute, trigger);
218     INSTALL_SIMPLE_READER(Attribute, builder);
219     INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_auto_deref, auto_deref);
220     INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_coerce, coerce);
221     INSTALL_SIMPLE_READER(Attribute, documentation);
222
223     /* predicates */
224     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_accessor, accessor);
225     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_reader, reader);
226     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_writer, writer);
227     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_predicate, predicate);
228     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_clearer, clearer);
229     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_handles, handles);
230
231     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_default, default);
232     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_type_constraint, type_constraint);
233     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_trigger, trigger);
234     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_builder, builder);
235     INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_documentation, documentation);
236
237     newCONSTSUB(gv_stashpvs("Mouse::Meta::Attribute", TRUE), "accessor_metaclass",
238         newSVpvs("Mouse::Meta::Method::Accessor::XS"));
239
240 MODULE = Mouse  PACKAGE = Mouse::Meta::TypeConstraint
241
242 BOOT:
243     INSTALL_SIMPLE_READER(TypeConstraint, name);
244     INSTALL_SIMPLE_READER(TypeConstraint, parent);
245     INSTALL_SIMPLE_READER(TypeConstraint, message);
246
247     INSTALL_SIMPLE_READER_WITH_KEY(TypeConstraint, _compiled_type_constraint, compiled_type_constraint);
248     INSTALL_SIMPLE_READER(TypeConstraint, _compiled_type_coercion); /* Mouse specific */
249
250     INSTALL_SIMPLE_PREDICATE_WITH_KEY(TypeConstraint, has_coercion, _compiled_type_coercion);
251
252
253 MODULE = Mouse  PACKAGE = Mouse::Meta::Method::Accessor::XS
254
255 CV*
256 _generate_accessor(klass, SV* attr, metaclass)
257 CODE:
258 {
259     RETVAL = mouse_instantiate_xs_accessor(aTHX_ attr, mouse_xs_accessor);
260 }
261 OUTPUT:
262     RETVAL
263
264 CV*
265 _generate_reader(klass, SV* attr, metaclass)
266 CODE:
267 {
268     RETVAL = mouse_instantiate_xs_accessor(aTHX_ attr, mouse_xs_reader);
269 }
270 OUTPUT:
271     RETVAL
272
273 CV*
274 _generate_writer(klass, SV* attr, metaclass)
275 CODE:
276 {
277     RETVAL = mouse_instantiate_xs_accessor(aTHX_ attr, mouse_xs_writer);
278 }
279 OUTPUT:
280     RETVAL
281
282 CV*
283 _generate_clearer(klass, SV* attr, metaclass)
284 CODE:
285 {
286     SV* const slot = mcall0s(attr, "name");
287     STRLEN len;
288     const char* const pv = SvPV_const(slot, len);
289     RETVAL = mouse_install_simple_accessor(aTHX_ NULL, pv, len, mouse_xs_simple_clearer);
290 }
291 OUTPUT:
292     RETVAL
293
294 CV*
295 _generate_predicate(klass, SV* attr, metaclass)
296 CODE:
297 {
298     SV* const slot = mcall0s(attr, "name");
299     STRLEN len;
300     const char* const pv = SvPV_const(slot, len);
301     RETVAL = mouse_install_simple_accessor(aTHX_ NULL, pv, len, mouse_xs_simple_predicate);
302 }
303 OUTPUT:
304     RETVAL
305