1 
2 module dquery.element;
3 
4 import std.traits;
5 import std.typetuple;
6 
7 import dquery.attribute;
8 import dquery.attributes;
9 import dquery.helper;
10 
11 struct DQueryElement(QueryType, string Name, alias Overload = null)
12 {
13 
14 	/++
15 	 + Returns the type being queried.
16 	 ++/
17 	@property
18 	alias type = QueryType;
19 
20 	/++
21 	 + Returns the name of the element.
22 	 ++/
23 	@property
24 	alias name = Name;
25 
26 	/++
27 	 + Returns the value of the element.
28 	 ++/
29 	@property
30 	alias value = Alias!(
31 		GetMember!(QueryType, Name)
32 	);
33 
34 	/++
35 	 + Returns true if the name matches.
36 	 ++/
37 	@property
38 	alias isName(string Name) = Alias!(
39 		name == Name
40 	);
41 
42 	/++
43 	 + Returns true if the element has an attribute of the given type.
44 	 ++/
45 	@property
46 	alias hasAttribute(Type) = Alias!(
47 		attributes.anyOf!Type.length > 0
48 	);
49 
50 	/++
51 	 + Returns true if the element has all of the given attributes.
52 	 ++/
53 	@property
54 	alias hasAllOf(TList...) = Alias!(
55 		attributes.hasAllOf!TList
56 	);
57 
58 	/++
59 	 + Returns true if the element has any of the given attributes.
60 	 ++/
61 	@property
62 	alias hasAnyOf(TList...) = Alias!(
63 		attributes.hasAnyOf!TList
64 	);
65 
66 	/++
67 	 + Returns true if the element has none of the given attributes.
68 	 ++/
69 	@property
70 	alias hasNoneOf(TList...) = Alias!(
71 		attributes.hasNoneOf!TList
72 	);
73 
74 	/++
75 	 + Returns the element's access protection.
76 	 ++/
77 	@property
78 	alias protection = Alias!(
79 		GetProtection!(QueryType, Name)
80 	);
81 
82 	/++
83 	 + Returns true if the element refers to a field.
84 	 ++/
85 	@property
86 	alias isField = Alias!(
87 		is(typeof(GetMember!(QueryType, Name))) && !isFunction
88 	);
89 
90 	/++
91 	 + Returns true if a given type matches the element's type exactly.
92 	 ++/
93 	@property
94 	alias isTypeOf(Type) = Alias!(
95 		__traits(compiles, {
96 			static assert(is(typeof(GetMember!(QueryType, Name)) == Type));
97 		})
98 	);
99 
100 	/++
101 	 + Returns true if a given type can be assigned to a variable
102 	 + of the element's type.
103 	 ++/
104 	@property
105 	alias isTypeAssignableTo(Type) = Alias!(
106 		__traits(compiles, {
107 			typeof(GetMember!(QueryType, Name)) t1 = void;
108 			Type t2 = t1;
109 		})
110 	);
111 
112 	/++
113 	 + Returns true if a given type can be assigned from a variable
114 	 + of the element's type.
115 	 ++/
116 	@property
117 	alias isTypeAssignableFrom(Type) = Alias!(
118 		__traits(compiles, {
119 			Type t1 = void;
120 			typeof(GetMember!(QueryType, Name)) t2 = t1;
121 		})
122 	);
123 
124 	/++
125 	 + Returns true if the element refers to a function.
126 	 ++/
127 	@property
128 	alias isFunction = Alias!(
129 		is(typeof(GetMember!(QueryType, Name)) == function) &&
130 		!is(typeof(Overload) == typeof(null))
131 	);
132 
133 	/++
134 	 + Returns true if the element refers to a constructor.
135 	 ++/
136 	@property
137 	alias isConstructor = Alias!(
138 		isFunction && isName!"__ctor"
139 	);
140 
141 	/++
142 	 + Returns true if the element refers to a destructor.
143 	 ++/
144 	@property
145 	alias isDestructor = Alias!(
146 		isFunction && isName!"__dtor"
147 	);
148 
149 	/++
150 	 + Return true if the element's arity matches the given number of parameters.
151 	 ++/
152 	@property
153 	alias isArity(int Count) = Alias!(
154 		isFunction && __traits(compiles, {
155 			static assert(Overload.arity == Count);
156 		})
157 	);
158 
159 	/++
160 	 + Returns true if a given type matches the element's return type exactly.
161 	 ++/
162 	@property
163 	alias isReturnTypeOf(Type) = Alias!(
164 		isFunction && __traits(compiles, {
165 			static assert(is(Overload.returnType == Type));
166 		})
167 	);
168 
169 	/++
170 	 + Returns true if a given type can be assigned to a variable of the
171 	 + element's return type.
172 	 ++/
173 	@property
174 	alias isReturnAssignableTo(Type) = Alias!(
175 		isFunction && __traits(compiles, {
176 			Overload.returnType t1 = void;
177 			Type t2 = t1;
178 		})
179 	);
180 
181 	/++
182 	 + Returns true if a given type can be assigned from a variable
183 	 + of the element's return type.
184 	 ++/
185 	@property
186 	alias isReturnAssignableFrom(Type) = Alias!(
187 		isFunction && __traits(compiles, {
188 			Type t1 = void;
189 			Overload.returnType t2 = t1;
190 		})
191 	);
192 
193 	/++
194 	 + Returns true if the element's parameter types match the given type list.
195 	 ++/
196 	@property
197 	alias isParameterTypesOf(TList...) = Alias!(
198 		isFunction && __traits(compiles, {
199 			static assert(Compare!(Overload.parameters).With!(TList));
200 		})
201 	);
202 
203 	/++
204 	 + Returns true if the element refers to an aggregate type.
205 	 ++/
206 	@property
207 	alias isAggregate = Alias!(
208 		__traits(compiles, {
209 			static assert(isAggregateType!(GetMember!(QueryType, Name)));
210 		})
211 	);
212 
213 	/++
214 	 + Returns true if a given type matches the element's aggregate type exactly.
215 	 ++/
216 	@property
217 	alias isAggregateTypeOf(Type) = Alias!(
218 		__traits(compiles, {
219 			static assert(is(GetMember!(QueryType, Name) == Type));
220 		})
221 	);
222 
223 	/++
224 	 + Returns true if a given type can be assigned to a variable of the
225 	 + element's aggregate type.
226 	 ++/
227 	@property
228 	alias isAggregateAssignableTo(Type) = Alias!(
229 		__traits(compiles, {
230 			GetMember!(QueryType, Name) t1 = void;
231 			Type t2 = t1;
232 		})
233 	);
234 
235 	/++
236 	 + Returns true if a given type can be assigned from a variable of the
237 	 + element's aggregate type.
238 	 ++/
239 	@property
240 	alias isAggregateAssignableFrom(Type) = Alias!(
241 		__traits(compiles, {
242 			Type t1 = void;
243 			GetMember!(QueryType, Name) t2 = t1;
244 		})
245 	);
246 
247 	/++
248 	 + Returns true if the element refers to a class.
249 	 ++/
250 	@property
251 	alias isClass = Alias!(
252 		__traits(compiles, {
253 			alias Element = Alias!(GetMember!(QueryType, Name));
254 			static assert(is(Element == class));
255 		})
256 	);
257 
258 	/++
259 	 + Returns true if the element refers to a struct.
260 	 ++/
261 	@property
262 	alias isStruct = Alias!(
263 		__traits(compiles, {
264 			alias Element = Alias!(GetMember!(QueryType, Name));
265 			static assert(is(Element == struct));
266 		})
267 	);
268 
269 	/++
270 	 + Returns true is the element is a template of the given type.
271 	 ++/
272 	@property
273 	alias isTemplateOf(alias Template) = Alias!(
274 		__traits(compiles, {
275 			alias Element = Alias!(GetMember!(QueryType, Name));
276 			static assert(is(TemplateOf!Element == Template));
277 		})
278 	);
279 
280 	/++
281 	 + Returns true if the element's template arguments match.
282 	 ++/
283 	@property
284 	alias isTemplateArgsOf(TemplateArgs...) = Alias!(
285 		__traits(compiles, {
286 			alias Element = Alias!(GetMember!(QueryType, Name));
287 			static assert(Compare!(TemplateArgsOf!Element).With!TemplateArgs);
288 		})
289 	);
290 
291 	/++
292 	 + Returns an uninitialized value of the element's type.
293 	 ++/
294 	@property
295 	static auto opCall()
296 	{
297 		DQueryElement!(QueryType, Name, Overload) element = void;
298 		return element;
299 	}
300 
301 	/++
302 	 + Returns a query for the type the element refers to.
303 	 ++/
304 	@property
305 	static auto query()()
306 	if(isAggregate)
307 	{
308 		import dquery.d;
309 		return query!(GetMember!(QueryType, Name));
310 	}
311 
312 	/++
313 	 + Returns a query for the parent type of the element.
314 	 ++/
315 	@property
316 	static auto parent()()
317 	{
318 		import dquery.d;
319 		return query!QueryType;
320 	}
321 
322 	/++
323 	 + Returns the element's attributes.
324 	 ++/
325 	@property
326 	static auto attributes()()
327 	{
328 		alias MapToAttribute(alias Attribute) = Alias!(
329 			DQueryAttribute!Attribute()
330 		);
331 
332 		return DQueryAttributes!(
333 			QueryType,
334 			staticMap!(
335 				MapToAttribute,
336 				GetAttributes!(QueryType, Name)
337 			)
338 		)();
339 	}
340  
341 	/++
342 	 + Returns the element's allowed attributes.
343 	 ++/
344 	@property
345 	static auto attributes(Allow...)()
346 	if(Allow.length > 0)
347 	{
348 		return attributes.allow!Allow;
349 	}
350 
351 	string toString()
352 	{
353 		return Name;
354 	}
355 
356 }