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
|
|
11 qtd.meta.Compiletime,
|
|
12
|
|
13 std.typetuple,
|
|
14 std.conv,
|
|
15 std.variant,
|
|
16 core.sync.rwmutex;
|
|
17
|
|
18 private __gshared ReadWriteMutex lock;
|
|
19 shared static this()
|
|
20 {
|
|
21 lock = new ReadWriteMutex;
|
|
22 }
|
|
23
|
|
24 /**
|
|
25 IDs of the built-in basic types.
|
|
26 */
|
|
27 enum BasicTypeId
|
|
28 {
|
|
29 ///
|
|
30 void_,
|
|
31 ///
|
|
32 bool_,
|
|
33 ///
|
|
34 byte_,
|
|
35 ///
|
|
36 ubyte_,
|
|
37 ///
|
|
38 short_,
|
|
39 ///
|
|
40 ushort_,
|
|
41 ///
|
|
42 int_,
|
|
43 ///
|
|
44 uint_,
|
|
45 ///
|
|
46 long_,
|
|
47 ///
|
|
48 ulong_,
|
|
49 ///
|
|
50 cent_,
|
|
51 ///
|
|
52 ucent_,
|
|
53 ///
|
|
54 float_,
|
|
55 ///
|
|
56 double_,
|
|
57 ///
|
|
58 real_,
|
|
59 ///
|
|
60 ifloat_,
|
|
61 ///
|
|
62 idouble_,
|
|
63 ///
|
|
64 ireal_,
|
|
65 ///
|
|
66 cfloat_,
|
|
67 ///
|
|
68 cdouble_,
|
|
69 ///
|
|
70 creal_,
|
|
71 ///
|
|
72 char_,
|
|
73 ///
|
|
74 wchar_,
|
|
75 ///
|
|
76 dchar_
|
|
77 }
|
|
78
|
|
79 /**
|
|
80 Thrown on meta-system errors.
|
|
81 */
|
|
82 class MetaException : Exception
|
|
83 {
|
|
84 this(string msg)
|
|
85 {
|
|
86 super(msg);
|
|
87 }
|
|
88 }
|
|
89
|
|
90 abstract class Meta
|
|
91 {
|
|
92 alias typeof(this) This;
|
|
93
|
|
94 string name;
|
|
95 MetaAttribute[] attributes;
|
|
96 Meta[] members;
|
|
97
|
|
98 template createImpl(M : This)
|
|
99 {
|
|
100 static M createImpl(alias symbol)()
|
|
101 {
|
|
102 auto m = new M;
|
|
103 m.construct!symbol;
|
|
104 return m;
|
|
105 }
|
|
106 }
|
|
107
|
|
108 private void createAttrs(alias symbol)()
|
|
109 {
|
|
110 alias GetAttributes!symbol attrs;
|
|
111 enum len = attrs.length; // COMPILER BUG
|
|
112 foreach (i, _; Repeat!(void, len))
|
|
113 {
|
|
114 alias TypeTuple!(attrs[i].tuple) attr;
|
|
115 // if the third element of the attribute data is a MetaAttribute subclass,
|
|
116 // use that to create the attribute instance.
|
|
117 static if (attr.length > 2 && (is(attr[2] : MetaAttribute)))
|
|
118 {
|
|
119 alias attr[2] MA;
|
|
120 alias TypeTuple!(attr[0..2], attr[3..$]) args;
|
|
121 attributes ~= MA /*COMPILER BUG: tuple element as tuple*/[0].create!args();
|
|
122 }
|
|
123 }
|
|
124 }
|
|
125
|
|
126 protected void construct(alias symbol)()
|
|
127 {
|
|
128 createAttrs!symbol;
|
|
129 }
|
|
130 }
|
|
131
|
|
132 /**
|
|
133 Base class for run time attributes.
|
|
134 */
|
|
135 abstract class MetaAttribute
|
|
136 {
|
|
137 alias typeof(this) This;
|
|
138
|
|
139 string name;
|
|
140 AttributeOptions options;
|
|
141
|
|
142 This create(string name, AttributeOptions opts, A...)()
|
|
143 {
|
|
144 auto ma = new This;
|
|
145 ma.construct!(name, opts, A)();
|
|
146 return ma;
|
|
147 }
|
|
148
|
|
149 void construct(string name, AttributeOptions opts)()
|
|
150 {
|
|
151 this.name = name;
|
|
152 options = opts;
|
|
153 }
|
|
154 }
|
|
155
|
|
156 abstract class MetaType : Meta
|
|
157 {
|
|
158 }
|
|
159
|
|
160 abstract class MetaAggregate : MetaType
|
|
161 {
|
|
162 }
|
|
163
|
|
164 class MetaClass : MetaAggregate
|
|
165 {
|
|
166 alias typeof(this) This;
|
|
167 alias createImpl!This create;
|
|
168 }
|
|
169
|
|
170 class MetaStruct : MetaAggregate
|
|
171 {
|
|
172 alias typeof(this) This;
|
|
173 alias createImpl!This create;
|
|
174 }
|
|
175
|
|
176 @property
|
|
177 auto meta(alias symbol, M : Meta)()
|
|
178 {
|
|
179 __gshared static M m;
|
|
180
|
|
181 {
|
|
182 lock.reader.lock;
|
|
183 scope(exit)
|
|
184 lock.reader.unlock;
|
|
185 if (m)
|
|
186 return m;
|
|
187 }
|
|
188
|
|
189 lock.writer.lock;
|
|
190 scope(exit)
|
|
191 lock.writer.unlock;
|
|
192
|
|
193 if (!m)
|
|
194 m = M.create!symbol;
|
|
195 return m;
|
|
196 }
|
|
197
|
|
198 // only classes and structs for now
|
|
199 @property
|
|
200 auto meta(T)()
|
|
201 {
|
|
202 static if (is(typeof(T.staticMetaObject)))
|
|
203 return T.staticMetaObject;
|
|
204 else static if (is(T == class))
|
|
205 return meta!(T, MetaClass);
|
|
206 else static if (is(T == struct))
|
|
207 return meta!(T, MetaStruct);
|
|
208 else
|
|
209 static assert(false, "No meta object for symbol " ~ T.stringof);
|
|
210 }
|
|
211
|
|
212 /**
|
|
213 A run time attribute implementation that stores the attribute data in an
|
|
214 array of variants.
|
|
215 */
|
|
216 class MetaVariantAttribute : MetaAttribute
|
|
217 {
|
|
218 Variant[] values;
|
|
219
|
|
220 private this()
|
|
221 {
|
|
222 }
|
|
223
|
|
224 static MetaVariantAttribute create(string category, AttributeOptions opts, A...)()
|
|
225 {
|
|
226 auto ret = new MetaVariantAttribute;
|
|
227 ret.construct!(category, opts)();
|
|
228 foreach(i, _; A)
|
|
229 {
|
|
230 static if (__traits(compiles, { ret.values ~= Variant(A[i]); } ))
|
|
231 ret.values ~= Variant(A[i]);
|
|
232 }
|
|
233 return ret;
|
|
234 }
|
|
235 }
|
|
236
|
|
237 /**
|
|
238 A run time attribute implementation that stores the attribute data in an
|
|
239 assiciative array of variants.
|
|
240 */
|
|
241 class MetaVariantDictAttribute : MetaAttribute
|
|
242 {
|
|
243 Variant[string] values;
|
|
244 alias typeof(this) This;
|
|
245
|
|
246 private this()
|
|
247 {
|
|
248 }
|
|
249
|
|
250 static This create(string category, AttributeOptions opts, A...)()
|
|
251 {
|
|
252 auto ret = new This;
|
|
253 ret.construct!(category, opts)();
|
|
254 foreach(i, _; A)
|
|
255 {
|
|
256 static if (i % 2 == 0 && __traits(compiles, { ret.values[A[i]] = Variant(A[i + 1]); } ))
|
|
257 ret.values[A[i]] = Variant(A[i + 1]); // PHOBOS BUG: phobos asserts on this
|
|
258 }
|
|
259 return ret;
|
|
260 }
|
|
261 }
|
|
262
|
|
263 version (QtdUnittest)
|
|
264 {
|
|
265 unittest
|
|
266 {
|
|
267 static void foo() {}
|
|
268
|
|
269 static class C
|
|
270 {
|
|
271 mixin InnerAttribute!("variantAttribute", MetaVariantAttribute, "22", foo, 33);
|
|
272 mixin InnerAttribute!("variantDictAttribute", MetaVariantDictAttribute,
|
|
273 //"a", "33", // PHOBOS BUG: variant is unusable with AAs
|
|
274 "b", foo
|
|
275 //"c", 44
|
|
276 );
|
|
277 }
|
|
278
|
|
279 auto attrs = meta!(C).attributes;
|
|
280 assert(attrs.length == 2);
|
|
281 auto attr = cast(MetaVariantAttribute)attrs[0];
|
|
282
|
|
283 assert(attr.name == "variantAttribute");
|
|
284 assert(attr.values[0] == "22");
|
|
285 assert(attr.values[1] == 33);
|
|
286
|
|
287 auto attr2 = cast(MetaVariantDictAttribute) attrs[1];
|
|
288 assert(attr2.name == "variantDictAttribute");
|
|
289 //assert(attr2.values["a"] == "33");
|
|
290 //assert(attr2.values["c"] == 44);
|
|
291 }
|
|
292 } |