1 /**
2     Helpers for creating special types.
3 
4     Copyright:
5         Copyright © 2023-2025, Kitsunebi Games
6         Copyright © 2023-2025, Inochi2D Project
7     
8     License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9     Authors:   Luna Nielsen
10 */
11 module numem.core.types;
12 
13 /**
14     Creates a new unique handle type.
15 
16     Handle types are pointers to opaque structs.
17 
18     Params:
19         name = Unique name of the handle.
20 
21     Examples:
22         ---
23         alias VkInstance = OpaqueHandle!("VkInstance");
24         ---
25 */
26 template OpaqueHandle(string name) {
27     struct OpaqueHandleT(string name);
28     alias OpaqueHandle = OpaqueHandleT!(name)*;
29 }
30 
31 @("OpaqueHandle")
32 unittest {
33     alias HandleT1 = OpaqueHandle!("HandleT1");
34     alias HandleT2 = OpaqueHandle!("HandleT2");
35 
36     assert(!is(HandleT1 == HandleT2));
37     assert(!is(HandleT1 : HandleT2));
38 }
39 
40 /**
41     Creates a new type based on an existing type.
42 
43     Params:
44         T = Base type of the typedef.
45         name = An extra identifier for the type.
46         init = Initializer value for this type.
47 
48     Examples:
49         ---
50         alias MyInt = TypeDef!(int, "MyInt");
51         assert(!is(MyInt == int));
52         ---
53 */
54 template TypeDef(T, string name, T init = T.init) {
55     import std.format : format;
56 
57     mixin(q{
58         struct %s {
59         @nogc nothrow:
60         private:
61             T value = init;
62 
63         public:
64             alias BaseType = T;
65             alias value this;
66 
67             static if ((is(T == struct) || is(T == union)) && !is(typeof({T t;}))) {
68                 @disable this();
69             }
70             this(T init) { this.value = init; }
71             this(typeof(this) init) { this.value = init.value; }
72         }
73     }.format(name));
74 
75     alias TypeDef = mixin(name);
76 }
77 
78 /**
79     Gets the base type of a typedef.
80 */
81 template TypeDefBase(T) {
82     static if (is(typeof({ T.BaseType t; }))) {
83         alias TypeDefBase = T.BaseType;
84     } else {
85         static assert(0, "Not a TypeDef!");
86     }
87 }
88 
89 @("TypeDef")
90 unittest {
91     alias MyInt = TypeDef!(int, "MyInt");
92     
93     // They're not the same type, but they *are* implicitly convertible.
94     assert(!is(MyInt == int));
95     assert(is(MyInt : int));
96 
97     int i = 42;
98     MyInt va = 42;
99 
100     assert(i == va);
101     assert(TypeDefBase!MyInt.stringof == int.stringof);
102 }