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 	@property string toString() pure nothrow @safe @nogc => toStringFaster(_enum);
15 	E _enum;					// the wrapped enum
16 	alias _enum this;
17 }
18 
19 ///
20 pure @safe unittest {
21 	enum X { a,
22 			 b,
23 			 _b = b			 // enumerator alias
24 	}
25 	alias EnumX = Enum!X;
26 	assert(EnumX(X.a).toString == "a");
27 	assert(EnumX(X.b).toString == "b");
28 	assert(EnumX(X._b).toString == "b"); // alias encodes to original
29 }
30 
31 /** Fast and more generic implementation of `std.conv.to` for enumerations.
32  */
33 string toStringFaster(T)(const scope T value) pure nothrow @safe @nogc
34 if (is(T == enum)) {
35 	import std.meta : AliasSeq;
36 	/* TODO: skip wrapping in `AliasSeq` when `allMembers` can be iterated
37 	 * directly when a bug in compiler has been fixed */
38 	alias members = AliasSeq!(__traits(allMembers, T));
39 	final switch (value) {
40 		static foreach (index, member; members) {
41 			static if (index == 0 ||
42 					   (__traits(getMember, T, members[index - 1]) !=
43 						__traits(getMember, T, member))) {
44 			case __traits(getMember, T, member):
45 				return member;
46 			}
47 		}
48 	}
49 }
50 
51 ///
52 pure nothrow @safe @nogc unittest {
53 	enum E { unknown, x, y, z, }
54 	assert(E.x.toStringFaster == "x");
55 	assert(E.y.toStringFaster == "y");
56 	assert(E.z.toStringFaster == "z");
57 }
58 
59 /** Faster implementation of `std.conv.to` for enumerations with no aliases.
60  */
61 string toStringNonAliases(T)(const scope T value) pure nothrow @safe @nogc
62 if (is(T == enum))			  /+ TODO: check for no aliases +/
63 {
64 	final switch (value) {
65 		static foreach (member; __traits(allMembers, T)) {
66 		case __traits(getMember, T, member):
67 			return member;
68 		}
69 	}
70 }
71 
72 ///
73 pure nothrow @safe @nogc unittest {
74 	enum E { unknown, x, y, z, }
75 	assert(E.x.toStringNonAliases == "x");
76 	assert(E.y.toStringNonAliases == "y");
77 	assert(E.z.toStringNonAliases == "z");
78 }