1 module libd.memory.ptr;
2 
3 // "NotNull" is deemed "uninitialised" if it's value is null. Think of it like "undefined" from JS.
4 
5 struct NotNullPtr(T, string Tag_ = "default")
6 {
7     static immutable Tag = Tag_;
8     alias ptr this;
9     T* ptr;
10 
11     auto opAssign()(T* ptr)
12     {
13         assert(ptr !is null, "Pointer is null.");
14         this.ptr = ptr;
15         return this;
16     }
17 
18     auto opAssign()(MaybeNullPtr!(T, Tag) ptr)
19     {
20         assert(ptr !is null, "Pointer is null.");
21         this.ptr = ptr;
22         return this;
23     }
24 
25     auto opAssign(string Tag2)(MaybeNullPtr!(T, Tag2) ptr)
26     if(Tag2 != Tag)
27     {
28         static assert(false, "Cannot implicitly assign from pointer with different tag.");
29     }
30 }
31 
32 struct MaybeNullPtr(T, string Tag_ = "default")
33 {
34     static immutable Tag = Tag_;
35     alias ptr this;
36     T* ptr;
37 }
38 
39 struct NotNullSlice(T, string Tag_ = "default")
40 {
41     static immutable Tag = Tag_;
42     alias slice this;
43     T[] slice;
44 
45     auto opAssign()(T[] value)
46     {
47         assert(value !is null, "Slice is null.");
48         this.slice = value;
49         return this;
50     }
51 
52     auto opAssign()(MaybeNullSlice!(T, Tag) slice)
53     {
54         assert(slice !is null, "Slice is null.");
55         this.slice = slice.slice;
56         return this;
57     }
58 
59     auto opAssign(string Tag2)(MaybeNullSlice!(T, Tag2) slice)
60     if(Tag2 != Tag)
61     {
62         static assert(false, "Cannot implicitly assign from slice with different tag.");
63     }
64 }
65 
66 struct MaybeNullSlice(T, string Tag_ = "default")
67 {
68     static immutable Tag = Tag_;
69     alias slice this;
70     T[] slice;
71 }
72 
73 @safe @nogc nothrow pure:
74 // This code is mostly write-once update-never due to its simple nature, so I don't give a damn about making it readable.
75 MaybeNullPtr  !(T, Tag) maybeNull(string Tag, T)(T* ptr)    { return typeof(return)(ptr);   }
76 MaybeNullPtr  !(T, Tag) maybeNull(string Tag, T)(NotNullPtr!(T, Tag) ptr) { return typeof(return)(ptr); }
77 MaybeNullSlice!(T, Tag) maybeNull(string Tag, T)(T[] slice) { return typeof(return)(slice); }
78 MaybeNullSlice!(T, Tag) maybeNull(string Tag, T)(NotNullSlice!(T, Tag) slice) { return typeof(return)(slice); }
79 NotNullPtr    !(T, Tag) notNull  (string Tag, T)(T* ptr)    { assert(ptr !is null, "Pointer is null"); return typeof(return)(ptr); }
80 NotNullPtr    !(T, Tag) notNull  (string Tag, T)(MaybeNullPtr!(T, Tag) ptr) { assert(ptr !is null, "Pointer is null"); return typeof(return)(ptr); }
81 NotNullSlice  !(T, Tag) notNull  (string Tag, T)(T[] slice) { assert(slice !is null, "Slice is null"); return typeof(return)(slice); }
82 NotNullSlice  !(T, Tag) notNull  (string Tag, T)(MaybeNullSlice!(T, Tag) slice) { assert(slice !is null, "Slice is null"); return typeof(return)(slice); }
83 
84 MaybeNullPtr  !(T, "default") maybeNull(T)(T* ptr)    { return typeof(return)(ptr);   }
85 NotNullPtr    !(T, "default") notNull  (T)(T* ptr)    { assert(ptr !is null, "Pointer is null"); return typeof(return)(ptr); }
86 MaybeNullSlice!(T, "default") maybeNull(T)(T[] slice) { return typeof(return)(slice); }
87 NotNullSlice  !(T, "default") notNull  (T)(T[] slice) { assert(slice !is null, "Slice is null"); return typeof(return)(slice); }