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 }