1 /++
2 This module is implementing the Expected idiom.
3 
4 See the [Andrei Alexandrescu’s talk (Systematic Error Handling in C++](http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C)
5 and [its slides](https://skydrive.live.com/?cid=f1b8ff18a2aec5c5&id=F1B8FF18A2AEC5C5!1158).
6 
7 Or more recent ["Expect the Expected"](https://www.youtube.com/watch?v=nVzgkepAg5Y) by Andrei Alexandrescu for further background.
8 
9 It is also inspired by C++'s proposed [std::expected](https://wg21.link/p0323) and [Rust's](https://www.rust-lang.org/) [Result](https://doc.rust-lang.org/std/result/).
10 
11 Similar work is [expectations](http://code.dlang.org/packages/expectations) by Paul Backus.
12 
13 ## Main features
14 
15 $(LIST
16     * lightweight, no other external dependencies
17     * works with `pure`, `@safe`, `@nogc`, `nothrow`, and `immutable`
18     * provides methods: `ok`, `err`, `consume`, `expect`, `expectErr`, `andThen`, `orElse`, `map`, `mapError`, `mapOrElse`
19     * type inference for ease of use with `ok` and `err`
20     * allows to use same types for `T` and `E`
21     * allows to define $(LREF Expected) without value (`void` for `T`) - can be disabled with custom `Hook`
22     * provides facility to change the $(LREF Expected) behavior by custom `Hook` implementation using the Design by introspection paradigm.
23     * can enforce result check (with a cost)
24     * can behave like a normal `Exception` handled code by changing the used `Hook` implementation
25     * range interface
26 )
27 
28 ## Description
29 
30 Actual $(LREF Expected) type is defined as $(D Expected!(T, E, Hook)), where:
31 
32 $(LIST
33     * `T` defines type of the success value
34     * `E` defines type of the error
35     * `Hook` defines behavior of the $(LREF Expected)
36 )
37 
38 Default type for error is `string`, i.e. `Expected!int` is the same as `Expected!(int, string)`.
39 
40 $(LREF Abort) is used as a default hook.
41 
42 ### Hooks
43 
44 $(LREF Expected) has customizable behavior with the help of a third type parameter,
45 `Hook`. Depending on what methods `Hook` defines, core operations on the
46 $(LREF Expected) may be verified or completely redefined.
47 If `Hook` defines no method at all and carries no state, there is no change in
48 default behavior.
49 
50 This module provides a few predefined hooks (below) that add useful behavior to
51 $(LREF Expected):
52 
53 $(BOOKTABLE ,
54     $(TR $(TD $(LREF Abort)) $(TD
55         Fails every incorrect operation with a call to `assert(0)`.
56         It is the default third parameter, i.e. $(D Expected!short) is the same as
57         $(D Expected!(short, string, Abort)).
58     ))
59     $(TR $(TD $(LREF Throw)) $(TD
60         Fails every incorrect operation by throwing an exception.
61     ))
62     $(TR $(TD $(LREF AsException)) $(TD
63         With this hook implementation $(LREF Expected) behaves just like regular
64         $(D Exception) handled code.
65 
66         That means when function returns $(LREF expected) value, it returns instance
67         of $(LREF Expected) with a success value.
68         But when it tries to return error, $(D Exception) is thrown right away,
69         i.e. $(LREF Expected) fails in constructor.
70     ))
71     $(TR $(TD $(LREF RCAbort)) $(TD
72         Similar to $(LREF Abort) hook but uses reference counted payload instead
73         which enables checking if the caller properly checked result of the
74         $(LREF Expected).
75     ))
76 )
77 
78 The hook's members are looked up statically in a Design by Introspection manner
79 and are all optional. The table below illustrates the members that a hook type
80 may define and their influence over the behavior of the `Checked` type using it.
81 In the table, `hook` is an alias for `Hook` if the type `Hook` does not
82 introduce any state, or an object of type `Hook` otherwise.
83 
84 $(TABLE_ROWS
85     * + Hook member
86       + Semantics in Expected!(T, E, Hook)
87     * - `enableDefaultConstructor`
88       - If defined, $(LREF Expected) would have enabled or disabled default constructor
89         based on it's `bool` value. Default constructor is disabled by default.
90         `opAssign` for value and error types is generated if default constructor is enabled.
91     * - `enableCopyConstructor`
92       - If defined, $(LREF Expected) would have enabled or disabled copy constructor based
93         on it's `bool` value. It is enabled by default. When disabled, it enables automatic
94         check if the result was checked either for value or error.
95         When not checked it calls $(D hook.onUnchecked) if provided.
96 
97         $(NOTE WARNING: As currently it's not possible to change internal state of `const`
98         or `immutable` object, automatic checking would't work on these. Hopefully with
99         `__mutable` proposal..)
100     * - `enableRefCountedPayload`
101       - Set $(LREF Expected) instances to use reference counted payload storage. It's usefull
102         when combined with `onUnchecked` to forcibly check that the result was checked for value
103         or error.
104     * - `enableVoidValue`
105       - Defines if $(LREF Expected) supports `void` values. It's enabled by default so this
106         hook can be used to disable it.
107     * - `onAccessEmptyValue`
108       - If value is accessed on unitialized $(LREF Expected) or $(LREF Expected) with error
109         value, $(D hook.onAccessEmptyValue!E(err)) is called. If hook doesn't implement the
110         handler, `T.init` is returned.
111     * - `onAccessEmptyError`
112       - If error is accessed on unitialized $(LREF Expected) or $(LREF Expected) with value,
113         $(D hook.onAccessEmptyError()) is called. If hook doesn't implement the handler,
114         `E.init` is returned.
115     * - `onUnchecked`
116       - If the result of $(LREF Expected) isn't checked, $(D hook.onUnchecked()) is called to
117         handle the error. If hook doesn't implement the handler, assert is thrown.
118         $(NOTE Note that `hook.enableCopyConstructor` must be `false` or `hook.enableRefCountedPayload`
119         must be `true` for checks to work.)
120     * - `onValueSet`
121       - $(D hook.onValueSet!T(val)) function is called when success value is being set to
122         $(LREF Expected). It can be used for loging purposes, etc.
123     * - `onErrorSet`
124       - $(D hook.onErrorSet!E(err)) function is called when error value is being set to
125         $(LREF Expected). This hook function is used by $(LREF AsException) hook implementation
126         to change `Expected` idiom to normal `Exception` handling behavior.
127 )
128 
129 License: BSL-1.0
130 Author: Tomáš Chaloupka
131 +/
132 
133 //TODO: collect errno function call - see https://dlang.org/phobos/std_exception.html#ErrnoException
134 
135 module expected;
136 
137 /// $(H3 Basic usage)
138 @("Basic usage example")
139 @safe unittest
140 {
141     auto foo(int i) {
142         if (i == 0) return err!int("oops");
143         return ok(42 / i);
144     }
145 
146     version (D_Exceptions)
147     {
148         auto bar(int i) {
149             if (i == 0) throw new Exception("err");
150             return i-1;
151         }
152     }
153 
154     // basic checks
155     assert(foo(2));
156     assert(foo(2).hasValue);
157     assert(!foo(2).hasError);
158     assert(foo(2).value == 21);
159 
160     assert(!foo(0));
161     assert(!foo(0).hasValue);
162     assert(foo(0).hasError);
163     assert(foo(0).error == "oops");
164 
165     // void result
166     assert(ok()); // no error -> success
167     assert(!ok().hasError);
168     // assert(err("foo").hasValue); // doesn't have hasValue and value properties
169 
170     version (D_Exceptions)
171     {
172         // expected from throwing function
173         assert(consume!bar(1) == 0);
174         assert(consume!bar(0).error.msg == "err");
175     }
176 
177     // orElse
178     assert(foo(2).orElse!(() => 0) == 21);
179     assert(foo(0).orElse(100) == 100);
180 
181     // andThen
182     assert(foo(2).andThen(foo(6)) == 7);
183     assert(foo(0).andThen(foo(6)).error == "oops");
184 
185     // map
186     assert(foo(2).map!(a => a*2).map!(a => a - 2) == 40);
187     assert(foo(0).map!(a => a*2).map!(a => a - 2).error == "oops");
188 
189     // mapError
190     assert(foo(0).mapError!(e => "OOPS").error == "OOPS");
191     assert(foo(2).mapError!(e => "OOPS") == 21);
192 
193     // mapOrElse
194     assert(foo(2).mapOrElse!(v => v*2, e => 0) == 42);
195     assert(foo(0).mapOrElse!(v => v*2, e => 0) == 0);
196 }
197 
198 version (D_Exceptions)
199 {
200     /// $(H3 Advanced usage - behavior modification)
201     @("Advanced usage example")
202     @safe unittest
203     {
204         import exp = expected;
205 
206         // define our Expected type using Exception as Error values
207         // and Throw hook, which throws when empty value or error is accessed
208         template Expected(T)
209         {
210             alias Expected = exp.Expected!(T, Exception, Throw);
211         }
212 
213         // create wrappers for simplified usage of our Expected
214         auto ok(T)(T val) { return exp.ok!(Exception, Throw)(val); }
215         auto err(T)(Exception err) { return exp.err!(T, Throw)(err); }
216 
217         // use it as normal
218         assert(ok(42) == 42);
219         assert(err!int(new Exception("foo")).orElse(0) == 0);
220         assertThrown(ok(42).error);
221         assertThrown(err!int(new Exception("bar")).value);
222     }
223 }
224 
225 version (unittest) {
226     import std.algorithm : reverse;
227     import std.exception : assertThrown, collectExceptionMsg;
228 }
229 
230 /++
231     `Expected!(T, E)` is a type that represents either success or failure.
232 
233     Type `T` is used for success value.
234     If `T` is `void`, then $(LREF Expected) can only hold error value and is considered a success when there is no error value.
235 
236     Type `E` is used for error value.
237     The default type for the error value is `string`.
238 
239     Default behavior of $(LREF Expected) can be modified by the `Hook` template parameter.
240 
241     Params:
242         T    = represents type of the expected value
243         E    = represents type of the error value.
244         Hook = defines the $(LREF Expected) type behavior
245 +/
246 struct Expected(T, E = string, Hook = Abort)
247     if (!is(E == void) && (isVoidValueEnabled!Hook || !is(T == void)))
248 {
249     import core.lifetime : forward;
250     import std.meta : AliasSeq, Filter, NoDuplicates;
251     import std.traits: isAssignable, isCopyable, hasIndirections, Unqual;
252 
253     private template noVoid(T) { enum noVoid = !is(T == void); } // Erase removes qualifiers
254     private alias Types = NoDuplicates!(Filter!(noVoid, AliasSeq!(T, E)));
255 
256     static foreach (i, CT; Types)
257     {
258         /++
259             Constructs an $(LREF Expected) with value or error based on the tye of the provided.
260 
261             In case when `T == E`, it constructs $(LREF Expected) with value.
262 
263             In case when `T == void`, it constructs $(LREF Expected) with error value.
264 
265             Default constructor (if enabled) initializes $(LREF Expected) to `T.init` value.
266             If `T == void`, it initializes $(LREF Expected) with no error.
267         +/
268         this()(auto ref CT val)
269         {
270             static if (isRefCountedPayloadEnabled!Hook)
271             {
272                 initialize(forward!val);
273             }
274             else
275             {
276                 storage = Payload(forward!val);
277             }
278             setState!CT();
279 
280             static if (hasOnValueSet!(Hook, CT)) { if (state == State.value) __traits(getMember, Hook, "onValueSet")(getValue()); }
281             static if (hasOnErrorSet!(Hook, CT)) { if (state == State.error) __traits(getMember, Hook, "onErrorSet")(getError()); }
282         }
283 
284         // static if (isCopyable!CT)
285         // {
286         //     / ditto
287         //     this()(auto ref const(CT) val) const
288         //     {
289         //         storage = const(Payload)(val);
290         //         setState!CT();
291 
292         //         static if (hasOnValueSet!(Hook, CT)) { if (state == State.value) __traits(getMember, Hook, "onValueSet")(val); }
293         //         static if (hasOnErrorSet!(Hook, CT)) { if (state == State.error) __traits(getMember, Hook, "onErrorSet")(val); }
294         //     }
295 
296         //     /// ditto
297         //     this()(auto ref immutable(CT) val) immutable
298         //     {
299         //         storage = immutable(Payload)(val);
300         //         setState!CT();
301 
302         //         static if (hasOnValueSet!(Hook, CT)) { if (state == State.value) __traits(getMember, Hook, "onValueSet")(val); }
303         //         static if (hasOnErrorSet!(Hook, CT)) { if (state == State.error) __traits(getMember, Hook, "onErrorSet")(val); }
304         //     }
305         // }
306         // else
307         // {
308         //     @disable this(const(CT) val) const;
309         //     @disable this(immutable(CT) val) immutable;
310         // }
311     }
312 
313     // generate constructor with flag to determine type of value
314     static if (Types.length == 1 && !is(T == void))
315     {
316         /++ Constructs an $(LREF Expected) with value or error based on the provided flag.
317             This constructor is available only for cases when value and error has the same type,
318             so we can still construct $(LREF Expected) with value or error.
319 
320             Params:
321                 val     = Value to set as value or error
322                 success = If `true`, $(LREF Expected) with value is created, $(LREF Expected) with error otherwise.
323         +/
324         this()(auto ref E val, bool success)
325         {
326             static if (isRefCountedPayloadEnabled!Hook)
327             {
328                 initialize(forward!val);
329             }
330             else
331             {
332                 storage = Payload(forward!val);
333             }
334             setState!E(success ? State.value : State.error);
335 
336             static if (hasOnValueSet!(Hook, E)) { if (state == State.value) __traits(getMember, Hook, "onValueSet")(getValue()); }
337             static if (hasOnErrorSet!(Hook, E)) { if (state == State.error) __traits(getMember, Hook, "onErrorSet")(getError()); }
338         }
339 
340         // static if (isCopyable!E)
341         // {
342         //     /// ditto
343         //     this()(auto ref const(E) val, bool success) const
344         //     {
345         //         storage = const(Payload)(val);
346         //         setState!E(success ? State.value : State.error);
347 
348         //         static if (hasOnValueSet!(Hook, E)) { if (state == State.value) __traits(getMember, Hook, "onValueSet")(val); }
349         //         static if (hasOnErrorSet!(Hook, E)) { if (state == State.error) __traits(getMember, Hook, "onErrorSet")(val); }
350         //     }
351 
352         //     /// ditto
353         //     this()(auto ref immutable(E) val, bool success) immutable
354         //     {
355         //         storage = immutable(Payload)(val);
356         //         setState!E(success ? State.value : State.error);
357 
358         //         static if (hasOnValueSet!(Hook, E)) { if (state == State.value) __traits(getMember, Hook, "onValueSet")(val); }
359         //         static if (hasOnErrorSet!(Hook, E)) { if (state == State.error) __traits(getMember, Hook, "onErrorSet")(val); }
360         //     }
361         // }
362         // else
363         // {
364         //     @disable this(const(E) val, bool success) const;
365         //     @disable this(immutable(E) val, bool success) immutable;
366         // }
367     }
368 
369     static if (!is(T == void) && !isDefaultConstructorEnabled!Hook) @disable this();
370 
371     static if (!isCopyConstructorEnabled!Hook) @disable this(this);
372 
373     static if (isChecked!Hook || isRefCountedPayloadEnabled!Hook)
374     {
375         ~this()
376         {
377             static void onUnchecked()
378             {
379                 static if (hasOnUnchecked!Hook) __traits(getMember, Hook, "onUnchecked")();
380                 else assert(0, "unchecked result");
381             }
382 
383             static if (isRefCountedPayloadEnabled!Hook)
384             {
385                 if (!storage) return;
386                 assert(storage.count > 0);
387 
388                 if (--storage.count) return;
389 
390                 // Done, deallocate
391                 static if (isChecked!Hook) bool ch = checked;
392                 destroy(storage.payload);
393                 static if (enableGCScan) () @trusted { pureGcRemoveRange(&storage.payload); } ();
394 
395                 () @trusted
396                 {
397                     pureFree(storage);
398                     storage = null;
399                 }();
400 
401                 static if (isChecked!Hook) { if (!ch) onUnchecked(); }
402             }
403             else static if (isChecked!Hook) { if (!checked) onUnchecked(); }
404         }
405     }
406 
407     static if (isDefaultConstructorEnabled!Hook)
408     {
409         static foreach (i, CT; Types)
410         {
411             static if (isAssignable!CT)
412             {
413                 /++ Assigns a value or error to an $(LREF Expected).
414 
415                     Note: This is only allowed when default constructor is also enabled.
416                 +/
417                 void opAssign()(auto ref CT rhs)
418                 {
419                     setState!CT(); // check state asserts before change
420                     auto s = state;
421                     static if (isRefCountedPayloadEnabled!Hook)
422                     {
423                         if (!storage) initialize(forward!rhs);
424                         else storage.payload = Payload(forward!rhs);
425                     }
426                     else storage = Payload(forward!rhs);
427                     setState!(CT)(s); // set previous state
428 
429                     static if (hasOnValueSet!(Hook, CT)) { if (state == State.value) __traits(getMember, Hook, "onValueSet")(getValue()); }
430                     static if (hasOnErrorSet!(Hook, CT)) { if (state == State.error) __traits(getMember, Hook, "onErrorSet")(getError()); }
431                 }
432             }
433         }
434     }
435 
436     //damn these are ugly :(
437     static if (!isChecked!Hook) {
438         /++ Implicit conversion to bool.
439             Returns: `true` if there is no error set, `false` otherwise.
440         +/
441         bool opCast(T)() const if (is(T == bool)) { return !this.hasError; }
442     } else {
443         /// ditto
444         bool opCast(T)() if (is(T == bool)) { return !this.hasError; }
445     }
446 
447     static if (!is(T == void))
448     {
449         static if (!isChecked!Hook) {
450             /++ Checks whether this $(LREF Expected) object contains a specific expected value.
451 
452                 * `opEquals` for the value is available only when `T != void`.
453                 * `opEquals` for the error isn't available, use equality test for $(LREF Expected) in that case.
454             +/
455             bool opEquals()(const auto ref T rhs) const
456             {
457                 return hasValue && value == rhs;
458             }
459         } else {
460             /// ditto
461             bool opEquals()(auto ref T rhs) { return hasValue && value == forward!rhs; }
462         }
463     }
464 
465     static if (!isChecked!Hook) {
466         /// Checks whether this $(LREF Expected) object and `rhs` contain the same expected value or error value.
467         bool opEquals()(const auto ref Expected!(T, E, Hook) rhs) const
468         {
469             if (state != rhs.state) return false;
470             static if (!is(T == void)) { if (hasValue) return value == rhs.value; }
471             return error == rhs.error;
472         }
473     } else {
474         /// ditto
475         bool opEquals()(auto ref Expected!(T, E, Hook) rhs)
476         {
477             if (state != rhs.state) return false;
478             static if (!is(T == void)) { if (hasValue) return value == forwardValue!rhs; }
479             return error == forwardError!rhs;
480         }
481     }
482 
483     static if (!isChecked!Hook) {
484         /++ Calculates the hash value of the $(LREF Expected) in a way that iff it has a value,
485             it returns hash of the value.
486             Hash is computed using internal state and storage of the $(LREF Expected) otherwise.
487         +/
488         size_t toHash()() const nothrow
489         {
490             static if (!is(T == void)) { if (hasValue) return value.hashOf; }
491             return storage.hashOf(state);
492         }
493     } else {
494         /// ditto
495         size_t toHash()() nothrow
496         {
497             static if (!is(T == void)) { if (hasValue) return value.hashOf; }
498             return storage.hashOf(state);
499         }
500     }
501 
502     static if (!is(T == void))
503     {
504         static if (!isChecked!Hook) {
505             /// Checks if $(LREF Expected) has value
506             @property bool hasValue()() const { return state == State.value; }
507         }
508         else {
509             /// ditto
510             @property bool hasValue()()
511             {
512                 checked = true;
513                 return state == State.value;
514             }
515         }
516 
517         static if (!isChecked!Hook) {
518             /++
519                 Returns the expected value if there is one.
520 
521                 With default `Abort` hook, it asserts when there is no value.
522                 It calls hook's `onAccessEmptyValue` otherwise.
523 
524                 It returns `T.init` when hook doesn't provide `onAccessEmptyValue`.
525             +/
526             @property auto ref inout(T) value() inout
527             {
528                 if (state != State.value)
529                 {
530                     static if (hasOnAccessEmptyValue!(Hook, E))
531                         __traits(getMember, Hook, "onAccessEmptyValue")(state == State.error ? getError() : E.init);
532                     else return T.init;
533                 }
534                 return getValue();
535             }
536         } else {
537             @property auto ref T value()
538             {
539                 checked = true;
540 
541                 if (state != State.value)
542                 {
543                     static if (hasOnAccessEmptyValue!(Hook, E))
544                         __traits(getMember, Hook, "onAccessEmptyValue")(state == State.error ? getError() : E.init);
545                     else return T.init;
546                 }
547                 return getValue();
548             }
549         }
550     }
551 
552     static if (!isChecked!Hook) {
553         /// Checks if $(LREF Expected) has error
554         @property bool hasError()() const { return state == State.error; }
555     } else {
556         /// ditto
557         @property bool hasError()()
558         {
559             checked = true;
560             return state == State.error;
561         }
562     }
563 
564     static if (!isChecked!Hook) {
565         /++
566             Returns the error value. May only be called when `hasValue` returns `false`.
567 
568             If there is no error value, it calls hook's `onAccessEmptyError`.
569 
570             It returns `E.init` when hook doesn't provide `onAccessEmptyError`.
571         +/
572         @property auto ref inout(E) error() inout
573         {
574             if (state != State.error)
575             {
576                 static if (hasOnAccessEmptyError!Hook) __traits(getMember, Hook, "onAccessEmptyError")();
577                 else return E.init;
578             }
579             return getError;
580         }
581     } else {
582         @property auto ref E error()
583         {
584             checked = true;
585 
586             if (state != State.error)
587             {
588                 static if (hasOnAccessEmptyError!Hook) __traits(getMember, Hook, "onAccessEmptyError")();
589                 else return E.init;
590             }
591             return getError;
592         }
593     }
594 
595     // range interface
596     static if (!is(T == void))
597     {
598         static if (!isChecked!Hook) {
599             /++ Range interface defined by `empty`, `front`, `popFront`.
600                 Yields one value if $(LREF Expected) has value.
601 
602                 If `T == void`, range interface isn't defined.
603             +/
604             @property bool empty() const { return state != State.value; }
605 
606             /// ditto
607             @property auto ref inout(T) front() inout { return value; }
608         } else {
609             @property bool empty() { checked = true; return state != State.value; }
610 
611             /// ditto
612             @property auto ref T front() { return value; }
613         }
614 
615         /// ditto
616         void popFront() { state = State.empty; }
617     }
618 
619     private:
620 
621     //FIXME: can probably be union instead, but that doesn't work well with destructors and copy constructors/postblits
622     //and need to be handled manually - so for now we use a safer variant
623     struct Payload
624     {
625         Types values;
626 
627         // generate payload constructors
628         static foreach (i, CT; Types)
629         {
630             this()(auto ref CT val)
631             {
632                 __traits(getMember, Payload, "values")[i] = forward!val;
633             }
634 
635             // static if (isCopyable!CT)
636             // {
637             //     this()(auto ref const(CT) val) const { __traits(getMember, Payload, "values")[i] = val; }
638             //     this()(auto ref immutable(CT) val) immutable { __traits(getMember, Payload, "values")[i] = val; }
639             // }
640             // else
641             // {
642             //     @disable this(const(CT) val) const;
643             //     @disable this(immutable(CT) val) immutable;
644             // }
645         }
646     }
647 
648     static if (isRefCountedPayloadEnabled!Hook)
649     {
650         version (D_BetterC) enum enableGCScan = false;
651         else enum enableGCScan = hasIndirections!Payload;
652 
653         // purify memory management functions - see https://github.com/dlang/phobos/pull/4832
654         extern(C) pure nothrow @nogc static
655         {
656             pragma(mangle, "malloc") void* pureMalloc(size_t);
657             pragma(mangle, "free") void pureFree( void *ptr );
658             static if (enableGCScan)
659             {
660                 pragma(mangle, "calloc") void* pureCalloc(size_t nmemb, size_t size);
661                 pragma(mangle, "gc_addRange") void pureGcAddRange( in void* p, size_t sz, const TypeInfo ti = null );
662                 pragma(mangle, "gc_removeRange") void pureGcRemoveRange( in void* p );
663             }
664         }
665 
666         struct Impl
667         {
668             Payload payload;
669             State state;
670             size_t count;
671             static if (isChecked!Hook) bool checked;
672         }
673 
674         void initialize(A...)(auto ref A args)
675         {
676             import std.conv : emplace;
677 
678             allocateStore();
679             emplace(&storage.payload, forward!args);
680             storage.count = 1;
681             storage.state = State.empty;
682             static if (isChecked!Hook) storage.checked = false;
683         }
684 
685         void allocateStore() nothrow pure @trusted
686         {
687             assert(!storage);
688             static if (enableGCScan)
689             {
690                 storage = cast(Impl*) pureCalloc(1, Impl.sizeof);
691                 if (!storage) assert(0, "Memory allocation failed");
692                 pureGcAddRange(&storage.payload, Payload.sizeof);
693             }
694             else
695             {
696                 storage = cast(Impl*) pureMalloc(Impl.sizeof);
697                 if (!storage) assert(0, "Memory allocation failed");
698             }
699         }
700 
701         Impl* storage;
702 
703         @property nothrow @safe pure @nogc
704         size_t refCount() const { return storage !is null ? storage.count : 0; }
705 
706         @property nothrow @safe pure @nogc
707         State state() const { return storage !is null ? storage.state : State.empty; }
708 
709         @property nothrow @safe pure @nogc
710         void state(State state) { assert(storage); storage.state = state; }
711 
712         static if (isChecked!Hook)
713         {
714             @property nothrow @safe pure @nogc
715             bool checked() const { assert(storage); return storage.checked; }
716 
717             @property nothrow @safe pure @nogc
718             void checked(bool ch) { assert(storage); storage.checked = ch; }
719         }
720 
721         ref inout(E) getError()() inout
722         {
723             assert(storage);
724             static if (__VERSION__ < 2078) // workaround - see: https://issues.dlang.org/show_bug.cgi?id=15094
725             {
726                 auto p = &storage.payload;
727                 static if (Types.length == 1) return __traits(getMember, p, "values")[0];
728                 else return __traits(getMember, p, "values")[1];
729             }
730             else
731             {
732                 static if (Types.length == 1) return __traits(getMember, storage.payload, "values")[0];
733                 else return __traits(getMember, storage.payload, "values")[1];
734             }
735         }
736 
737         static if (!is(T == void))
738         {
739             ref inout(T) getValue()() inout
740             {
741                 assert(storage);
742                 static if (__VERSION__ < 2078) // workaround - see: https://issues.dlang.org/show_bug.cgi?id=15094
743                 {
744                     auto p = &storage.payload;
745                     return __traits(getMember, p, "values")[0];
746                 }
747                 else return __traits(getMember, storage.payload, "values")[0];
748             }
749         }
750 
751         this(this) @safe pure nothrow @nogc
752         {
753             if (!storage) return;
754             ++storage.count;
755         }
756     }
757     else
758     {
759         Payload storage;
760         State state = State.empty;
761         static if (isChecked!Hook) bool checked = false;
762 
763         ref inout(E) getError()() inout
764         {
765             static if (Types.length == 1) return __traits(getMember, storage, "values")[0];
766             else return __traits(getMember, storage, "values")[1];
767         }
768 
769         static if (!is(T == void))
770         {
771             ref inout(T) getValue()() inout
772             {
773                 return __traits(getMember, storage, "values")[0];
774             }
775         }
776     }
777 
778     enum State : ubyte { empty, value, error }
779 
780     void setState(MT)(State known = State.empty)
781     {
782         State s;
783         if (known != State.empty) s = known;
784         else
785         {
786             static if (Types.length == 1 && is(T == void)) s = State.error;
787             else static if (Types.length == 1 || is(MT == T)) s = State.value;
788             else s = State.error;
789         }
790 
791         //TODO: change with Hook?
792         assert(state == State.empty || state == s, "Can't change meaning of already set Expected type");
793         state = s;
794     }
795 }
796 
797 /++ Template to determine if hook enables or disables copy constructor.
798 
799     It is enabled by default.
800 
801     See $(LREF hasOnUnchecked) handler, which can be used in combination with disabled
802     copy constructor to enforce that the result is checked.
803 
804     $(WARNING If copy constructor is disabled, it severely limits function chaining
805     as $(LREF Expected) needs to be passed as rvalue in that case.)
806 +/
807 template isCopyConstructorEnabled(Hook)
808 {
809     static if (__traits(hasMember, Hook, "enableCopyConstructor"))
810     {
811         static assert(
812             is(typeof(__traits(getMember, Hook, "enableCopyConstructor")) : bool),
813             "Hook's enableCopyConstructor is expected to be of type bool"
814         );
815         enum isCopyConstructorEnabled = __traits(getMember, Hook, "enableCopyConstructor");
816     }
817     else enum isCopyConstructorEnabled = true;
818 }
819 
820 ///
821 @("isCopyConstructorEnabled")
822 @safe unittest
823 {
824     struct Foo {}
825     struct Bar { static immutable bool enableCopyConstructor = false; }
826     static assert(isCopyConstructorEnabled!Foo);
827     static assert(!isCopyConstructorEnabled!Bar);
828 }
829 
830 /++ Template to determine if hook defines that the $(LREF Expected) storage should
831     use refcounted state storage.
832 
833     If this is enabled, payload is mallocated on the heap and dealocated with the
834     destruction of last $(Expected) instance.
835 
836     See $(LREF hasOnUnchecked) handler, which can be used in combination with refcounted
837     payload to enforce that the result is checked.
838 +/
839 template isRefCountedPayloadEnabled(Hook)
840 {
841     static if (__traits(hasMember, Hook, "enableRefCountedPayload"))
842     {
843         static assert(
844             is(typeof(__traits(getMember, Hook, "enableRefCountedPayload")) : bool),
845             "Hook's enableCopyConstructor is expected to be of type bool"
846         );
847         enum isRefCountedPayloadEnabled = __traits(getMember, Hook, "enableRefCountedPayload");
848         static assert (
849             !isRefCountedPayloadEnabled || isCopyConstructorEnabled!Hook,
850             "Refcounted payload wouldn't work without copy constructor enabled"
851         );
852     }
853     else enum isRefCountedPayloadEnabled = false;
854 }
855 
856 ///
857 @("isRefCountedPayloadEnabled")
858 @safe unittest
859 {
860     struct Foo {}
861     struct Bar {
862         static immutable bool enableCopyConstructor = false;
863         static immutable bool enableRefCountedPayload = true;
864     }
865     struct Hook { static immutable bool enableRefCountedPayload = true; }
866     static assert(!isRefCountedPayloadEnabled!Foo);
867     static assert(!__traits(compiles, isRefCountedPayloadEnabled!Bar));
868     static assert(isRefCountedPayloadEnabled!Hook);
869 }
870 
871 // just a helper to determine check behavior
872 private template isChecked(Hook)
873 {
874     enum isChecked = !isCopyConstructorEnabled!Hook || isRefCountedPayloadEnabled!Hook;
875 }
876 
877 /// Template to determine if provided Hook enables default constructor for $(LREF Expected)
878 template isDefaultConstructorEnabled(Hook)
879 {
880     static if (__traits(hasMember, Hook, "enableDefaultConstructor"))
881     {
882         static assert(
883             is(typeof(__traits(getMember, Hook, "enableDefaultConstructor")) : bool),
884             "Hook's enableDefaultConstructor is expected to be of type bool"
885         );
886         enum isDefaultConstructorEnabled = __traits(getMember, Hook, "enableDefaultConstructor");
887     }
888     else enum isDefaultConstructorEnabled = false;
889 }
890 
891 ///
892 @("isDefaultConstructorEnabled")
893 @safe unittest
894 {
895     struct Foo {}
896     struct Bar { static immutable bool enableDefaultConstructor = true; }
897     static assert(!isDefaultConstructorEnabled!Foo);
898     static assert(isDefaultConstructorEnabled!Bar);
899 }
900 
901 /// Template to determine if provided Hook enables void values for $(LREF Expected)
902 template isVoidValueEnabled(Hook)
903 {
904     static if (__traits(hasMember, Hook, "enableVoidValue"))
905     {
906         static assert(
907             is(typeof(__traits(getMember, Hook, "enableVoidValue")) : bool),
908             "Hook's enableVoidValue is expected to be of type bool"
909         );
910         enum isVoidValueEnabled = __traits(getMember, Hook, "isVoidValueEnabled");
911     }
912     else enum isVoidValueEnabled = true;
913 }
914 
915 ///
916 @("isVoidValueEnabled")
917 @safe unittest
918 {
919     struct Hook { static immutable bool enableVoidValue = false; }
920     assert(!ok().hasError); // void values are enabled by default
921     static assert(!__traits(compiles, ok!(string, Hook)())); // won't compile
922 }
923 
924 /// Template to determine if hook provides function called on empty value.
925 template hasOnAccessEmptyValue(Hook, E)
926 {
927     static if (__traits(hasMember, Hook, "onAccessEmptyValue"))
928     {
929         static assert(
930             is(typeof(__traits(getMember, Hook, "onAccessEmptyValue")(E.init))),
931             "Hook's onAccessEmptyValue is expected to be callable with error value type"
932         );
933         enum hasOnAccessEmptyValue = true;
934     }
935     else enum hasOnAccessEmptyValue = false;
936 }
937 
938 ///
939 @("hasOnAccessEmptyValue")
940 @safe unittest
941 {
942     struct Foo {}
943     struct Bar { static void onAccessEmptyValue(E)(E err) {} }
944     static assert(!hasOnAccessEmptyValue!(Foo, string));
945     static assert(hasOnAccessEmptyValue!(Bar, string));
946 }
947 
948 /++ Template to determine if hook provides function called on empty error.
949 +/
950 template hasOnAccessEmptyError(Hook)
951 {
952     static if (__traits(hasMember, Hook, "onAccessEmptyError"))
953     {
954         static assert(
955             is(typeof(__traits(getMember, Hook, "onAccessEmptyError")())),
956             "Hook's onAccessEmptyValue is expected to be callable with no arguments"
957         );
958         enum hasOnAccessEmptyError = true;
959     }
960     else enum hasOnAccessEmptyError = false;
961 }
962 
963 ///
964 @("hasOnAccessEmptyError")
965 @safe unittest
966 {
967     struct Foo {}
968     struct Bar { static void onAccessEmptyError() {} }
969     static assert(!hasOnAccessEmptyError!Foo);
970     static assert(hasOnAccessEmptyError!Bar);
971 }
972 
973 /++ Template to determine if hook provides custom handler for case
974     when the $(LREF Expected) result is not checked.
975 
976     For this to work it currently also has to pass $(LREF isCopyConstructorEnabled)
977     as this is implemented by simple flag controled on $(LREF Expected) destructor.
978 +/
979 template hasOnUnchecked(Hook)
980 {
981     static if (__traits(hasMember, Hook, "onUnchecked"))
982     {
983         static assert(
984             is(typeof(__traits(getMember, Hook, "onUnchecked")())),
985             "Hook's onUnchecked is expected to be callable with no arguments"
986         );
987         static assert(
988             !isCopyConstructorEnabled!Hook || isRefCountedPayloadEnabled!Hook,
989             "For unchecked check to work, it is needed to also have disabled copy constructor or enabled reference counted payload"
990         );
991         enum hasOnUnchecked = true;
992     }
993     else enum hasOnUnchecked = false;
994 }
995 
996 version (D_Exceptions)
997 {
998     ///
999     @("hasOnUnchecked")
1000     @safe unittest
1001     {
1002         struct Foo {}
1003         struct Bar { static void onUnchecked() { } }
1004         struct Hook {
1005             static immutable bool enableCopyConstructor = false;
1006             static void onUnchecked() @safe { throw new Exception("result unchecked"); }
1007         }
1008 
1009         // template checks
1010         static assert(!hasOnUnchecked!Foo);
1011         static assert(!__traits(compiles, hasOnUnchecked!Bar)); // missing disabled constructor
1012         static assert(hasOnUnchecked!Hook);
1013 
1014         // copy constructor
1015         auto exp = ok!(string, Hook)(42);
1016         auto exp2 = err!(int, Hook)("foo");
1017         static assert(!__traits(compiles, exp.andThen(ok!(string, Hook)(42)))); // disabled cc
1018         assert(exp.andThen(exp2).error == "foo"); // passed by ref so no this(this) called
1019 
1020         // check for checked result
1021         assertThrown({ ok!(string, Hook)(42); }());
1022         assertThrown({ err!(void, Hook)("foo"); }());
1023     }
1024 }
1025 
1026 /++ Template to determine if hook provides function called when value is set.
1027 +/
1028 template hasOnValueSet(Hook, T)
1029 {
1030     static if (__traits(hasMember, Hook, "onValueSet"))
1031     {
1032         static assert(
1033             is(typeof(__traits(getMember, Hook, "onValueSet")(T.init))),
1034             "Hook's onValueSet is expected to be callable with value argument"
1035         );
1036         enum hasOnValueSet = true;
1037     }
1038     else enum hasOnValueSet = false;
1039 }
1040 
1041 ///
1042 @("hasOnValueSet")
1043 @safe unittest
1044 {
1045     struct Hook {
1046         static int lastValue;
1047         static void onValueSet(T)(auto ref T val) { lastValue = val; }
1048     }
1049 
1050     static assert(hasOnValueSet!(Hook, int));
1051     auto res = ok!(string, Hook)(42);
1052     assert(res.hasValue);
1053     assert(Hook.lastValue == 42);
1054 }
1055 
1056 /++ Template to determine if hook provides function called when error is set.
1057 +/
1058 template hasOnErrorSet(Hook, T)
1059 {
1060     static if (__traits(hasMember, Hook, "onErrorSet"))
1061     {
1062         static assert(
1063             is(typeof(__traits(getMember, Hook, "onErrorSet")(T.init))),
1064             "Hook's onErrorSet is expected to be callable with error argument"
1065         );
1066         enum hasOnErrorSet = true;
1067     }
1068     else enum hasOnErrorSet = false;
1069 }
1070 
1071 ///
1072 @("hasOnErrorSet")
1073 @safe unittest
1074 {
1075     struct Hook {
1076         static string lastErr;
1077         static void onErrorSet(E)(auto ref E err) { lastErr = err; }
1078     }
1079 
1080     static assert(hasOnErrorSet!(Hook, string));
1081     auto res = err!(int, Hook)("foo");
1082     assert(res.hasError);
1083     assert(Hook.lastErr == "foo");
1084 }
1085 
1086 /++ Default hook implementation for $(LREF Expected)
1087 +/
1088 struct Abort
1089 {
1090 static:
1091     /++ Default constructor for $(LREF Expected) is disabled.
1092         Same with the `opAssign`, so $(LREF Expected) can be only constructed
1093         once and not modified afterwards.
1094     +/
1095     immutable bool enableDefaultConstructor = false;
1096 
1097     /// Handler for case when empty value is accessed.
1098     void onAccessEmptyValue(E)(E err) nothrow @nogc
1099     {
1100         assert(0, "Value not set");
1101     }
1102 
1103     /// Handler for case when empty error is accessed.
1104     void onAccessEmptyError() nothrow @nogc @safe
1105     {
1106         assert(0, "Error not set");
1107     }
1108 }
1109 
1110 ///
1111 @("Abort")
1112 @system unittest
1113 {
1114     static assert(!isDefaultConstructorEnabled!Abort);
1115     static assert(hasOnAccessEmptyValue!(Abort, string));
1116     static assert(hasOnAccessEmptyValue!(Abort, int));
1117     static assert(hasOnAccessEmptyError!Abort);
1118 
1119     version (D_Exceptions)
1120     {
1121         assertThrown!Throwable(ok(42).error);
1122         assertThrown!Throwable(err!int("foo").value);
1123     }
1124 }
1125 
1126 version (D_Exceptions)
1127 {
1128     /++ Hook implementation that throws exceptions instead of default assert behavior.
1129     +/
1130     struct Throw
1131     {
1132     static:
1133 
1134         /++ Default constructor for $(LREF Expected) is disabled.
1135             Same with the `opAssign`, so $(LREF Expected) can be only constructed
1136             once and not modified afterwards.
1137         +/
1138         immutable bool enableDefaultConstructor = false;
1139 
1140         /++ Handler for case when empty value is accessed.
1141 
1142             Throws:
1143                 If `E` inherits from `Throwable`, the error value is thrown.
1144                 Otherwise, an [Unexpected] instance containing the error value is
1145                 thrown.
1146         +/
1147         void onAccessEmptyValue(E)(E err)
1148         {
1149             import std.traits : Unqual;
1150             static if(is(Unqual!E : Throwable)) throw err;
1151             else throw new Unexpected!E(err);
1152         }
1153 
1154         /// Handler for case when empty error is accessed.
1155         void onAccessEmptyError() @safe
1156         {
1157             throw new Unexpected!string("Can't access error on expected value");
1158         }
1159     }
1160 
1161     ///
1162     @("Throw")
1163     @safe unittest
1164     {
1165         static assert(!isDefaultConstructorEnabled!Throw);
1166         static assert(hasOnAccessEmptyValue!(Throw, string));
1167         static assert(hasOnAccessEmptyValue!(Throw, int));
1168         static assert(hasOnAccessEmptyError!Throw);
1169 
1170         assertThrown!(Unexpected!string)(ok!(string, Throw)(42).error);
1171         assertThrown!(Unexpected!string)(err!(int, Throw)("foo").value);
1172         assertThrown!(Unexpected!int)(err!(bool, Throw)(-1).value);
1173     }
1174 
1175     /++ Hook implementation that behaves like a thrown exception.
1176         It throws $(D Exception) right when the $(LREF Expected) with error is initialized.
1177 
1178         With this, one can easily change the code behavior between `Expected` idiom or plain `Exception`s.
1179     +/
1180     struct AsException
1181     {
1182     static:
1183 
1184         /++ Default constructor for $(LREF Expected) is disabled.
1185             Same with the `opAssign`, so $(LREF Expected) can be only constructed
1186             once and not modified afterwards.
1187         +/
1188         immutable bool enableDefaultConstructor = false;
1189 
1190         /++ Handler for case when empty error is accessed.
1191         +/
1192         void onErrorSet(E)(auto ref E err)
1193         {
1194             import core.lifetime : forward;
1195             static if (is(E : Throwable)) throw E;
1196             else throw new Unexpected!E(forward!err);
1197         }
1198     }
1199 
1200     ///
1201     @("AsException")
1202     @safe unittest
1203     {
1204         static assert(!isDefaultConstructorEnabled!AsException);
1205         static assert(hasOnErrorSet!(AsException, string));
1206 
1207         auto div(int a, int b) {
1208             if (b != 0) return ok!(string, AsException)(a / b);
1209             return err!(int, AsException)("oops");
1210         }
1211 
1212         assert(div(10, 2) == 5);
1213         assert(collectExceptionMsg!(Unexpected!string)(div(1, 0)) == "oops");
1214     }
1215 }
1216 
1217 /++ Hook implementation that behaves same as $(LREF Abort) hook, but uses refcounted payload
1218     instead, which also enables us to check, if the result was properly checked before it is
1219     discarded.
1220 +/
1221 struct RCAbort
1222 {
1223 static:
1224     /++ Default constructor for $(LREF Expected) is disabled.
1225         Same with the `opAssign`, so $(LREF Expected) can be only constructed
1226         once and not modified afterwards.
1227     +/
1228     immutable bool enableDefaultConstructor = false;
1229 
1230     /// Copy constructor is enabled so the reference counting makes sense
1231     immutable bool enableCopyConstructor = true;
1232 
1233     /// Enabled reference counted payload
1234     immutable bool enableRefCountedPayload = true;
1235 
1236     void onUnchecked() pure nothrow @nogc @safe { assert(0, "result unchecked"); }
1237 }
1238 
1239 ///
1240 @("RCAbort")
1241 @safe unittest
1242 {
1243     // behavior checks
1244     static assert(!isDefaultConstructorEnabled!RCAbort);
1245     static assert(isCopyConstructorEnabled!RCAbort);
1246     static assert(isRefCountedPayloadEnabled!RCAbort);
1247 
1248     // basics
1249     assert(ok!(string, RCAbort)(42) == 42);
1250     assert(err!(int, RCAbort)("foo").error == "foo");
1251 
1252     // checked
1253     {
1254         auto res = ok!(string, RCAbort)(42);
1255         assert(!res.checked);
1256         assert(res);
1257         assert(res.checked);
1258     }
1259 
1260     // unchecked - throws assert
1261     version (D_Exceptions) () @trusted { assertThrown!Throwable({ ok!(string, RCAbort)(42); }()); }();
1262 
1263     {
1264         auto res = ok!(string, RCAbort)(42);
1265         {
1266             auto res2 = res;
1267             assert(!res.checked);
1268             assert(res.refCount == 2);
1269             assert(res2.refCount == 2);
1270         }
1271         assert(res.refCount == 1);
1272         assert(res.hasValue);
1273     }
1274 
1275     // chaining
1276     assert(err!(int, RCAbort)("foo").orElse!(() => ok!(string, RCAbort)(42)) == 42);
1277     assert(ok!(string, RCAbort)(42).andThen!(() => err!(int, RCAbort)("foo")).error == "foo");
1278     version (D_Exceptions)
1279     {
1280         () @trusted
1281         {
1282             assertThrown!Throwable(err!(int, RCAbort)("foo").orElse!(() => ok!(string, RCAbort)(42)));
1283             assertThrown!Throwable(ok!(string, RCAbort)(42).andThen!(() => err!(int, RCAbort)("foo")));
1284         }();
1285     }
1286 }
1287 
1288 version (D_Exceptions)
1289 {
1290     /++ An exception that represents an error value.
1291 
1292         This is used by $(LREF Throw) hook when undefined value or error is
1293         accessed on $(LREF Expected)
1294     +/
1295     class Unexpected(T) : Exception
1296     {
1297         // remove possible inout qualifier
1298         static if (is(T U == inout U)) alias ET = U;
1299         else alias ET = T;
1300 
1301         ET error; /// error value
1302 
1303         /// Constructs an `Unexpected` exception from an error value.
1304         pure @safe @nogc nothrow
1305         this()(auto ref T value, string file = __FILE__, size_t line = __LINE__)
1306         {
1307             import core.lifetime : forward;
1308             import std.traits : isAssignable;
1309             static if (isAssignable!(string, T)) super(forward!value, file, line);
1310             else super("Unexpected error", file, line);
1311 
1312             this.error = error;
1313         }
1314     }
1315 }
1316 
1317 /++
1318     Creates an $(LREF Expected) object from an expected value, with type inference.
1319 +/
1320 Expected!(T, E, Hook) ok(E = string, Hook = Abort, T)(auto ref T value)
1321 {
1322     import core.lifetime : forward;
1323     return Expected!(T, E, Hook)(forward!value);
1324 }
1325 
1326 /// ditto
1327 Expected!(void, E, Hook) ok(E = string, Hook = Abort)()
1328 {
1329     return Expected!(void, E, Hook)();
1330 }
1331 
1332 ///
1333 @("Expected from value")
1334 @safe unittest
1335 {
1336     // void
1337     {
1338         auto res = ok();
1339         static assert(is(typeof(res) == Expected!(void, string)));
1340         assert(res);
1341     }
1342 
1343     // int
1344     {
1345         auto res = ok(42);
1346         static assert(is(typeof(res) == Expected!(int, string)));
1347         assert(res);
1348         assert(res.value == 42);
1349     }
1350 
1351     // string
1352     {
1353         auto res = ok("42");
1354         static assert(is(typeof(res) == Expected!(string, string)));
1355         assert(res);
1356         assert(res.value == "42");
1357     }
1358 
1359     // other error type
1360     {
1361         auto res = ok!bool(42);
1362         static assert(is(typeof(res) == Expected!(int, bool)));
1363         assert(res);
1364         assert(res.value == 42);
1365     }
1366 }
1367 
1368 /++ Constructs $(LREF Expected) from the result of the provided function.
1369 
1370     If the function is `nothrow`, it just returns it's result using $(LREF Expected).
1371 
1372     If not, then it consumes it's possible $(D Exception) using `try catch` block and
1373     constructs $(LREF Expected) in regards of the result.
1374 +/
1375 template consume(alias fun, Hook = Abort)
1376 {
1377     import core.lifetime : forward;
1378     auto consume(Args...)(auto ref Args args) if (is(typeof(fun(forward!args))))
1379     {
1380         import std.traits : hasFunctionAttributes;
1381 
1382         alias T = typeof(fun(forward!args));
1383         static if (is(hasFunctionAttributes!(fun, "nothrow"))) return ok!Exception(fun(forward!args));
1384         else
1385         {
1386             try return Expected!(T, Exception)(fun(forward!args));
1387             catch (Exception ex) return err!T(ex);
1388         }
1389     }
1390 }
1391 
1392 version (D_Exceptions)
1393 {
1394     ///
1395     @("consume from function call")
1396     @safe unittest
1397     {
1398         auto fn(int v) { if (v == 42) throw new Exception("don't panic"); return v; }
1399 
1400         assert(consume!fn(1) == 1);
1401         assert(consume!fn(42).error.msg == "don't panic");
1402     }
1403 }
1404 
1405 /++
1406     Creates an $(LREF Expected) object from an error value, with type inference.
1407 +/
1408 Expected!(T, E, Hook) err(T = void, Hook = Abort, E)(auto ref E err)
1409 {
1410     import core.lifetime : forward;
1411     static if (Expected!(T, E, Hook).Types.length == 1 && !is(T == void))
1412         return Expected!(T, E, Hook)(forward!err, false);
1413     else return Expected!(T, E, Hook)(forward!err);
1414 }
1415 
1416 ///
1417 @("Expected from error value")
1418 @safe unittest
1419 {
1420     // implicit void value type
1421     {
1422         auto res = err("foo");
1423         static assert(is(typeof(res) == Expected!(void, string)));
1424         assert(!res);
1425         assert(res.error == "foo");
1426     }
1427 
1428     // bool
1429     {
1430         auto res = err!int("42");
1431         static assert(is(typeof(res) == Expected!(int, string)));
1432         assert(!res);
1433         assert(res.error == "42");
1434     }
1435 
1436     // other error type
1437     {
1438         auto res = err!bool(42);
1439         static assert(is(typeof(res) == Expected!(bool, int)));
1440         assert(!res);
1441         assert(res.error == 42);
1442     }
1443 }
1444 
1445 /++ Unwraps a result, yielding the content of expected value.
1446     If there is none, or error value, it throws $(D assert(0)) with the provided message.
1447 
1448     Params:
1449         res     = $(LREF Expected) to check the result of
1450         msg     = message to use with assert
1451         handler = custom handler to be called on error
1452 +/
1453 auto ref T expect(EX : Expected!(T, E, H), T, E, H)(auto ref EX res, lazy string msg)
1454 {
1455     //TODO: hook for customization
1456 
1457     static if (!is(T == void)) {
1458         if (res.hasValue) return forwardValue!res;
1459     }
1460     else { if (!res.hasError) return; }
1461 
1462     version (D_BetterC) assert(0, msg);
1463     else
1464     {
1465         import std.format : format;
1466         if (res.hasError) assert(0, format!"%s: %s"(msg, res.error));
1467         else assert(0, format!"%s: empty"(msg));
1468     }
1469 }
1470 
1471 /// ditto
1472 auto ref T expect(alias handler, EX : Expected!(T, E, H), T, E, H)(auto ref EX res)
1473 {
1474     static if (!is(T == void)) { if (res.hasValue) return forwardValue!res; }
1475     else { if (!res.hasError) return; }
1476 
1477     static if (!is(typeof(handler(forwardError!res)) == noreturn) && !is(typeof(handler(forwardError!res)) == void))
1478         return handler(forwardError!res);
1479     else
1480     {
1481         handler(forwardError!res);
1482         static if (__VERSION__ < 2096) {
1483             static if (!is(T == void))
1484                 return T.init;
1485         } else {
1486             static if (!is(T == void) && !is(typeof(handler(forwardError!res)) == noreturn)) // avoid 'statement is not reachable'
1487                 return T.init;
1488         }
1489     }
1490 }
1491 
1492 ///
1493 @("expect")
1494 @safe unittest
1495 {
1496     assert(ok(42).expect("oops") == 42);
1497     ok().expect("oops"); // void value
1498 
1499     version (D_Exceptions)
1500     {
1501         () @trusted
1502         {
1503             assert(collectExceptionMsg!Throwable(Expected!int.init.expect("oops")) == "oops: empty");
1504             assert(collectExceptionMsg!Throwable(err!int("foo").expect("oops")) == "oops: foo");
1505         }();
1506     }
1507 
1508     assert(ok("foo").expect!(a => "bar") == "foo");
1509     assert(err!string("foo").expect!(a => "bar") == "bar");
1510     assert(err!string("foo").expect!((a) {}) is null);
1511 
1512     static struct NonCopyable { @disable this(this); int foo; }
1513     assert(err!NonCopyable(42).expect!((e) {}) == NonCopyable.init);
1514     err!void(42).expect!((e) {});
1515     ok!int().expect!(e => assert(0));
1516     ok!int(42).expect!(e => assert(0));
1517 }
1518 
1519 /++ Unwraps a result, yielding the content of an error value.
1520     If there is none, or success value, it throws $(D assert(0)) with the provided message.
1521 
1522     Params:
1523         res = $(LREF Expected) to check the result of
1524         msg = message to use with assert
1525         handler = custom handler to be called on value
1526 +/
1527 auto ref E expectErr(EX : Expected!(T, E, H), T, E, H)(auto ref EX res, lazy string msg)
1528 {
1529     //TODO: hook for customization
1530 
1531     if (res.hasError) return res.error;
1532 
1533     version (D_BetterC) assert(0, msg);
1534     else
1535     {
1536         import std.format : format;
1537         static if (!is(T == void))
1538         {
1539             if (res.hasValue) assert(0, format!"%s: %s"(msg, forwardValue!res));
1540         }
1541         assert(0, format!"%s: empty"(msg));
1542     }
1543 }
1544 
1545 /// ditto
1546 auto ref E expectErr(alias handler, EX : Expected!(T, E, H), T, E, H)(auto ref EX res)
1547 {
1548     if (res.hasError) return res.error;
1549 
1550     static if (!is(typeof(handler(forwardError!res)) == noreturn) && !is(typeof(handler(T.init)) == void))
1551     {
1552         static if (!is(T == void)) return handler(res.hasValue ? forwardValue!res : T.init);
1553         else return handler();
1554     }
1555     else
1556     {
1557         static if (!is(T == void)) handler(res.hasValue ? forwardValue!res : T.init);
1558         else handler();
1559         static if (__VERSION__ < 2096)
1560             return E.init;
1561         else static if (!is(typeof(handler(forwardError!res)) == noreturn)) // avoid 'statement is not reachable'
1562             return E.init;
1563     }
1564 }
1565 
1566 ///
1567 @("expectErr")
1568 @safe unittest
1569 {
1570     assert(err("foo").expectErr("oops") == "foo");
1571     version (D_Exceptions)
1572     {
1573         () @trusted
1574         {
1575             assert(collectExceptionMsg!Throwable(Expected!int.init.expectErr("oops")) == "oops: empty");
1576             assert(collectExceptionMsg!Throwable(ok(42).expectErr("oops")) == "oops: 42");
1577             assert(collectExceptionMsg!Throwable(ok().expectErr("oops")) == "oops: empty"); // void value
1578         }();
1579     }
1580 
1581     assert(ok("foo").expectErr!(a => "bar") == "bar");
1582     assert(err!string("foo").expectErr!(a => "bar") == "foo");
1583     assert(ok!string("foo").expectErr!((a) {}) is null);
1584     assert(ok!string(42).expectErr!((a) {}) is null);
1585     err!int(42).expectErr!(a => assert(0));
1586 }
1587 
1588 /++
1589     Returns the error contained within the $(LREF Expected) _and then_ another value if there's no error.
1590     This function can be used for control flow based on $(LREF Expected) values.
1591 
1592     Predicate can accept no arguments, variable arguments, or previous result value with additional variable arguments.
1593     It must return $(LREF Expected) wth the same error type. But can provide different value type.
1594 
1595     Params:
1596         exp = The $(LREF Expected) to call andThen on
1597         value = The value to return if there isn't an error
1598         pred = The predicate to call if the there isn't an error
1599 +/
1600 auto ref andThen(EX : Expected!(T, E, H), VEX : Expected!(VT, E, H), T, VT, E, H)(
1601     auto ref EX exp, auto ref VEX value)
1602 {
1603     import core.lifetime : forward;
1604     static if (is(T == VT)) return exp.hasError ? exp : value;
1605     else return exp.hasError ? err!(VT, H)(forwardError!exp) : value;
1606 }
1607 
1608 /// ditto
1609 auto ref andThen(alias pred, EX : Expected!(T, E, H), T, E, H, Args...)(auto ref EX exp, auto ref Args args)
1610 {
1611     import core.lifetime : forward;
1612     static if (!is(T == void) && is(typeof(pred(forwardValue!exp, forward!args)) : Expected!(VT, E, H), VT))
1613     {
1614         static if (is(T == VT)) return exp.hasError ? exp : pred(forwardValue!exp, forward!args);
1615         else return exp.hasError ? err!(VT, H)(forwardError!exp) : pred(forwardValue!exp, forward!args);
1616     }
1617     else static if (is(typeof(pred(forward!args)) : Expected!(VT, E, H), VT))
1618     {
1619         static if (is(T == VT)) return exp.hasError ? exp : pred(forward!args);
1620         else return exp.hasError ? err!(VT, H)(forwardError!exp) : pred(forward!args);
1621     }
1622     else
1623     {
1624         static assert(0, "Expected predicate of Expected type with optional args receiving previous value");
1625     }
1626 }
1627 
1628 ///
1629 @("andThen")
1630 @safe unittest
1631 {
1632     import std.format : format;
1633 
1634     assert(ok(42).andThen(ok(1)) == 1);
1635     assert(ok(42).andThen!(() => ok(0)) == 0);
1636     assert(ok(42).andThen(err!int("foo")).error == "foo");
1637     assert(ok(42).andThen!(() => err!int("foo")).error == "foo");
1638     assert(err!int("foo").andThen(ok(42)).error == "foo");
1639     assert(err!int("foo").andThen!(() => ok(42)).error == "foo");
1640     assert(err!int("foo").andThen(err!int("bar")).error == "foo");
1641     assert(err!int("foo").andThen!(() => err!int("bar")).error == "foo");
1642 
1643     // with void value
1644     assert(ok().andThen!(() => ok()));
1645     assert(ok().andThen!(() => err("foo")).error == "foo");
1646     assert(err("foo").andThen!(() => ok()).error == "foo");
1647 
1648     // with different value type
1649     assert(ok(42).andThen(ok("foo")) == "foo");
1650     assert(err!int("bug").andThen(ok("foo")).error == "bug");
1651     assert(ok(42).andThen!(() => err!bool("foo")).error == "foo");
1652     assert(err!int("bug").andThen!(() => err!bool("foo")).error == "bug");
1653 
1654     // with args
1655     assert(ok(42).andThen!((v) => err!bool(v))("foo").error == "foo"); // doesn't use previous value
1656     version (D_BetterC)
1657         assert(ok(42).andThen!((i, v)
1658             {
1659                 assert(i == 42);
1660                 assert(v == "foo");
1661                 return err!bool("betterc");
1662             })("foo").error == "betterc"); // pass previous value to predicate
1663     else
1664         assert(ok(42).andThen!((i, v) => err!bool(format!"%s: %s"(v, i)))("foo").error == "foo: 42"); // pass previous value to predicate
1665     assert(ok().andThen!((v) => ok(v))(42) == 42); // void type on first ok
1666 }
1667 
1668 /++
1669     Returns the value contained within the $(LREF Expected) _or else_ another value if there's an error.
1670     This function can be used for control flow based on $(LREF Expected) values.
1671 
1672     Predicate can accept no arguments, variable arguments, or previous result error value with additional variable arguments.
1673     It must return $(LREF Expected) wth the same value type. But can provide different error value type.
1674 
1675     Params:
1676         exp = The $(LREF Expected) to call orElse on
1677         value = The value to return if there is an error
1678         pred = The predicate to call if the there is an error
1679 +/
1680 auto ref U orElse(EX, U)(auto ref EX exp, lazy U value)
1681     if (is(EX : Expected!(T, E, H), T, E, H) && is(U : T))
1682 {
1683     import core.lifetime : forward;
1684     return forward!exp.orElse!value;
1685 }
1686 
1687 /// ditto
1688 auto ref orElse(alias pred, EX : Expected!(T, E, H), T, E, H, Args...)(
1689     auto ref EX exp, auto ref Args args)
1690 {
1691     import core.lifetime : forward;
1692     static if (is(typeof(pred(forward!args)) : T))
1693         return exp.hasError ? pred(forward!args) : exp.value;
1694     else static if (is(typeof(pred(forwardError!exp, forward!args)) : T))
1695         return exp.hasError ? pred(forwardError!exp, forward!args) : exp.value;
1696     else static if (is(typeof(pred(forward!args)) : Expected!(T, VE, H), VE))
1697     {
1698         static if (is(E == VE)) return exp.hasError ? pred(forward!args) : exp;
1699         else return exp.hasError ? pred(forward!args) : ok!VE(forwardValue!exp);
1700     }
1701     else static if (is(typeof(pred(forwardError!exp, forward!args)) : Expected!(T, VE, H), VE))
1702     {
1703         static if (is(E == VE)) return exp.hasError ? pred(forwardError!exp, forward!args) : exp;
1704         else return exp.hasError ? pred(forwardError!exp, forward!args) : ok!VE(forwardValue!exp);
1705     }
1706     else static assert(0, "Expecting predicate of same value type");
1707 }
1708 
1709 ///
1710 @("orElse")
1711 @safe unittest
1712 {
1713     assert(ok(42).orElse(0) == 42);
1714     assert(ok(42).orElse!(() => 0) == 42);
1715     assert(err!int("foo").orElse(0) == 0);
1716     assert(err!int("foo").orElse!(() => 0) == 0);
1717     assert(ok(42).orElse!(() => ok(0)) == 42);
1718     assert(err!int("foo").orElse!(() => ok(42)) == 42);
1719     assert(err!int("foo").orElse!(() => err!int("bar")).error == "bar");
1720 
1721     // with void value
1722     assert(ok().orElse!(() => err("foo")));
1723     assert(err("foo").orElse!(() => ok()));
1724     assert(err("foo").orElse!(() => err("bar")).error == "bar");
1725 
1726     // with args
1727     assert(err!int("foo").orElse!((v) => v)(42) == 42);
1728 
1729     // with different error type
1730     assert(err!int("foo").orElse!((v) => ok!int(v))(42).value == 42); // string -> int
1731     assert(err!int("foo").orElse!((v) => err!int(v))(42).error == 42);
1732     assert(err!int("foo").orElse!((e, v) => err!int(e.length + v))(42).error == 45); // with previous error
1733 }
1734 
1735 /++
1736     Applies a function to the expected value in an $(LREF Expected) object.
1737 
1738     If no expected value is present, the original error value is passed through
1739     unchanged, and the function is not called.
1740 
1741     Params:
1742         op = function called to map $(LREF Expected) value
1743         hook = use another hook for mapped $(LREF Expected)
1744 
1745     Returns:
1746         A new $(LREF Expected) object containing the result.
1747 +/
1748 template map(alias op, Hook = Abort)
1749 {
1750     /++
1751         The actual `map` function.
1752 
1753         Params:
1754             self = an [Expected] object
1755     +/
1756     auto ref map(T, E, H)(auto ref Expected!(T, E, H) self)
1757         if ((is(T == void) && is(typeof(op()))) || (!is(T == void) && is(typeof(op(forwardValue!self)))))
1758     {
1759         static if (is(T == void)) alias U = typeof(op());
1760         else alias U = typeof(op(forwardValue!self));
1761 
1762         if (self.hasError) return err!(U, Hook)(forwardError!self);
1763         else
1764         {
1765             static if (is(T == void)) return ok!(E, Hook)(op());
1766             else return ok!(E, Hook)(op(forwardValue!self));
1767         }
1768     }
1769 }
1770 
1771 ///
1772 @("map")
1773 @safe unittest
1774 {
1775     {
1776         assert(ok(42).map!(a => a/2).value == 21);
1777         assert(ok().map!(() => 42).value == 42);
1778         assert(err!int("foo").map!(a => 42).error == "foo");
1779         assert(err("foo").map!(() => 42).error == "foo");
1780     }
1781 
1782     // remap hook
1783     {
1784         static struct Hook {}
1785         auto res = ok(42).map!(a => a/2, Hook);
1786         assert(res == 21);
1787         static assert(is(typeof(res) == Expected!(int, string, Hook)));
1788     }
1789 }
1790 
1791 /++
1792     Applies a function to the expected error in an $(LREF Expected) object.
1793 
1794     If no error is present, the original value is passed through
1795     unchanged, and the function is not called.
1796 
1797     Params:
1798         op = function called to map $(LREF Expected) error
1799         hook = use another hook for mapped $(LREF Expected)
1800 
1801     Returns:
1802         A new $(LREF Expected) object containing the result.
1803 +/
1804 template mapError(alias op, Hook = Abort)
1805 {
1806     /++
1807         The actual `mapError` function.
1808 
1809         Params:
1810             self = an [Expected] object
1811     +/
1812     auto ref mapError(T, E, H)(auto ref Expected!(T, E, H) self)
1813         if (is(typeof(op(forwardError!self))))
1814     {
1815         alias U = typeof(op(forwardError!self));
1816 
1817         static if (!is(T == void))
1818         {
1819             if (self.hasValue) return ok!(U, Hook)(forwardValue!self);
1820         }
1821         return err!(T, Hook)(op(forwardError!self));
1822     }
1823 }
1824 
1825 ///
1826 @("mapError")
1827 @safe unittest
1828 {
1829     {
1830         assert(ok(42).mapError!(e => e).value == 42);
1831         assert(err("foo").mapError!(e => 42).error == 42);
1832         version (D_Exceptions) assert(err("foo").mapError!(e => new Exception(e)).error.msg == "foo");
1833     }
1834 
1835     // remap hook
1836     {
1837         static struct Hook {}
1838         auto res = ok(42).mapError!(e => e, Hook);
1839         assert(res == 42);
1840         static assert(is(typeof(res) == Expected!(int, string, Hook)));
1841 
1842         auto res2 = err!int("foo").mapError!(e => "bar", Hook);
1843         assert(res2.error == "bar");
1844         static assert(is(typeof(res2) == Expected!(int, string, Hook)));
1845     }
1846 }
1847 
1848 /++
1849     Maps a `Expected<T, E>` to `U` by applying a function to a contained value, or a fallback function to a contained error value.
1850 
1851     Both functions has to be of the same return type.
1852 
1853     This function can be used to unpack a successful result while handling an error.
1854 
1855     Params:
1856         valueOp = function called to map $(LREF Expected) value
1857         errorOp = function called to map $(LREF Expected) error
1858         hook = use another hook for mapped $(LREF Expected)
1859 
1860     Returns:
1861         A new $(LREF Expected) object containing the result.
1862 +/
1863 template mapOrElse(alias valueOp, alias errorOp)
1864 {
1865     /++
1866         The actual `mapOrElse` function.
1867 
1868         Params:
1869             self = an [Expected] object
1870     +/
1871     auto ref mapOrElse(T, E, H)(auto ref Expected!(T, E, H) self)
1872         if (
1873             is(typeof(errorOp(forwardError!self))) &&
1874             (
1875                 (is(T == void) && is(typeof(valueOp()) == typeof(errorOp(forwardError!self)))) ||
1876                 (!is(T == void) && is(typeof(valueOp(self.value)) == typeof(errorOp(forwardError!self))))
1877             )
1878         )
1879     {
1880         alias U = typeof(errorOp(forwardError!self));
1881 
1882         if (self.hasError) return errorOp(forwardError!self);
1883         else
1884         {
1885             static if (is(T == void)) return valueOp();
1886             else return valueOp(forwardValue!self);
1887         }
1888     }
1889 }
1890 
1891 ///
1892 @("mapOrElse")
1893 @safe unittest
1894 {
1895     assert(ok(42).mapOrElse!(v => v/2, e => 0) == 21);
1896     assert(ok().mapOrElse!(() => true, e => false));
1897     assert(err!int("foo").mapOrElse!(v => v/2, e => 42) == 42);
1898     assert(!err("foo").mapOrElse!(() => true, e => false));
1899 }
1900 
1901 private template forwardMember(alias arg, string member)
1902 {
1903     import core.lifetime : move;
1904     // lvalue arg or non-moveable member (rvalue or const/immutable)
1905     static if (__traits(isRef,  arg) ||
1906                __traits(isOut,  arg) ||
1907                __traits(isLazy, arg) ||
1908                !is(typeof(move(__traits(getMember, arg, member)))))
1909         @property auto ref forwardMember(){ return __traits(getMember, arg, member); }
1910     // rvalue arg and moveable member (mutable lvalue)
1911     else
1912         @property auto forwardMember(){ return move(__traits(getMember, arg, member)); }
1913 }
1914 
1915 private alias forwardValue(alias arg) = forwardMember!(arg, "value");
1916 private alias forwardError(alias arg) = forwardMember!(arg, "error");
1917 
1918 @("forwardMember")
1919 @safe unittest
1920 {
1921     struct A
1922     {
1923         int i;
1924         ~this() {}
1925     }
1926     struct S
1927     {
1928         A a;
1929         A rvalue() { return a; }
1930         ref A lvalue() { return a; }
1931     }
1932 
1933     bool foo(T)(auto ref T val)
1934     {
1935         return __traits(isRef, val);
1936     }
1937     bool bar(string member, T)(auto ref T val, out int after)
1938     {
1939         auto res = foo(forwardMember!(val, member));
1940         after = val.a.i;
1941         return res;
1942     }
1943 
1944     int after;
1945 
1946     // rvalue arg, member -> foo gets rvalue by move
1947     assert(bar!"a"(S(A(1729)), after) == false);
1948     assert(after == 0);
1949 
1950     // rvalue arg, rvalue method -> foo gets rvalue as return value of `rvalue` method, no moves
1951     assert(bar!"rvalue"(S(A(1729)), after) == false);
1952     assert(after == 1729);
1953 
1954     // rvalue arg, lvalue method -> foo gets rvalue by move
1955     assert(bar!"lvalue"(S(A(1729)), after) == false);
1956     assert(after == 0);
1957 
1958     auto s = S(A(42));
1959 
1960     // lvalue arg, member -> foo gets lvalue
1961     assert(bar!"a"(s, after) == true);
1962     assert(after == 42);
1963     assert(s.a.i == 42);
1964 
1965     // lvalue arg, rvalue method -> foo gets rvalue as return value of `rvalue` method, no moves
1966     assert(bar!"rvalue"(s, after) == false);
1967     assert(after == 42);
1968     assert(s.a.i == 42);
1969 
1970     // lvalue arg, lvalue method -> foo gets lvalue
1971     assert(bar!"lvalue"(s, after) == true);
1972     assert(after == 42);
1973     assert(s.a.i == 42);
1974 }
1975 
1976 static if (__VERSION__ < 2096) {
1977     private alias noreturn = void;
1978 }