1 /// Add "tagged value" to D for an effective use of std.variant.Algebraic. 2 module tag; 3 4 /** 5 Wraps **T** with **tag_**. 6 */ 7 public struct Tag(string tag_, T = void) { 8 /// tag 9 enum string tag = tag_; 10 static if(is(T == void)) { 11 } else { 12 /// internal value 13 public T value; 14 alias value this; 15 16 public this(T value) { 17 this.value = value; 18 } 19 } 20 } 21 22 /// 23 @system unittest { 24 import std.variant : Algebraic, visit; 25 alias Option(T) = Algebraic!( 26 Tag!("Some", T), 27 Tag!"None" 28 ); 29 Option!int option; 30 31 option = tag!"Some"(1); 32 assert(option.visit!( 33 (Tag!("Some", int) a) => Option!int(tag!"Some"(a + 1)), 34 (Tag!"None" a) => Option!int(a) 35 ) == tag!"Some"(2)); 36 37 option = tag!"None"(); 38 assert(option.visit!( 39 (Tag!("Some", int) a) => Option!int(tag!"Some"(a + 1)), 40 (Tag!"None" a) => Option!int(a) 41 ) == tag!"None"()); 42 } 43 44 @safe unittest { 45 alias T = Tag!("Tag", int); 46 static assert(T.tag == "Tag"); 47 48 T tagged = 12; 49 assert(tagged == tag!"Tag"(12)); 50 assert(tagged + 1 == 13); 51 } 52 53 /// Gets the underlying type whitch a **Tag** wraps. If **T** is not a **Tag** it will alias itself to **T**. 54 template TaggedType(T) { 55 static if(is(T == Tag!(tag_, U), string tag_, U)) { 56 alias TaggedType = U; 57 } else { 58 alias TaggedType = T; 59 } 60 } 61 62 /// 63 @safe unittest { 64 static assert(is( 65 TaggedType!(Tag!("Tag", int)) == int 66 )); 67 static assert(is( 68 TaggedType!int == int 69 )); 70 } 71 72 /// Wraps **value** with **tag_**. 73 public template tag(string tag_) { 74 /// ditto 75 public Tag!(tag_, T) tag(T)(T value) { 76 Tag!(tag_, T) temp; 77 temp.value = value; 78 return temp; 79 } 80 81 @safe unittest { 82 assert(tag!"Some"(1) == 1); 83 assert(tag!"Some"(1) != tag!"Some"(114514)); 84 } 85 86 /// ditto 87 public pure @safe @nogc Tag!(tag_, void) tag() { 88 Tag!(tag_, void) temp; 89 return temp; 90 } 91 } 92 93 /// 94 @safe unittest { 95 Tag!("Tag", int) tagged = tag!"Tag"(1); 96 Tag!"None" nil = tag!"None"; 97 }