1 /++ Result type. 2 +/ 3 module nxt.result; 4 5 @safe: 6 7 /++ Result of `T`. 8 Designed for error handling where an operation can either succeed or fail. 9 - TODO: Add member `toRange` alias with `opSlice` 10 - TODO: Add member visit() 11 +/ 12 struct Result(T) { 13 static if (!__traits(isPOD, T)) 14 import core.lifetime : move, moveEmplace; 15 this(T value) { 16 static if (__traits(isPOD, T)) 17 _value = value; 18 else 19 () @trusted { moveEmplace(value, _value); }(); /+ TODO: remove when compiler does this +/ 20 _isValid = true; 21 } 22 ref typeof(this) opAssign(T value) { 23 static if (__traits(isPOD, T)) 24 _value = value; 25 else 26 () @trusted { move(value, _value); }(); /+ TODO: remove when compiler does this +/ 27 _isValid = true; 28 return this; 29 } 30 @property: 31 ref inout(T) value() inout scope return in(isValid) => _value; 32 // ditto 33 ref inout(T) opUnary(string op)() inout scope return if (op == "*") => value; 34 string toString() inout scope pure { 35 import std.conv : to; 36 return isValid ? _value.to!string : "invalid"; 37 } 38 pure nothrow @nogc: 39 bool isValid() const scope => _isValid; 40 alias hasValue = isValid; 41 bool opCast(T : bool)() const scope => _isValid; 42 static typeof(this) invalid() => typeof(this).init; 43 private 44 T _value; 45 bool _isValid; 46 } 47 48 /// to string conversion 49 @safe pure unittest { 50 alias R = Result!int; 51 const R r1; 52 assert(r1.toString == "invalid"); 53 const R r2 = 42; 54 assert(r2.toString == "42"); 55 } 56 57 /// result of uncopyable type 58 @safe pure nothrow @nogc unittest { 59 alias T = Uncopyable; 60 alias R = Result!T; 61 R r1; 62 assert(!r1); 63 assert(r1 == R.invalid); 64 assert(r1 != R(T.init)); 65 assert(!r1.isValid); 66 T t = T(42); 67 r1 = move(t); 68 assert(r1 != R(T.init)); 69 assert(*r1 == T(42)); 70 R r2 = T(43); 71 assert(*r2 == T(43)); 72 assert(r2.value == T(43)); 73 } 74 75 version (unittest) { 76 import core.lifetime : move; 77 private static struct Uncopyable { this(this) @disable; int _x; } 78 }