1 /// Expansive traits module meant to replace `std.traits`.
2 module tern.traits;
3 
4 // TODO: Legacy imports, get rid of this eventually
5 public import std.traits : functionAttributes, hasFunctionAttributes, functionLinkage, FunctionTypeOf,
6     ParameterDefaults, ParameterIdentifierTuple, ParameterStorageClassTuple, SetFunctionAttributes, variadicFunctionStyle,
7     BaseClassesTuple, BaseTypeTuple, EnumMembers, FieldNameTuple, hasStaticMember, hasNested, hasIndirections, isNested,
8     RepresentationTypeTuple, TemplateArgsOf, TemplateOf, TransitiveBaseTypeTuple, InoutOf, ConstOf, SharedOf, SharedInoutOf,
9     SharedConstInoutOf, SharedConstOf, ImmutableOf, QualifierOf, allSameType, ForeachType, KeyType, Largest, mostNegative,
10     PointerTarget, Signed, Unconst, Unshared, Unqual, Unsigned, ValueType, Promoted, lvalueOf, rvalueOf, select, Select,
11     hasUDA, getUDAs, getSymbolsByUDA;
12 static import std.traits;
13 static import tern.traits;
14 import std.meta;
15 import std.string;
16 import std.functional : toDelegate;
17 import std.conv;
18 
19 /// Gets the partial identifier of `A` excluding all parents.
20 public enum identifier(alias A) =
21 {
22     static if (!__traits(compiles, { auto _ = __traits(identifier, A); }) || isType!A || isExpression!A)
23         return A.stringof;
24     else
25         return __traits(identifier, A);
26 }();
27 /// Gets the full identifier of `A` including all parents.
28 public enum fullIdentifier(alias A) =
29 {
30     // TODO: Fix, use identifier unless type or expression
31     static if (hasParents!A)
32         return identifier!(Parent!A)~"."~identifier!A;
33     else
34         return identifier!A;
35 }();
36 /// Gets the parent of `A`.
37 public alias Parent(alias A) = __traits(parent, A);
38 /// Gets the children of `A`.
39 public alias Children(alias A) = __traits(allMembers, A);
40 /// Gets the `alias this` of `T`.
41 public alias AliasThis(T) = __traits(getAliasThis, T);
42 /// Gets all attributes that are applied to `A`.
43 public alias Attributes(alias A) = __traits(getAttributes, A);
44 /// True if `A` has a child `M`.
45 public enum hasChild(alias A, string M) = std.traits.hasMember!(A, M);
46 /// True if `A` has a field `M`.
47 public enum hasField(alias A, string M) = std.traits.hasMember!(A, M) && isField!(getChild!(M, A));
48 /// True if `A` has a function `M`.
49 public enum hasFunction(alias A, string M) = std.traits.hasMember!(A, M) && isFunction!(getChild!(M, A));
50 /// True if `A` has a type `M`.
51 public enum hasType(alias A, string M) = std.traits.hasMember!(A, M) && isType!(getChild!(M, A));
52 /// True if `A` has a type `M`.
53 public enum hasTemplate(alias A, string M) = std.traits.hasMember!(A, M) && isTemplate!(getChild!(M, A));
54 /// Gets an alias to child `M` in `A`.
55 public alias getChild(alias A, string M) = __traits(getMember, A, M);
56 /// True if `A` has a parent `P`.
57 public enum hasParent(alias A, alias P) = staticIndexOf!(P, Implements!A) != -1;
58 /// True if type `B` is an instance of type `A`.
59 public enum isInstanceOf(A, B) = hasParent!(A, B) || (isTemplate!A && std.traits.isInstanceOf!(A, B));
60 /// True if `A` contains any kind of aliasing.
61 public enum hasAliasing(alias A) = std.traits.hasAliasing!A;
62 /// True if `A` contains any kind of unshared (thread-unsafe) aliasing.
63 public enum hasUnsharedAliasing(alias A) = std.traits.hasUnsharedAliasing!A;
64 /// True if `T` has a user defined assignment operation.
65 public enum hasElaborateAssign(T) = std.traits.hasElaborateAssign!T;
66 /// True if `T` has a user defined copy constructor.
67 public enum hasElaborateCopyConstructor(T) = std.traits.hasElaborateCopyConstructor!T;
68 /// True if `T` has a user defined destructor.
69 public enum hasElaborateDestructor(T) = std.traits.hasElaborateDestructor!T;
70 /// True if `T` has a user defined move operation.
71 public enum hasElaborateMove(T) = std.traits.hasElaborateMove!T;
72 /// True if `F` is safe.
73 public enum isSafe(alias F) = std.traits.isSafe!F;
74 /// True if `F` is unsafe.
75 public enum isUnsafe(alias F) = std.traits.isUnsafe!F;
76 /// True if `A` is final.
77 public enum isFinal(alias A) = std.traits.isFinal!A;
78 /// True if `A` is final.
79 public enum isAbstract(alias A) = std.traits.isAbstractClass!A || std.traits.isAbstractFunction!A;
80 /// True if `F` has no return type (`void`.)
81 public enum isNoReturn(alias F) = is(ReturnType!F == void);
82 /// True if type `A` is assignable to type `B`.
83 public enum isAssignable(A, B) = std.traits.isAssignable!(A, B);
84 /// True if type `A` is covariant with type `B`.
85 public enum isCovariantWith(A, B) = std.traits.isCovariantWith!(A, B);
86 /// True if type `A` is implicitly convertible to type `B`.
87 public enum isImplicitlyConvertible(A, B) = std.traits.isImplicitlyConvertible!(A, B);
88 /// True if type `A` is qualifier convertible to type `B`.
89 public enum isQualifierConvertible(A, B) = std.traits.isQualifierConvertible!(A, B);
90 /// True if type `A` is reinterpretable to type `B`.
91 public enum isReinterpretable(A, B) =
92 {
93     static if ((is(A == void*) && is(B == class)) || (is(A == class) && is(B == void*)))
94         return true;
95 
96     static if (is(A == class) != is(B == class))
97         return false;
98 
99     static if (A.sizeof > B.sizeof)
100         return false;
101 
102     static if (hasChildren!A && hasChildren!B)
103     {
104         static foreach (i, field; Fields!A)
105         {{
106             alias FA = getChild!(A, field);
107             alias FB = getChild!(B, Fields!B[i]);
108             static if (!isReinterpretable!(typeof(FA), typeof(FB)) || (isManifest!FA != isManifest!FB))
109                 return false;
110         }}
111     }
112     else static if (hasChildren!A || hasChildren!B)
113     {
114         static if (hasChildren!A)
115         {
116             static if (isManifest!(getChild!(A, Fields!A[0])))
117                 return false;
118 
119             alias FA = typeof(getChild!(A, Fields!A[0]));
120         }
121         else
122             alias FA = A;
123 
124         static if (hasChildren!B)
125         {
126             static if (isManifest!(getChild!(B, Fields!B[0])))
127                 return false;
128                 
129             alias FB = typeof(getChild!(B, Fields!B[0]));
130         }
131         else
132             alias FB = B;
133 
134         return isReinterpretable!(FA, FB);
135     }
136 
137     return true;
138 }();
139 /// True if `T` is an array.
140 public enum isArray(T) = std.traits.isArray!T;
141 /// True if `T` is a dynamic array.
142 public enum isDynamicArray(T) = std.traits.isDynamicArray!T;
143 /// True if `T` is a static array.
144 public enum isStaticArray(T) = std.traits.isStaticArray!T;
145 /// True if `T` is an associative array.
146 public enum isAssociativeArray(T) = std.traits.isAssociativeArray!T;
147 /// True if `T` is an auto-decodeable string.
148 public enum isAutodecodeableString(T) = std.traits.isAutodecodableString!T;
149 /// True if `T` is a built-in type, as in any language defined type.
150 public enum isBuiltinType(T) = std.traits.isBuiltinType!T;
151 /// True if `T` is an integral.
152 public enum isIntegral(T) = std.traits.isIntegral!T;
153 /// True if `T` is an intrinsically numeric.
154 public enum isScalar(T) = std.traits.isScalarType!T;
155 /// True if `T` is a floating point.
156 public enum isFloatingPoint(T) = std.traits.isFloatingPoint!T;
157 /// True if `T` is a `string` or `wstring`.
158 public enum isNarrowString(T) = std.traits.isNarrowString!T;
159 /// True if `T` is numerically represented, as in integral or float.
160 public enum isNumeric(T) = std.traits.isNumeric!T;
161 /// True if `T` is a pointer.
162 public enum isPointer(T) = std.traits.isPointer!T;
163 /// True if `T` is any string.
164 public enum isString(T) = std.traits.isSomeString!T;
165 /// True if `T` is any char.
166 public enum isChar(T) = std.traits.isSomeChar!T;
167 /// True if `T` is signed.
168 public enum isSigned(T) = std.traits.isSigned!T;
169 /// True if `T` is unsigned.
170 public enum isUnsigned(T) = std.traits.isUnsigned!T;
171 /// True if `T` is unable to be copied.
172 public enum isCopyable(T) = std.traits.isCopyable!T;
173 /// True if `T` is able to be equality compared.
174 public enum isEqualityComparable(T) = std.traits.isTestable!T || std.traits.isEqualityComparable!T;
175 /// True if `T` is able to be ordering compared, as in `<`, `>`, etc.
176 public enum isOrderingComparable(T) = std.traits.isOrderingComparable!T;
177 /// True if `T` is an indirection.
178 public enum isReferenceType(T) = is(T == class) || is(T == interface) || isPointer!T || isDynamicArray!T || isAssociativeArray!T;
179 /// True if `T` is not an indirection.
180 public enum isValueType(T) = is(T == struct) || is(T == enum) || is(T == union) || isBuiltinType!T || hasModifiers!T;
181 /// True if `A` is a template.
182 public enum isTemplate(alias A) = __traits(isTemplate, A);
183 /// True if `A` is a module.
184 public enum isModule(alias A) = __traits(isModule, A);
185 /// True if `A` is a package.
186 public enum isPackage(alias A) = __traits(isPackage, A);
187 /// True if `A` is a field.
188 public enum isField(alias A) = !isType!A && !isFunction!A && !isTemplate!A && !isModule!A && !isPackage!A;
189 /// True if `A` is a local.
190 public enum isLocal(alias A) = !isManifest!A && !__traits(compiles, { enum _ = A; }) && __traits(compiles, { auto _ = A; });
191 /// True if `A` is an expression, like a string, numeric, or other manifest data.
192 public enum isExpression(alias A) = __traits(compiles, { enum _ = A; });
193 /// True if `A` is a function symbol.
194 public enum isFunction(alias A) = std.traits.isFunction!A;
195 /// True if `A` is a function pointer symbol.
196 public enum isFunctionPointer(alias A) = std.traits.isFunctionPointer!A;
197 /// True if `A` is a delegate symbol.
198 public enum isDelegate(alias A) = std.traits.isDelegate!A;
199 /// True if `A` is a type symbol.
200 public enum isType(alias A) = std.traits.isType!A;
201 /// True if `A` is a class type symbol.
202 public enum isClass(alias A) = is(A == class);
203 /// True if `A` is a interface type symbol.
204 public enum isInterface(alias A) = is(A == interface);
205 /// True if `A` is a struct type symbol.
206 public enum isStruct(alias A) = is(A == struct);
207 /// True if `A` is a enum type symbol.
208 public enum isEnum(alias A) = is(A == enum);
209 /// True if `A` is a union type symbol.
210 public enum isUnion(alias A) = is(A == union);
211 /// True if `A` is an aggregate type symbol.
212 public enum isAggregateType(alias A) = std.traits.isAggregateType!A;
213 /// True if `A` is an alias to a top-level symbol, like a package or intrinsic, which has no parent.
214 public enum isTopLevel(alias A) = !__traits(compiles, { alias _ = Parent!A; }) || !__traits(compiles, { enum _ = is(Parent!A == void); }) || is(Parent!A == void);
215 /// True if `A` has any parents.
216 public enum hasParents(alias A) = !isManifest!A && !isTopLevel!A;
217 /// True if `T` is an enum, array, or pointer.
218 public enum hasModifiers(T) = isArray!T || isPointer!T || isEnum!T;
219 /// True if `A` has any children.
220 public enum hasChildren(alias A) = isModule!A || isPackage!A || (!isType!A || (!isBuiltinType!A && !hasModifiers!A));
221 /// True if `T` has any instance constructor ("__ctor").
222 public enum hasConstructor(alias A) = std.traits.hasMember!(T, "__ctor");
223 /// True if `F` is a constructor;
224 public enum isConstructor(alias F) = isFunction!F && (__traits(identifier, F).startsWith("__ctor") || __traits(identifier, F).startsWith("_staticCtor"));
225 /// True if `F` is a destructor.
226 public enum isDestructor(alias F) = isFunction!F && (__traits(identifier, F).startsWith("__dtor") || __traits(identifier, F).startsWith("__xdtor") || __traits(identifier, F).startsWith("_staticDtor"));
227 /// True if `A` is a static field.
228 public enum isStatic(alias A) = !isManifest!A && ((isField!A && __traits(compiles, { auto _ = __traits(getMember, Parent!A, __traits(identifier, A)); })) || (isLocal!A && __traits(compiles, { static auto _() { return A; } })));
229 /// True if `A` is an enum field or local.
230 public enum isManifest(alias A) = __traits(compiles, { enum _ = __traits(getMember, Parent!A, __traits(identifier, A)); });
231 /// True if `A` is an implementation defined alias (ie: __ctor, std, rt, etc.)
232 public enum isDImplDefined(alias A) =
233 {
234     static if ((isModule!A || (isType!A && !isBuiltinType!A)) && (getPackage!A.stringof == "package std" || getPackage!A.stringof == "package rt" || getPackage!A.stringof == "package core"))
235         return true;
236     else static if (isPackage!A && (A.stringof == "package std" || A.stringof == "package rt" || A.stringof == "package core"))
237         return true;
238     else static if (isType!A && isBuiltinType!A)
239         return true;
240     else static if (isFunction!A && 
241     // Not exactly accurate but good enough
242         (__traits(identifier, A).startsWith("_d_") || __traits(identifier, A).startsWith("rt_") || 
243         __traits(identifier, A).startsWith("__") || __traits(identifier, A).startsWith("op")))
244         return true;
245     else static if (isConstructor!A || isDestructor!A || (isFunction!F && (__traits(identifier, F).startsWith("toHash") || __traits(identifier, F).startsWith("toString"))))
246         return true;
247     else
248         return false;
249 }();
250 /// True if `A` is not D implementation defined.
251 public enum isOrganic(alias A) = !isDImplDefined!A;
252 /// True if `T` is able to be indexed.
253 public enum isIndexable(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; auto _ = t[0]; });
254 /// True if `T` is able to be index assigned.
255 public enum isIndexAssignable(T) = __traits(compiles, { T t; auto _ = (t[0] = t[1]); }) && isMutable!(ElementType!T);
256 /// True if `T` is able to be sliced.
257 public enum isSliceable(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; auto _ = t[0..1]; });
258 /// True if `T` is able to be slice assigned.
259 public enum isSliceAssignable(T) = __traits(compiles, { T t; auto _ = (t[0..1] = t[1..2]); } && isMutable!(ElementType!T));
260 /// True if `T` is able to be iterated upon forwards.
261 public enum isForward(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; foreach (u; t) { } });
262 /// True if `T` is able to be iterated upon forwards.
263 public enum isBackward(T) = isDynamicArray!T || isStaticArray!T || __traits(compiles, { T t; foreach_reverse (u; t) { } });
264 /// True if `B` is an element type of `A` (assignable as element.)
265 public enum isElement(A, B) = isAssignable!(B, ElementType!A);
266 /// True if `B` is able to be used as a range the same as `A`.
267 public enum isSimRange(A, B) = isAssignable!(ElementType!B, ElementType!A);
268 /// True if `F` is a lambda.
269 public enum isLambda(alias F) = __traits(identifier, F).startsWith("__lambda");
270 /// True if `F` is a dynamic lambda (templated, ie: `x => x + 1`)
271 public enum isTemplatedCallable(alias F) = std.traits.isCallable!(DefaultInstance!F);
272 /// True if `F` is a dynamic lambda (templated, ie: `x => x + 1`)
273 public enum isDynamicLambda(alias F) = isLambda!F && is(typeof(F) == void);
274 /// True if `F` is a function, lambda, or otherwise may be called using `(...)`
275 public enum isCallable(alias F) = std.traits.isCallable!F || isLambda!F || isTemplatedCallable!F;
276 /// True if `F` is a property of any kind.
277 public enum isProperty(alias F) = hasUDA!(F, property);
278 /// True if `F` is a pure callable.
279 public enum isPure(alias F) = isCallable!F && hasFunctionAttributes!(F, "pure");
280 /// True if type `A` implements type `B`.
281 public enum isImplement(A, B) = staticIndexOf!(B, Implements!A) != -1;
282 /// True if `A` is not mutable (const, immutable, enum, etc.).
283 public enum isMutable(alias A) =
284 {
285     static if (isType!A)
286         return std.traits.isMutable!A;
287     else static if (isField!A)
288         return std.traits.isMutable!(typeof(A)) || !isManifest!A;
289     else
290         return false;
291 }();
292 
293 /// Gets all children of child `M` in `A`.
294 public alias Children(alias A, string M) = Children!(getChild!(A, M));
295 /// Gets all attributes of child `M` in `A`.
296 public alias Attributes(alias A, string M) = Attributes!(getChild!(A, M));
297 /// True if child `M1` in `A` has a child `M2`.
298 public alias hasChild(alias A, string M1, string M2) = hasChild!(getChild!(A, M1), M2);
299 /// True if child `M1` in `A` has a field `M2`.
300 public alias hasField(alias A, string M1, string M2) = hasField!(getChild!(A, M1), M2);
301 /// True if child `M1` in `A` has a function `M2`.
302 public alias hasFunction(alias A, string M1, string M2) = hasFunction!(getChild!(A, M1), M2);
303 /// True if child `M1` in `A` has a type `M2`.
304 public alias hasType(alias A, string M1, string M2) = hasType!(getChild!(A, M1), M2);
305 /// True if child `M1` in `A` has a template `M2`.
306 public alias hasTemplate(alias A, string M1, string M2) = hasTemplate!(getChild!(A, M1), M2);
307 /// Gets the child `M2` in `M1` in `A`.
308 public alias getChild(alias A, string M1, string M2) = getChild!(getChild!(A, M1), M2);
309 /// True if child `M1` in `A` has a parent `P`.
310 public alias hasParent(alias A, string M, alias P) = hasParent!(getChild!(A, M), P);
311 /// True if the type of `M` in `A` has aliasing.
312 public alias hasAliasing(alias A, string M) = hasAliasing!(typeof(getChild!(A, M)));
313 /// True if the type of `M` in `A` has unshared aliasing.
314 public alias hasUnsharedAliasing(alias A, string M) = hasUnsharedAliasing!(typeof(getChild!(A, M)));
315 /// True if the type of `M` in `A` has an elaborate assign.
316 public alias hasElaborateAssign(alias A, string M) = hasElaborateAssign!(typeof(getChild!(A, M)));
317 /// True if the type of `M` in `A` has an elaborate copy constructor.
318 public alias hasElaborateCopyConstructor(alias A, string M) = hasElaborateCopyConstructor!(typeof(getChild!(A, M)));
319 /// True if the type of `M` in `A` has an elaborate destructor.
320 public alias hasElaborateDestructor(alias A, string M) = hasElaborateDestructor!(typeof(getChild!(A, M)));
321 /// True if the type of `M` in `A` has an elaborate move.
322 public alias hasElaborateMove(alias A, string M) = hasElaborateMove!(typeof(getChild!(A, M)));
323 /// True if the type of `M` in `A` is safe.
324 public alias isSafe(alias A, string M) = isSafe!(typeof(getChild!(A, M)));
325 /// True if the type of `M` in `A` is unsafe.
326 public alias isUnsafe(alias A, string M) = isUnsafe!(typeof(getChild!(A, M)));
327 /// True if the type of `M` in `A` is final.
328 public alias isFinal(alias A, string M) = isFinal!(typeof(getChild!(A, M)));
329 /// True if the type of `M` in `A` is abstract.
330 public alias isAbstract(alias A, string M) = isAbstract!(typeof(getChild!(A, M)));
331 /// True if the type of `M` in `A` is a void returning callable.
332 public alias isNoReturn(alias A, string M) = isNoReturn!(typeof(getChild!(A, M)));
333 /// True if the type of `M` in `A` is assignable to `B`.
334 public alias isAssignable(alias A, string M, alias B) = isAssignable!(typeof(getChild!(A, M), B));
335 /// True if the type of `M` in `A` is covariant with `B`.
336 public alias isCovariantWith(alias A, string M, alias B) = isCovariantWith!(typeof(getChild!(A, M), B));
337 /// True if the type of `M` in `A` is implicitly convertible to `B`.
338 public alias isImplicitlyConvertible(alias A, string M, alias B) = isImplicitlyConvertible!(typeof(getChild!(A, M), B));
339 /// True if the type of `M` in `A` is qualifier convertible to `B`.
340 public alias isQualifierConvertible(alias A, string M, alias B) = isQualifierConvertible!(typeof(getChild!(A, M), B));
341 /// True if the type of `M` in `A` is reinterpretable to `B`.
342 public alias isReinterpretable(alias A, string M, alias B) = isReinterpretable!(typeof(getChild!(A, M), B));
343 /// True if the type of `M` in `A` is an array.
344 public alias isArray(alias A, string M) = isArray!(typeof(getChild!(A, M)));
345 /// True if the type of `M` in `A` is a dynamic array.
346 public alias isDynamicArray(alias A, string M) = isDynamicArray!(typeof(getChild!(A, M)));
347 /// True if the type of `M` in `A` is a static array.
348 public alias isStaticArray(alias A, string M) = isStaticArray!(typeof(getChild!(A, M)));
349 /// True if the type of `M` in `A` is an associative array.
350 public alias isAssociativeArray(alias A, string M) = isAssociativeArray!(typeof(getChild!(A, M)));
351 /// True if the type of `M` in `A` is an auto-decodeable string.
352 public alias isAutodecodableString(alias A, string M) = isAutodecodableString!(typeof(getChild!(A, M)));
353 /// True if the type of `M` in `A` is a built-in type.
354 public alias isBuiltinType(alias A, string M) = isBuiltinType!(typeof(getChild!(A, M)));
355 /// True if the type of `M` in `A` is an integral.
356 public alias isIntegral(alias A, string M) = isIntegral!(typeof(getChild!(A, M)));
357 /// True if the type of `M` in `A` is a scalar.
358 public alias isScalar(alias A, string M) = isScalar!(typeof(getChild!(A, M)));
359 /// True if the type of `M` in `A` is a floating-point.
360 public alias isFloatingPoint(alias A, string M) = isFloatingPoint!(typeof(getChild!(A, M)));
361 /// True if the type of `M` in `A` is a narrow string.
362 public alias isNarrowString(alias A, string M) = isNarrowString!(typeof(getChild!(A, M)));
363 /// True if the type of `M` in `A` is numeric.
364 public alias isNumeric(alias A, string M) = isNumeric!(typeof(getChild!(A, M)));
365 /// True if the type of `M` in `A` is a pointer.
366 public alias isPointer(alias A, string M) = isPointer!(typeof(getChild!(A, M)));
367 /// True if the type of `M` in `A` is any string.
368 public alias isString(alias A, string M) = isString!(typeof(getChild!(A, M)));
369 /// True if the type of `M` in `A` is any char.
370 public alias isChar(alias A, string M) = isChar!(typeof(getChild!(A, M)));
371 /// True if the type of `M` in `A` is signed.
372 public alias isSigned(alias A, string M) = isSigned!(typeof(getChild!(A, M)));
373 /// True if the type of `M` in `A` is unsigned.
374 public alias isUnsigned(alias A, string M) = isUnsigned!(typeof(getChild!(A, M)));
375 /// True if the type of `M` in `A` is copyable.
376 public alias isCopyable(alias A, string M) = isCopyable!(typeof(getChild!(A, M)));
377 /// True if the type of `M` in `A` is equality comparable.
378 public alias isEqualityComparable(alias A, string M) = isEqualityComparable!(typeof(getChild!(A, M)));
379 /// True if the type of `M` in `A` is ordering comparable.
380 public alias isOrderingComparable(alias A, string M) = isOrderingComparable!(typeof(getChild!(A, M)));
381 /// True if the type of `M` in `A` is a reference type.
382 public alias isReferenceType(alias A, string M) = isReferenceType!(typeof(getChild!(A, M)));
383 /// True if the type of `M` in `A` is a value type.
384 public alias isValueType(alias A, string M) = isValueType!(typeof(getChild!(A, M)));
385 /// True if `M` in `A` is a template.
386 public alias isTemplate(alias A, string M) = isTemplate!(getChild!(A, M));
387 /// True if `M` in `A` is a module.
388 public alias isModule(alias A, string M) = isModule!(getChild!(A, M));
389 /// True if `M` in `A` is a field.
390 public alias isField(alias A, string M) = isField!(getChild!(A, M));
391 /// True if `M` in `A` is a local.
392 public alias isLocal(alias A, string M) = isLocal!(getChild!(A, M));
393 /// True if `M` in `A` is a function.
394 public alias isFunction(alias A, string M) = isFunction!(getChild!(A, M));
395 /// True if the type of `M` in `A` is a function pointer.
396 public alias isFunctionPointer(alias A, string M) = isFunctionPointer!(typeof(getChild!(A, M)));
397 /// True if the type of `M` in `A` is a delegate.
398 public alias isDelegate(alias A, string M) = isDelegate!(typeof(getChild!(A, M)));
399 /// True if `M` in `A` is a type. 
400 public alias isType(alias A, string M) = isType!(getChild!(A, M));
401 /// True if the type of `M` in `A` is a class. 
402 public alias isClass(alias A, string M) = isClass!(typeof(getChild!(A, M)));
403 /// True if the type of `M` in `A` is an interface.
404 public alias isInterface(alias A, string M) = isInterface!(typeof(getChild!(A, M)));
405 /// True if the type of `M` in `A` is a struct.
406 public alias isStruct(alias A, string M) = isStruct!(typeof(getChild!(A, M)));
407 /// True if the type of `M` in `A` is an enum.
408 public alias isEnum(alias A, string M) = isEnum!(typeof(getChild!(A, M)));
409 /// True if the type of `M` in `A` is a union.
410 public alias isUnion(alias A, string M) = isUnion!(typeof(getChild!(A, M)));
411 /// True if the type of `M` in `A` is an aggregate type.
412 public alias isAggregateType(alias A, string M) = isAggregateType!(typeof(getChild!(A, M)));
413 /// True if the type of `M` in `A` is an instance of `B`.
414 public alias isInstanceOf(alias A, string M, alias B) = isInstanceOf!(typeof(getChild!(A, M)), B);
415 /// True if the type of `M` in `A` has modifiers.
416 public alias hasModifiers(alias A, string M) = hasModifiers!(typeof(getChild!(A, M)));
417 /// True if `M` in `A` has children.
418 public alias hasChildren(alias A, string M) = hasChildren!(getChild!(A, M));
419 /// True if the type of `M` in `A` has a constructor.
420 public alias hasConstructor(alias A, string M) = hasChildren!(typeof(getChild!(A, M)));
421 /// True if `M` in `A` is static.
422 public alias isStatic(alias A, string M) = isStatic!(getChild!(A, M));
423 /// True if `M` in `A` is manifest data.
424 public alias isManifest(alias A, string M) = isManifest!(getChild!(A, M));
425 /// True if `M` in `A` is implementation defined.
426 public alias isDImplDefined(alias A, string M) = isDImplDefined!(getChild!(A, M));
427 /// True if `M` in `A` is not implementation defined.
428 public alias isOrganic(alias A, string M) = isOrganic!(getChild!(A, M));
429 /// True if the type of `M` in `A` is indexable.
430 public alias isIndexable(alias A, string M) = isIndexable!(typeof(getChild!(A, M)));
431 /// True if the type of `M` in `A` is index assignable.
432 public alias isIndexAssignable(alias A, string M) = isIndexAssignable!(typeof(getChild!(A, M)));
433 /// True if the type of `M` in `A` is sliceable.
434 public alias isSliceable(alias A, string M) = isSliceable!(typeof(getChild!(A, M)));
435 /// True if the type of `M` in `A` is slice assignable.
436 public alias isSliceAssignable(alias A, string M) = isSliceAssignable!(typeof(getChild!(A, M)));
437 /// True if the type of `M` in `A` is forward iterable.
438 public alias isForward(alias A, string M) = isForward!(typeof(getChild!(A, M)));
439 /// True if the type of `M` in `A` is backward iterable.
440 public alias isBackward(alias A, string M) = isBackward!(typeof(getChild!(A, M)));
441 /// True if the type of `M` in `A` is an element of `B`.
442 public alias isElement(alias A, string M, alias B) = isElement!(typeof(getChild!(A, M)), B);
443 /// True if the type of `M` in `A` shares element type with `B`.
444 public alias isSimRange(alias A, string M, alias B) = isSimRange!(typeof(getChild!(A, M)), B);
445 /// True if the type of `M` in `A` is a lambda.
446 public alias isLambda(alias A, string M) = isLambda!(typeof(getChild!(A, M)));
447 /// True if the type of `M` in `A` is a templated callable.
448 public alias isTemplatedCallable(alias A, string M) = isTemplatedCallable!(typeof(getChild!(A, M)));
449 /// True if the type of `M` in `A` is a dynamic lambda.
450 public alias isDynamicLambda(alias A, string M) = isDynamicLambda!(typeof(getChild!(A, M)));
451 /// True if the type of `M` in `A` is callable.
452 public alias isCallable(alias A, string M) = isCallable!(typeof(getChild!(A, M)));
453 /// True if `M` in `A` is a property.
454 public alias isProperty(alias A, string M) = isProperty!(getChild!(A, M));
455 /// True if the type of `M` in `A` is pure.
456 public alias isPure(alias A, string M) = isPure!(typeof(getChild!(A, M)));
457 /// True if the type of `M` in `A` implements `B`.
458 public alias isImplement(alias A, string M, alias B) = isImplement!(typeof(getChild!(A, M)), B);
459 /// True if `M` in `A` is mutable.
460 public alias isMutable(alias A, string M) = isMutable!(getChild!(A, M));
461 
462 /// Gets the alignment of `T` dynamically, returning the actual instance alignment.
463 public enum alignof(T) =
464 {
465     static if (is(T == class))
466         return __traits(classInstanceAlignment, T);
467     else
468         return T.alignof;
469 }();
470 
471 /// Gets the size of `T` dynamically, returning the actual instance size.
472 public enum sizeof(T) =
473 {
474     static if (is(T == class))
475         return __traits(classInstanceSize, T);
476     else
477         return T.sizeof;
478 }();
479 
480 /// Instantiates `T` using all default arguments (`void[]` for types or variadic)
481 public template DefaultInstantiate(alias T)
482     if (isTemplate!T)
483 {
484     string args()
485     {
486         string ret;
487         static foreach (arg; T.stringof[(T.stringof.indexOf("(") + 1)..T.stringof.indexOf(")")].split(", "))
488         {
489             static if (arg.split(" ").length == 1)
490                 ret ~= "void[], ";
491             else
492                 ret ~= arg.split(" ")[0]~".init, ";
493         }
494         return ret[0..(ret.length >= 2 ? $-2 : $)];
495     }
496 
497     alias defaultInstantiate = mixin("T!("~args~")");
498 }
499 
500 /// Gets the number of arguments that `F` takes, undefined or variadic.
501 public enum Arity(alias F) =
502 {
503     static if (F.stringof.startsWith("__lambda") && !is(typeof(F) == void))
504     {
505         typeof(toDelegate(F)) dg;
506         return Parameters!dg.length;
507     }
508     static if (!F.stringof.startsWith("__lambda") || !is(typeof(F) == void))
509         return Parameters!F.length;
510     else
511     {
512         string p = F.stringof[(F.stringof.lastIndexOf("(") + 1)..(F.stringof.lastIndexOf(")"))];
513         return p.split(", ").length;
514     }
515 }();
516 
517 /// Gets the module that `A` is declared in, or itself, if it has no module.
518 public template Module(alias A)
519 {
520     static if (!hasParents!A || isPackage!(Parent!A))
521         alias Module = A;
522     else
523         alias Module = Module!(Parent!A);
524 }
525 
526 /// Gets the package that `A` is declared in, or itself, if it has no package.
527 public template Package(alias A)
528 {
529     static if (!hasParents!A)
530         alias Package = A;
531     else static if (isPackage!(Parent!A))
532         alias Package = Parent!A;
533     else
534         alias Package = Package!(Parent!A);
535 }
536 
537 /// Gets the return type of a callable symbol.
538 public template ReturnType(alias F)
539     if (isCallable!F)
540 {
541     static if (isLambda!F && !__traits(compiles, { alias _ = std.traits.ReturnType!F; }))
542     {
543         typeof(toDelegate(F)) dg;
544         alias ReturnType = typeof(dg);
545     }  
546     else
547         alias ReturnType = std.traits.ReturnType!F;
548 }
549 
550 /// Gets the parameters of a callable symbol.
551 public template Parameters(alias F)
552     if (isCallable!F)
553 {
554     static if (isLambda!F && !__traits(compiles, { alias _ = std.traits.Parameters!F; }))
555     {
556         typeof(toDelegate(F)) dg;
557         alias Parameters = std.traits.Parameters!dg;
558     }  
559     else
560         alias Parameters = std.traits.Parameters!F;
561 }
562 
563 /// Gets the element type of `T`, if applicable.  
564 /// Returns the type of enum values if `T` is an enum.
565 public template ElementType(T) 
566 {
567     static if (is(T == U[], U) || is(T == U*, U) || is(T U == U[L], size_t L))
568         alias ElementType = ElementType!U;
569     else static if (isIndexable!T)
570     {
571         T temp;
572         alias ElementType = ElementType!(typeof(temp[0]));
573     }
574     else
575         alias ElementType = std.traits.OriginalType!T;
576 }
577 
578 /// Gets the length of `T`, if applicable.
579 public template Length(T) 
580 {
581     static if (is(T U == U[L], size_t L))
582         enum Length = L;
583 }
584 
585 /// Gets an `AliasSeq` all types that `T` implements.
586 public template Implements(T)
587 {
588     private template Flatten(H, T...)
589     {
590         static if (T.length)
591         {
592             alias Flatten = AliasSeq!(Flatten!H, Flatten!T);
593         }
594         else
595         {
596             static if (!is(H == Object) && (is(H == class) || is(H == interface)))
597                 alias Flatten = AliasSeq!(H, Implements!H);
598             else
599                 alias Flatten = Implements!H;
600         }
601     }
602 
603     static if (is(T S == super) && S.length)
604     {
605         static if (getAliasThis!T.length != 0)
606             alias Implements = AliasSeq!(TypeOf!(T, getAliasThis!T), Implements!(TypeOf!(T, getAliasThis!T)), NoDuplicates!(Flatten!S));
607         else
608             alias Implements = NoDuplicates!(Flatten!S);
609     }
610     else
611     {
612         static if (getAliasThis!T.length != 0)
613             alias Implements = AliasSeq!(TypeOf!(T, getAliasThis!T), Implements!(TypeOf!(T, getAliasThis!T)));
614         else
615             alias Implements = AliasSeq!();
616     }  
617 }
618 
619 /// Gets an `AliasSeq` of the names of all fields in `A`.
620 public template Fields(alias A)
621 {
622     alias Fields = AliasSeq!();
623 
624     static if (hasChildren!A)
625     static foreach (member; Children!A)
626     {
627         static if (isField!(getChild!(A, member)))
628             Fields = AliasSeq!(Fields, member);
629     }
630 }
631 
632 /// Gets an `AliasSeq` of the names all functions in `A`.
633 public template Functions(alias A)
634 {
635     alias Functions = AliasSeq!();
636 
637     static if (hasChildren!A)
638     static foreach (member; Children!A)
639     {
640         static if (isFunction!(getChild!(A, member)))
641             Functions = AliasSeq!(Functions, member);
642     }
643 }
644 
645 /// Gets an `AliasSeq` of the names of all types in `A`.
646 public template Types(alias A)
647 {
648     alias Types = AliasSeq!();
649 
650     static if (hasChildren!A)
651     static foreach (member; Children!A)
652     {
653         static if (isType!(getChild!(A, member)))
654             Types = AliasSeq!(Types, member);
655     }
656 }
657 
658 /// Gets an `AliasSeq` of the names of all templates in `A`.
659 public template Templates(alias A)
660 {
661     alias Templates = AliasSeq!();
662 
663     static if (hasChildren!A)
664     static foreach (member; Children!A)
665     {
666         static if (isTemplate!(getChild!(A, member)))
667             Templates = AliasSeq!(Templates, member);
668     }
669 }
670 
671 /// Gets the signature of `A` as a string, has defined special behavior for callables and fields.
672 /// This includes all attributes, templates (must be already initialized, names are lost,) and parameters.
673 public template Signature(alias A, bool DECLARING = true)
674 {
675     static if (isCallable!A)
676     enum Signature = 
677     {
678         static if (DECLARING)
679         {
680             string paramSig = "(";
681             static if (__traits(compiles, { alias _ = TemplateArgsOf!A; }))
682             {
683                 static foreach (i, A; TemplateArgsOf!A)
684                 {
685                     static if (__traits(compiles, { enum _ = B; }))
686                         paramSig ~= fullIdentifier!(typeof(B))~" T"~i.stringof[0..$-2];
687                     else
688                         paramSig ~= "alias T"~i.stringof[0..$-2];
689                 }
690                 paramSig ~= ")(";
691             }
692 
693             foreach (i, P; Parameters!A)
694             {
695                 foreach (Q; __traits(getParameterStorageClasses, A, i))
696                     paramSig ~= Q~" ";
697                 paramSig ~= fullIdentifier!P~" "~ParameterIdentifierTuple!A[i]~(i == Parameters!A.length - 1 ? null : ", ");
698             }
699             paramSig ~= ")";
700 
701             string attrs;
702             static foreach (ATTR; __traits(getFunctionAttributes, A))
703                 attrs ~= ATTR~" ";
704             attrs = attrs[0..(attrs.length == 0 ? $ : $-1)];
705         }
706         else
707         {
708             string paramSig = "(";
709             static if (__traits(compiles, { alias _ = TemplateArgsOf!A; }))
710             {
711                 static foreach (i, A; TemplateArgsOf!A)
712                 {
713                     static if (__traits(compiles, { enum _ = B; }))
714                         paramSig ~= "T"~i.stringof[0..$-2];
715                     else
716                         paramSig ~= "T"~i.stringof[0..$-2];
717                 }
718                 paramSig ~= ")(";
719             }
720 
721             foreach (i, P; Parameters!A)
722                 paramSig ~= ParameterIdentifierTuple!A[i]~(i == Parameters!A.length - 1 ? null : ", ");
723             paramSig ~= ")";
724         }
725 
726         static if (DECLARING)
727             return attrs~" "~fullIdentifier!(ReturnType!A)~" "~identifier!A~paramSig;
728         else
729             return identifier!A~paramSig;
730     }();
731 
732     static if (isField!A)
733     enum Signature =
734     {
735         static if (isManifest!F)
736             return "enum "~fullIdentifier!(typeof(F))~" "~identifier!F~" = "~F.stringof;
737         else static if (isStatic!F)
738             return "static "~fullIdentifier!(typeof(F))~" "~identifier!F;
739         else
740             return fullIdentifier!(typeof(F))~" "~identifier!F;
741     }();
742 
743     static if (!isCallable!A && !isField!A)
744         enum Signature = fullIdentifier!A;
745 }
746 
747 /// Gets an alias to the return type of `M` in `A`.
748 public alias ReturnType(alias A, string M) = ReturnType!(getChild!(A, M));
749 /// Gets an alias to the parameters of `M` in `A`.
750 public alias Parameters(alias A, string M) = Parameters!(getChild!(A, M));
751 /// Gets an alias to the element type of `M` in `A`.
752 public alias ElementType(alias A, string M) = ElementType!(typeof(getChild!(A, M)));
753 /// Gets an alias to the length of `M` in `A`.
754 public alias Length(alias A, string M) = Length!(typeof(getChild!(A, M)));
755 /// Gets an `AliasSeq` with all types implemented by `M` in `A`.
756 public alias Implements(alias A, string M) = Implements!(getChild!(A, M));
757 /// Gets an `AliasSeq` with all fields in `M` in `A`.
758 public alias Fields(alias A, string M) = Fields!(getChild!(A, M));
759 /// Gets an `AliasSeq` with all functions in `M` in `A`.
760 public alias Functions(alias A, string M) = Functions!(getChild!(A, M));
761 /// Gets an `AliasSeq` with all types in `M` in `A`.
762 public alias Types(alias A, string M) = Types!(getChild!(A, M));
763 /// Gets an `AliasSeq` with all templates in `M` in `A`.
764 public alias Templates(alias A, string M) = Templates!(getChild!(A, M));
765 /// Gets the signature of `M` in `A`.
766 public alias Signature(alias A, string M) = Signature!(getChild!(A, M));