1 module nxt.enum_ex;
2 
3 @safe:
4 
5 /** Enumeration wrapper that uses optimized conversion to string (via `toString`
6  * member).
7  *
8  * See_Also: https://forum.dlang.org/thread/ppndhxvzayedgpbjculm@forum.dlang.org?page=1
9  *
10  * TODO: Move logic to `std.conv.to`.
11  */
12 struct Enum(E)
13 if (is(E == enum))
14 {
15     @property string toString() @safe pure nothrow @nogc => toStringFaster(_enum);
16     E _enum;                    // the wrapped enum
17     alias _enum this;
18 }
19 
20 ///
21 @safe pure unittest
22 {
23     enum X { a,
24              b,
25              _b = b             // enumerator alias
26     }
27     alias EnumX = Enum!X;
28     assert(EnumX(X.a).toString == "a");
29     assert(EnumX(X.b).toString == "b");
30     assert(EnumX(X._b).toString == "b"); // alias encodes to original
31 }
32 
33 /** Fast and more generic implementation of `std.conv.to` for enumerations.
34  */
35 string toStringFaster(T)(const scope T value) @safe pure nothrow @nogc
36 if (is(T == enum))
37 {
38     import std.meta : AliasSeq;
39     /* TODO: skip wrapping in `AliasSeq` when `allMembers` can be iterated
40      * directly when a bug in compiler has been fixed */
41     alias members = AliasSeq!(__traits(allMembers, T));
42     final switch (value)
43     {
44         static foreach (index, member; members)
45         {
46             static if (index == 0 ||
47                        (__traits(getMember, T, members[index - 1]) !=
48                         __traits(getMember, T, member)))
49             {
50             case __traits(getMember, T, member):
51                 return member;
52             }
53         }
54     }
55 }
56 
57 ///
58 @safe pure nothrow @nogc unittest
59 {
60     enum E { unknown, x, y, z, }
61     assert(E.x.toStringFaster == "x");
62     assert(E.y.toStringFaster == "y");
63     assert(E.z.toStringFaster == "z");
64 }
65 
66 /** Faster implementation of `std.conv.to` for enumerations with no aliases.
67  */
68 string toStringNonAliases(T)(const scope T value) @safe pure nothrow @nogc
69 if (is(T == enum))              // TODO: check for no aliases
70 {
71     final switch (value)
72     {
73         static foreach (member; __traits(allMembers, T))
74         {
75         case __traits(getMember, T, member):
76             return member;
77         }
78     }
79 }
80 
81 ///
82 @safe pure nothrow @nogc unittest
83 {
84     enum E { unknown, x, y, z, }
85     assert(E.x.toStringNonAliases == "x");
86     assert(E.y.toStringNonAliases == "y");
87     assert(E.z.toStringNonAliases == "z");
88 }