1 ///
2 module dpq.meta;
3 
4 import dpq.attributes;
5 
6 import std.traits;
7 import std.typecons : Nullable;
8 import std.datetime : SysTime;
9 
10 version(unittest) import std.stdio;
11 
12 /**
13 	Returns the array's base type
14 
15 	Returns the string type for any type that returns true
16 	for isSomeString!T
17 
18 	Examples:
19 	---------------
20 	alias T = BaseType!(int[][]);
21 	alias T2 = BaseType!(int[]);
22 	alias T3 = BaseType!int;
23 	alias T4 = BaseType!(string[])
24 
25 	static assert(is(T == int));
26 	static assert(is(T2 == int));
27 	static assert(is(T3 == int));
28 	static assert(is(T4 == string));
29 	---------------
30 */
31 template BaseType(T)
32 {
33 	import std.typecons : TypedefType;
34 	static if (isArray!T && !isSomeString!T)
35 		alias BaseType = BaseType!(ForeachType!T);
36 	else
37 		alias BaseType = TypedefType!(Unqual!T);
38 }
39 
40 unittest
41 {
42 	writeln(" * meta");
43 	writeln("\t * BaseType");
44 
45 	static assert(is(BaseType!(int[][][]) == int));
46 	static assert(is(BaseType!(string[]) == string));
47 	static assert(is(BaseType!string == string));
48 	static assert(is(BaseType!dstring == dstring));
49 }
50 
51 /**
52 	Returns the number of dimensions of the given array type
53 
54 	Examples:
55 	-----------------
56 	auto dims = ArrayDimensions!(int[][]);
57 	static assert(dims == 2);
58 	-----------------
59  */
60 deprecated("Use ArraySerialier's ArrayDimensions instead")
61 template ArrayDimensions(T)
62 {
63 	static if (isArray!T)
64 		enum ArrayDimensions = 1 + ArrayDimensions!(ForeachType!T);
65 	else 
66 		enum ArrayDimensions = 0;
67 }
68 
69 
70 /// Removes any Nullable specifiers, even multiple levels
71 template NoNullable(T)
72 {
73 	static if (isInstanceOf!(Nullable, T))
74 		// Nullable nullable? Costs us nothing, so why not
75 		alias NoNullable = NoNullable!(Unqual!(ReturnType!(T.get)));
76 	else
77 		alias NoNullable = T;
78 }
79 
80 /**
81 	Will strip off any Nullable, Typedefs and qualifiers from a given type.
82 	It's a bit paranoid and tries to remove any identifiers multiple times, until
83 	the removal attempt yields no changes, but it shouldn't be a problem since it's
84 	all just compile-time.
85 
86 	Examples:
87 		static assert(RealType!(const Nullable!(immutable int) == int));
88  */
89 template RealType(T)
90 {
91 	import std.typecons : TypedefType;
92 	// Ugly, but better than doing this every time we need it
93 	alias NT = OriginalType!(Unqual!(NoNullable!(TypedefType!T)));
94 
95 	static if (is(T == NT))
96 		alias RealType = NT;
97 	else
98 		alias RealType = RealType!NT;
99 }