1 /** 2 Copyright: Copyright (c) 2021, Joakim Brännström. All rights reserved. 3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 */ 6 module my.sumtype; 7 8 public import sumtype; 9 10 /** Check if an instance of a sumtype contains the specific type. 11 * 12 * This is from the D forum by Paul Backus, the author of sumtype. 13 * 14 * Example: 15 * --- 16 * assert(someType.contains!int); 17 * --- 18 * 19 */ 20 bool contains(T, ST)(ST st) if (isSumType!ST) { 21 return st.match!(value => is(typeof(value) == T)); 22 } 23 24 @("shall match the sumtype") 25 unittest { 26 alias T = SumType!(int, bool, char); 27 auto a = T(true); 28 assert(a.contains!bool); 29 assert(!a.contains!int); 30 } 31 32 /** Restrict matching in a sumtype to a bundle of types. 33 * 34 */ 35 template restrictTo(Args...) if (Args.length >= 1) { 36 import std.meta : IndexOf = staticIndexOf; 37 38 alias Types = Args[0 .. $ - 1]; 39 alias fun = Args[$ - 1]; 40 41 auto ref restrictTo(T)(auto ref T value) if (IndexOf!(T, Types) >= 0) { 42 import core.lifetime : forward; 43 44 static assert(IndexOf!(T, Types) >= 0); 45 return fun(forward!value); 46 } 47 } 48 49 @("shall restrict matching") 50 unittest { 51 static struct Foo0 { 52 } 53 54 static struct Foo1 { 55 } 56 57 static struct Foo2 { 58 } 59 60 static struct Foo3 { 61 } 62 63 static struct Foo4 { 64 } 65 66 static struct Bar0 { 67 } 68 69 static struct Bar1 { 70 } 71 72 static struct Bar2 { 73 } 74 75 SumType!(Foo0, Foo1, Foo2, Foo3, Foo4, Bar0, Bar1, Bar2) someType; 76 77 someType.match!(restrictTo!(Foo0, Foo1, Foo2, Foo3, (val) {}), 78 restrictTo!(Bar0, Bar1, Bar2, (val) {}), (_) {}); 79 } 80 81 /// For ignoring types. 82 void ignore(T)(T) { 83 } 84 85 // TODO: why doesn't this work? 86 //void ignore(T)(auto ref T) {} 87 88 @("shall ignore the type") 89 unittest { 90 static struct A { 91 } 92 93 static struct B { 94 } 95 96 static struct C { 97 } 98 99 SumType!(A, B, C) obj; 100 101 ignore(A.init); 102 103 //You can instantiate it explicitly to ignore a specific type: 104 obj.match!(ignore!A, (B b) {}, (C c) {}); 105 106 //// Or you can use it as a catch-all handler: 107 obj.match!((A a) {}, ignore); 108 } 109 110 /** All return types from `Args`. 111 */ 112 template AllReturn(Args...) if (Args.length >= 1) { 113 import std.meta : AliasSeq; 114 import std.traits : ReturnType; 115 116 static if (Args.length == 1) { 117 alias AllReturn = ReturnType!(Args[0]); 118 } else { 119 alias AllReturn = AliasSeq!(ReturnType!(Args[0]), AllReturn!(Args[1 .. $])); 120 } 121 } 122 123 alias SumTypeFromReturn(T...) = SumType!(AllReturn!T); 124 125 @("shall make a sumtype from the return types") 126 unittest { 127 int fn1() { 128 return 0; 129 } 130 131 double fn2() { 132 return 0.0; 133 } 134 135 SumTypeFromReturn!(fn1, fn2) obj; 136 obj.match!((int x) {}, (double x) {}); 137 }