Changelogging
[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;
cccb83de 8
da4432f3 9static SV* mouse_all_attrs_cache;
10static SV* mouse_all_attrs_cache_gen;
11
12AV*
13mouse_get_all_attributes(pTHX_ SV* const metaclass){
14 SV* const package = get_slot(metaclass, mouse_package);
15 HV* const stash = gv_stashsv(package, TRUE);
16 UV const pkg_gen = mro_get_pkg_gen(stash);
17 SV* cache_gen = get_slot(metaclass, mouse_all_attrs_cache_gen);
18
19 if(!(cache_gen && pkg_gen == SvUV(cache_gen))){ /* update */
20 CV* const get_metaclass = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE);
743ca82e 21 AV* const all_attrs = newAV();
22 SV* const get_attribute = newSVpvs_share("get_attribute");
23
da4432f3 24 AV* const linearized_isa = mro_get_linear_isa(stash);
25 I32 const len = AvFILLp(linearized_isa);
26 I32 i;
27 HV* seen;
da4432f3 28
29 /* warn("Update all_attrs_cache (cache_gen %d != pkg_gen %d)", (cache_gen ? (int)SvIV(cache_gen) : 0), (int)pkg_gen); //*/
30
31 ENTER;
32 SAVETMPS;
33
743ca82e 34 sv_2mortal(get_attribute);
35
da4432f3 36 set_slot(metaclass, mouse_all_attrs_cache, sv_2mortal(newRV_inc((SV*)all_attrs)));
37
38 seen = newHV();
39 sv_2mortal((SV*)seen);
40
41 for(i = 0; i < len; i++){
42 SV* const klass = MOUSE_av_at(linearized_isa, i);
43 SV* meta;
44 I32 n;
45 dSP;
46
47 PUSHMARK(SP);
48 XPUSHs(klass);
49 PUTBACK;
50
51 call_sv((SV*)get_metaclass, G_SCALAR);
52
53 SPAGAIN;
54 meta = POPs;
55 PUTBACK;
56
57 if(!SvOK(meta)){
58 continue; /* skip non-Mouse classes */
59 }
60
61 /* $meta->get_attribute_list */
62 PUSHMARK(SP);
63 XPUSHs(meta);
64 PUTBACK;
65
66 n = call_method("get_attribute_list", G_ARRAY);
67 for(NOOP; n > 0; n--){
68 SV* name;
69
70 SPAGAIN;
71 name = POPs;
72 PUTBACK;
73
74 if(hv_exists_ent(seen, name, 0U)){
75 continue;
76 }
77 (void)hv_store_ent(seen, name, &PL_sv_undef, 0U);
78
743ca82e 79 av_push(all_attrs, newSVsv( mcall1(meta, get_attribute, name) ));
da4432f3 80 }
81 }
82
83 if(!cache_gen){
84 cache_gen = sv_newmortal();
85 }
86 sv_setuv(cache_gen, mro_get_pkg_gen(stash));
87 set_slot(metaclass, mouse_all_attrs_cache_gen, cache_gen);
88
89 FREETMPS;
90 LEAVE;
91
92 return all_attrs;
93 }
94 else {
95 SV* const all_attrs_ref = get_slot(metaclass, mouse_all_attrs_cache);
96
97 if(!IsArrayRef(all_attrs_ref)){
98 croak("Not an ARRAY reference");
99 }
100
101 return (AV*)SvRV(all_attrs_ref);
102 }
103}
104
646c0371 105MODULE = Mouse PACKAGE = Mouse
df6dd016 106
107PROTOTYPES: DISABLE
108
cccb83de 109BOOT:
110 mouse_package = newSVpvs_share("package");
111 mouse_namespace = newSVpvs_share("namespace");
3e44140b 112 mouse_methods = newSVpvs_share("methods");
a5df48e5 113 mouse_name = newSVpvs_share("name");
3e44140b 114
da4432f3 115 mouse_all_attrs_cache = newSVpvs_share("__all_attrs_cache");
116 mouse_all_attrs_cache_gen = newSVpvs_share("__all_attrs_cache_gen");
117
646c0371 118 MOUSE_CALL_BOOT(Mouse__Util);
1d5ecd5f 119 MOUSE_CALL_BOOT(Mouse__Util__TypeConstraints);
646c0371 120 MOUSE_CALL_BOOT(Mouse__Meta__Method__Accessor__XS);
f48920c1 121
cccb83de 122
7d96ae4d 123MODULE = Mouse PACKAGE = Mouse::Meta::Module
124
125BOOT:
126 INSTALL_SIMPLE_READER_WITH_KEY(Module, name, package);
127 INSTALL_SIMPLE_READER_WITH_KEY(Module, _method_map, methods);
128 INSTALL_SIMPLE_READER_WITH_KEY(Module, _attribute_map, attributes);
129
130HV*
131namespace(SV* self)
132CODE:
133{
6a97bbda 134 SV* const package = get_slot(self, mouse_package);
7d96ae4d 135 if(!(package && SvOK(package))){
3e44140b 136 croak("No package name defined");
7d96ae4d 137 }
138 RETVAL = gv_stashsv(package, GV_ADDMULTI);
139}
140OUTPUT:
141 RETVAL
142
3e44140b 143# ignore extra arguments for extensibility
144void
145add_method(SV* self, SV* name, SV* code, ...)
146CODE:
147{
6a97bbda 148 SV* const package = get_slot(self, mouse_package); /* $self->{package} */
149 SV* const methods = get_slot(self, mouse_methods); /* $self->{methods} */
3e44140b 150 GV* gv;
151 SV* code_ref;
152
153 if(!(package && SvOK(package))){
154 croak("No package name defined");
155 }
156
157 SvGETMAGIC(name);
158 SvGETMAGIC(code);
159
160 if(!SvOK(name)){
161 mouse_throw_error(self, NULL, "You must define a method name");
162 }
163 if(!SvROK(code)){
164 mouse_throw_error(self, NULL, "You must define a CODE reference");
165 }
166
167 code_ref = code;
168 if(SvTYPE(SvRV(code_ref)) != SVt_PVCV){
169 SV* sv = code_ref; /* used in tryAMAGICunDEREF */
170 SV** sp = &sv; /* used in tryAMAGICunDEREF */
171 tryAMAGICunDEREF(to_cv); /* try \&{$code} */
172 if(SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV){
173 mouse_throw_error(self, NULL, "Not a CODE reference");
174 }
175 code_ref = sv;
176 }
177
178 /* *{$package . '::' . $name} -> *gv */
179 gv = gv_fetchpv(form("%"SVf"::%"SVf, package, name), GV_ADDMULTI, SVt_PVCV);
180 if(GvCVu(gv)){ /* delete *slot{gv} to work around "redefine" warning */
181 SvREFCNT_dec(GvCV(gv));
182 GvCV(gv) = NULL;
183 }
184 sv_setsv_mg((SV*)gv, code_ref); /* *gv = $code_ref */
185
6fe2272b 186 set_slot(methods, name, code); /* $self->{methods}{$name} = $code */
3e44140b 187
188 /* TODO: name the CODE ref if it's anonymous */
189 //code_entity = (CV*)SvRV(code_ref);
190 //if(CvANON(code_entity)
191 // && CvGV(code_entity) /* a cv under construction has no gv */ ){
192
193 // CvGV(code_entity) = gv;
194 // CvANON_off(code_entity);
195 //}
196}
197
43165725 198MODULE = Mouse PACKAGE = Mouse::Meta::Class
199
200BOOT:
201 INSTALL_SIMPLE_READER(Class, roles);
202 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Class, is_anon_class, anon_serial_id);
203
cccb83de 204void
205linearized_isa(SV* self)
206PPCODE:
207{
208 SV* const stash_ref = mcall0(self, mouse_namespace); /* $self->namespace */
209 AV* linearized_isa;
210 I32 len;
211 I32 i;
212 if(!(SvROK(stash_ref) && SvTYPE(SvRV(stash_ref)) == SVt_PVHV)){
213 croak("namespace() didn't return a HASH reference");
214 }
215 linearized_isa = mro_get_linear_isa((HV*)SvRV(stash_ref));
216 len = AvFILLp(linearized_isa) + 1;
217 EXTEND(SP, len);
218 for(i = 0; i < len; i++){
219 PUSHs(AvARRAY(linearized_isa)[i]);
220 }
221}
222
da4432f3 223void
224get_all_attributes(SV* self)
225PPCODE:
226{
227 AV* const all_attrs = mouse_get_all_attributes(aTHX_ self);
228 I32 const len = AvFILLp(all_attrs) + 1;
229 I32 i;
230
231 EXTEND(SP, len);
232 for(i = 0; i < len; i++){
233 PUSHs( MOUSE_av_at(all_attrs, i) );
234 }
235}
441964ce 236
43165725 237MODULE = Mouse PACKAGE = Mouse::Meta::Role
238
239BOOT:
240 INSTALL_SIMPLE_READER_WITH_KEY(Role, get_roles, roles);
241 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Role, is_anon_role, anon_serial_id);
242
43165725 243MODULE = Mouse PACKAGE = Mouse::Meta::Attribute
244
245BOOT:
246 /* readers */
247 INSTALL_SIMPLE_READER(Attribute, name);
248 INSTALL_SIMPLE_READER(Attribute, associated_class);
249 INSTALL_SIMPLE_READER(Attribute, accessor);
250 INSTALL_SIMPLE_READER(Attribute, reader);
251 INSTALL_SIMPLE_READER(Attribute, writer);
252 INSTALL_SIMPLE_READER(Attribute, predicate);
253 INSTALL_SIMPLE_READER(Attribute, clearer);
254 INSTALL_SIMPLE_READER(Attribute, handles);
255
256 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, _is_metadata, is);
257 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_required, required);
258 INSTALL_SIMPLE_READER(Attribute, default);
259 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy, lazy);
260 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_lazy_build, lazy_build);
261 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, is_weak_ref, weak_ref);
262 INSTALL_SIMPLE_READER(Attribute, init_arg);
263 INSTALL_SIMPLE_READER(Attribute, type_constraint);
264 INSTALL_SIMPLE_READER(Attribute, trigger);
265 INSTALL_SIMPLE_READER(Attribute, builder);
266 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_auto_deref, auto_deref);
267 INSTALL_SIMPLE_READER_WITH_KEY(Attribute, should_coerce, coerce);
268 INSTALL_SIMPLE_READER(Attribute, documentation);
269
270 /* predicates */
271 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_accessor, accessor);
272 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_reader, reader);
273 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_writer, writer);
274 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_predicate, predicate);
275 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_clearer, clearer);
276 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_handles, handles);
277
278 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_default, default);
279 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_type_constraint, type_constraint);
280 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_trigger, trigger);
281 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_builder, builder);
282 INSTALL_SIMPLE_PREDICATE_WITH_KEY(Attribute, has_documentation, documentation);
283
93540011 284 newCONSTSUB(gv_stashpvs("Mouse::Meta::Attribute", TRUE), "accessor_metaclass",
285 newSVpvs("Mouse::Meta::Method::Accessor::XS"));
286