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 }