Mercurial > projects > qtd
annotate d2/qtd/meta/Runtime.d @ 364:a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
author | Max Samukha <maxter@maxter.com> |
---|---|
date | Fri, 11 Jun 2010 12:16:09 +0300 |
parents | 59d847a814e3 |
children | 958e8b9a89bd |
rev | line source |
---|---|
351 | 1 /************************************************************************** |
2 Copyright: Copyright Max Samukha, 2010 | |
3 Authors: Max Samukha | |
4 License: Boost Software License 1.0 | |
5 **************************************************************************/ | |
6 module qtd.meta.Runtime; | |
7 //TODO: Probably replace switch dispatch with pointer dispatch | |
8 //and leave switch dispatch only in C interface | |
9 | |
10 import | |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
11 qtd.Core, |
351 | 12 qtd.meta.Compiletime, |
13 | |
14 std.typetuple, | |
15 std.conv, | |
16 std.variant, | |
17 core.sync.rwmutex; | |
18 | |
19 private __gshared ReadWriteMutex lock; | |
20 shared static this() | |
21 { | |
22 lock = new ReadWriteMutex; | |
23 } | |
24 | |
25 /** | |
26 IDs of the built-in basic types. | |
27 */ | |
28 enum BasicTypeId | |
29 { | |
30 /// | |
31 void_, | |
32 /// | |
33 bool_, | |
34 /// | |
35 byte_, | |
36 /// | |
37 ubyte_, | |
38 /// | |
39 short_, | |
40 /// | |
41 ushort_, | |
42 /// | |
43 int_, | |
44 /// | |
45 uint_, | |
46 /// | |
47 long_, | |
48 /// | |
49 ulong_, | |
50 /// | |
51 cent_, | |
52 /// | |
53 ucent_, | |
54 /// | |
55 float_, | |
56 /// | |
57 double_, | |
58 /// | |
59 real_, | |
60 /// | |
61 ifloat_, | |
62 /// | |
63 idouble_, | |
64 /// | |
65 ireal_, | |
66 /// | |
67 cfloat_, | |
68 /// | |
69 cdouble_, | |
70 /// | |
71 creal_, | |
72 /// | |
73 char_, | |
74 /// | |
75 wchar_, | |
76 /// | |
77 dchar_ | |
78 } | |
79 | |
80 /** | |
81 Thrown on meta-system errors. | |
82 */ | |
83 class MetaException : Exception | |
84 { | |
85 this(string msg) | |
86 { | |
87 super(msg); | |
88 } | |
89 } | |
90 | |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
91 abstract class MetaBase |
351 | 92 { |
93 alias typeof(this) This; | |
94 | |
95 string name; | |
96 MetaAttribute[] attributes; | |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
97 MetaBase[] members; |
351 | 98 |
99 template createImpl(M : This) | |
100 { | |
101 static M createImpl(alias symbol)() | |
102 { | |
103 auto m = new M; | |
104 m.construct!symbol; | |
105 return m; | |
106 } | |
107 } | |
108 | |
109 private void createAttrs(alias symbol)() | |
110 { | |
111 alias GetAttributes!symbol attrs; | |
112 enum len = attrs.length; // COMPILER BUG | |
113 foreach (i, _; Repeat!(void, len)) | |
114 { | |
115 alias TypeTuple!(attrs[i].tuple) attr; | |
116 // if the third element of the attribute data is a MetaAttribute subclass, | |
117 // use that to create the attribute instance. | |
118 static if (attr.length > 2 && (is(attr[2] : MetaAttribute))) | |
119 { | |
120 alias attr[2] MA; | |
121 alias TypeTuple!(attr[0..2], attr[3..$]) args; | |
122 attributes ~= MA /*COMPILER BUG: tuple element as tuple*/[0].create!args(); | |
123 } | |
124 } | |
125 } | |
126 | |
127 protected void construct(alias symbol)() | |
128 { | |
129 createAttrs!symbol; | |
130 } | |
131 } | |
132 | |
133 /** | |
134 Base class for run time attributes. | |
135 */ | |
136 abstract class MetaAttribute | |
137 { | |
138 alias typeof(this) This; | |
139 | |
140 string name; | |
141 AttributeOptions options; | |
142 | |
143 This create(string name, AttributeOptions opts, A...)() | |
144 { | |
145 auto ma = new This; | |
146 ma.construct!(name, opts, A)(); | |
147 return ma; | |
148 } | |
149 | |
150 void construct(string name, AttributeOptions opts)() | |
151 { | |
152 this.name = name; | |
153 options = opts; | |
154 } | |
155 } | |
156 | |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
157 abstract class MetaType : MetaBase |
351 | 158 { |
159 } | |
160 | |
161 abstract class MetaAggregate : MetaType | |
162 { | |
163 } | |
164 | |
165 class MetaClass : MetaAggregate | |
166 { | |
167 alias typeof(this) This; | |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
168 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
169 private: |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
170 This base_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
171 This firstDerived_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
172 This next_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
173 TypeInfo_Class classInfo_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
174 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
175 this() {} |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
176 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
177 public: |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
178 /** |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
179 Returns the meta-object of the base class. |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
180 */ |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
181 @property |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
182 This base() |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
183 { |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
184 return base_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
185 } |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
186 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
187 /** |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
188 Returns next meta-object on this level of the derivation hierarchy. |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
189 */ |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
190 @property |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
191 This next() |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
192 { |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
193 return next_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
194 } |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
195 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
196 /** |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
197 Returns meta-object of the first derived class. |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
198 */ |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
199 @property |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
200 This firstDerived() |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
201 { |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
202 return firstDerived_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
203 } |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
204 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
205 /** |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
206 D class info. |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
207 */ |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
208 @property |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
209 TypeInfo_Class classInfo() |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
210 { |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
211 return classInfo_; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
212 } |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
213 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
214 /* internal */ alias createImpl!This create; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
215 |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
216 /* internal */ void construct(T : Object)() |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
217 { |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
218 static if (!is(T == Object)) |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
219 { |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
220 alias BaseClassesTuple!(T)[0] Base; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
221 base_ = meta!Base; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
222 } |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
223 classInfo_ = T.classinfo; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
224 } |
351 | 225 } |
226 | |
227 class MetaStruct : MetaAggregate | |
228 { | |
229 alias typeof(this) This; | |
230 alias createImpl!This create; | |
231 } | |
232 | |
233 @property | |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
234 auto meta(alias symbol, M : MetaBase)() |
351 | 235 { |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
236 __gshared static M sharedM; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
237 static M m; |
351 | 238 |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
239 if (!m) |
351 | 240 { |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
241 synchronized(qtdMoLock) |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
242 { |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
243 if (!sharedM) |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
244 sharedM = M.create!symbol; |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
245 } |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
246 m = sharedM; |
351 | 247 } |
248 | |
249 return m; | |
250 } | |
251 | |
252 // only classes and structs for now | |
253 @property | |
254 auto meta(T)() | |
255 { | |
364
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
256 static if (is(T.Meta)) // If the type defines a meta-class - use that. |
a084e2df3776
Preparing for non-QObject meta-objects. Now meta-objects for static types can be uniformly accessed using meta!T
Max Samukha <maxter@maxter.com>
parents:
351
diff
changeset
|
257 return meta!(T, T.Meta); |
351 | 258 else static if (is(T == class)) |
259 return meta!(T, MetaClass); | |
260 else static if (is(T == struct)) | |
261 return meta!(T, MetaStruct); | |
262 else | |
263 static assert(false, "No meta object for symbol " ~ T.stringof); | |
264 } | |
265 | |
266 /** | |
267 A run time attribute implementation that stores the attribute data in an | |
268 array of variants. | |
269 */ | |
270 class MetaVariantAttribute : MetaAttribute | |
271 { | |
272 Variant[] values; | |
273 | |
274 private this() | |
275 { | |
276 } | |
277 | |
278 static MetaVariantAttribute create(string category, AttributeOptions opts, A...)() | |
279 { | |
280 auto ret = new MetaVariantAttribute; | |
281 ret.construct!(category, opts)(); | |
282 foreach(i, _; A) | |
283 { | |
284 static if (__traits(compiles, { ret.values ~= Variant(A[i]); } )) | |
285 ret.values ~= Variant(A[i]); | |
286 } | |
287 return ret; | |
288 } | |
289 } | |
290 | |
291 /** | |
292 A run time attribute implementation that stores the attribute data in an | |
293 assiciative array of variants. | |
294 */ | |
295 class MetaVariantDictAttribute : MetaAttribute | |
296 { | |
297 Variant[string] values; | |
298 alias typeof(this) This; | |
299 | |
300 private this() | |
301 { | |
302 } | |
303 | |
304 static This create(string category, AttributeOptions opts, A...)() | |
305 { | |
306 auto ret = new This; | |
307 ret.construct!(category, opts)(); | |
308 foreach(i, _; A) | |
309 { | |
310 static if (i % 2 == 0 && __traits(compiles, { ret.values[A[i]] = Variant(A[i + 1]); } )) | |
311 ret.values[A[i]] = Variant(A[i + 1]); // PHOBOS BUG: phobos asserts on this | |
312 } | |
313 return ret; | |
314 } | |
315 } | |
316 | |
317 version (QtdUnittest) | |
318 { | |
319 unittest | |
320 { | |
321 static void foo() {} | |
322 | |
323 static class C | |
324 { | |
325 mixin InnerAttribute!("variantAttribute", MetaVariantAttribute, "22", foo, 33); | |
326 mixin InnerAttribute!("variantDictAttribute", MetaVariantDictAttribute, | |
327 //"a", "33", // PHOBOS BUG: variant is unusable with AAs | |
328 "b", foo | |
329 //"c", 44 | |
330 ); | |
331 } | |
332 | |
333 auto attrs = meta!(C).attributes; | |
334 assert(attrs.length == 2); | |
335 auto attr = cast(MetaVariantAttribute)attrs[0]; | |
336 | |
337 assert(attr.name == "variantAttribute"); | |
338 assert(attr.values[0] == "22"); | |
339 assert(attr.values[1] == 33); | |
340 | |
341 auto attr2 = cast(MetaVariantDictAttribute) attrs[1]; | |
342 assert(attr2.name == "variantDictAttribute"); | |
343 //assert(attr2.values["a"] == "33"); | |
344 //assert(attr2.values["c"] == 44); | |
345 } | |
346 } |