1 /*******************************************************************************
2 
3     Copyright:
4         Copyright (C) 2017 dunnhumby Germany GmbH. All rights reserved.
5 
6     NB: because this module is often used as purely compile-time dependency it
7         used built-in asserts instead of `ocean.core.Test` to reduce amount of
8         cyclic imports. `ocean.meta` modules in general are not supposed to
9         import anything outside of `ocean.meta`.
10 
11     License:
12         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
13         Alternatively, this file may be distributed under the terms of the Tango
14         3-Clause BSD License (see LICENSE_BSD.txt for details).
15 
16 *******************************************************************************/
17 
18 module ocean.meta.types.Typedef;
19 
20 import ocean.meta.types.Qualifiers;
21 
22 /*******************************************************************************
23 
24     Replacement for `typedef` which is completely deprecated.
25 
26     It generates a wrapper struct with `alias this`.
27 
28     Used as mixin(Typedef!(hash_t, "MyHash"))
29 
30     `IsTypedef` member alias is defined so that any struct type can be quickly
31     checked if it originates from typedef via `is(typeof(S.IsTypedef))`.
32     This is a hack reserved for backwards compatibility in libraries and should
33     never be relied upon in user code.
34 
35     Parameters:
36         T       = type to typedef
37         name    = identifier string for new type
38         initval = optional default value for that type
39 
40 *******************************************************************************/
41 
42 template Typedef(T, istring name, T initval)
43 {
44     static assert (name.length, "Can't create Typedef with an empty identifier");
45 
46     enum Typedef =
47         ("static struct " ~ name ~
48         "{ " ~
49         "alias IsTypedef = void;" ~
50         T.stringof ~ " value = " ~ initval.stringof ~ ";" ~
51         "alias value this;" ~
52         "this(" ~ T.stringof ~ " rhs) { this.value = rhs; }" ~
53         " }");
54 }
55 
56 /// ditto
57 template Typedef(T, istring name)
58 {
59     static assert (name.length, "Can't create Typedef with an empty identifier");
60 
61     enum Typedef =
62         ("static struct " ~ name ~
63         "{ " ~
64         "alias IsTypedef = void;" ~
65         T.stringof ~ " value; " ~
66         "alias value this;" ~
67         "this(" ~ T.stringof ~ " rhs) { this.value = rhs; }" ~
68         " }");
69 }
70 
71 unittest
72 {
73     mixin(Typedef!(int, "MyInt1", 42));
74     mixin(Typedef!(int, "MyInt2", 42));
75 
76     static assert (!is(MyInt1 : MyInt2));
77 
78     MyInt1 myint;
79     assert(myint == 42);
80 
81     void foo1(MyInt2) { }
82     void foo2(MyInt1) { }
83     void foo3(int) { }
84 
85     static assert (!is(typeof(foo1(myint))));
86     static assert ( is(typeof(foo2(myint))));
87     static assert ( is(typeof(foo3(myint))));
88 
89     int base = myint;
90     assert(base == myint);
91     myint = cast(MyInt1) (base + 1);
92     assert(myint == 43);
93 }
94 
95 unittest
96 {
97     struct MyType { }
98 
99     mixin(Typedef!(MyType, "MyType2"));
100     MyType2 var;
101 
102     static assert (is(typeof(var) : MyType));
103 }
104 
105 unittest
106 {
107     mixin(Typedef!(int, "MyInt"));
108     MyInt var = 42;
109     assert (var == 42);
110 }
111 
112 /*******************************************************************************
113 
114     Resolves to type used as first argument to `Typedef!(type, name)` call
115     when defining T.
116 
117     Params:
118         T = type to reduce to base, must be generated by `Typedef`
119 
120 *******************************************************************************/
121 
122 template TypedefBaseType ( T )
123 {
124     alias typeof(T.value) TypedefBaseType;
125 }
126 
127 unittest
128 {
129     mixin(Typedef!(int, "MyInt"));
130     static assert (is(TypedefBaseType!(MyInt) == int));
131 }
132 
133 /*******************************************************************************
134 
135     Helper function to reduce typedef to its base value
136 
137     Params:
138         T = type to reduce to base, must be generated by `Typedef`
139 
140     Returns:
141         `value` cast to `TypedefBaseType!(T)`
142 
143 *******************************************************************************/
144 
145 TypedefBaseType!(T) castToBase ( T ) ( T value )
146 {
147     return cast(TypedefBaseType!(T)) value;
148 }
149 
150 unittest
151 {
152     mixin(Typedef!(int, "MyInt"));
153     MyInt value = 42;
154     assert (castToBase(value) == 42);
155     static assert (is(typeof(castToBase(value)) == int));
156 }