1 /** 2 Copyright: Copyright (c) 2020, 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 Definition of an optional type using sumtype. 7 */ 8 module my.optional; 9 10 import std.traits : isSomeFunction, ReturnType; 11 12 import sumtype; 13 14 alias Optional(T) = SumType!(None, Some!T); 15 16 /// Optional with no value 17 Optional!T none(T)() { 18 return typeof(return)(None.init); 19 } 20 21 /// An optional containing a value. 22 Optional!T some(T)(T value) { 23 return typeof(return)(Some!T(value)); 24 } 25 26 /// No value in the Optional. 27 struct None { 28 } 29 30 /// A value. 31 struct Some(T) { 32 T value; 33 alias value this; 34 } 35 36 bool hasValue(T : SumType!(None, Some!U), U)(T v) { 37 return match!((None a) => false, (Some!U a) => true)(v); 38 } 39 40 U orElse(T, U)(T v, U or) if (is(T == Optional!U)) { 41 return match!((None a) => or, (Some!U a) => a.value)(v); 42 } 43 44 T orElse(T : SumType!(None, Some!U), U)(T v, T or) { 45 return match!((None a) => or, (Some!U a) => T(a))(v); 46 } 47 48 T orElse(T : SumType!(None, Some!U), U, OrT)(T v, OrT or) 49 if (isSomeFunction!OrT && is(ReturnType!OrT == T)) { 50 return match!((None a) => or(), (Some!U a) => T(a))(v); 51 } 52 53 U orElse(T : SumType!(None, Some!U), U, OrT)(T v, OrT or) 54 if (isSomeFunction!OrT && is(ReturnType!OrT == U)) { 55 return match!((None a) => or(), (Some!U a) => a.value)(v); 56 } 57 58 @("shall chain multiple optional") 59 unittest { 60 static int fn1() { 61 return 5; 62 } 63 64 static Optional!int fn2() { 65 return some(5); 66 } 67 68 assert(none!int.hasValue == false); 69 assert(some(5).hasValue == true); 70 71 assert(none!int.orElse(5) == 5); 72 assert(none!int.orElse(() => 5) == 5); 73 assert(none!int.orElse(&fn1) == 5); 74 75 assert(some(10).orElse(5) == 10); 76 assert(some(10).orElse(() => 5) == 10); 77 assert(some(10).orElse(&fn1) == 10); 78 79 assert(none!int.orElse(some(5)) == some(5)); 80 assert(none!int.orElse(() => some(5)) == some(5)); 81 assert(none!int.orElse(&fn2) == some(5)); 82 83 assert(some(10).orElse(some(5)) == some(10)); 84 assert(some(10).orElse(() => some(5)) == some(10)); 85 assert(some(10).orElse(&fn2) == some(10)); 86 }