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 }