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