# Inspired by nim-results. type Result*[T, E] = object when E is void and T is void: # weirdness has*: bool elif E is void and not (T is void): # opt case has*: bool of true: val*: T else: discard elif not (E is void) and T is void: # err case has*: bool of true: discard else: ex*: E else: # result case has*: bool of true: val*: T else: ex*: E Opt*[T] = Result[T, void] Err*[E] = Result[void, E] template ok*[E](t: type Err[E]): Err[E] = Err[E](has: true) template ok*[T, E](t: type Result[T, E], x: T): Result[T, E] = Result[T, E](val: x, has: true) template ok*[T](x: T): auto = ok(typeof(result), x) template ok*(): auto = ok(typeof(result)) template ok*[T, E](res: var Result[T, E], x: T) = res = Result[T, E](has: true, val: x) template ok*[E](res: var Result[void, E]) = res = Result[void, E](has: true) template err*[T, E](t: type Result[T, E], e: E): Result[T, E] = Result[T, E](has: false, ex: e) template err*[T](t: type Result[T, ref object]): auto = t(has: false, ex: nil) template err*[T](t: type Result[T, void]): Result[T, void] = Result[T, void](has: false) template err*(): auto = err(typeof(result)) template err*[T, E](res: var Result[T, E], e: E) = res = Result[T, E](has: false, ex: e) template err*[T, E](res: var Result[T, E]) = res = Result[T, E](has: false) template err*[E](e: E): auto = err(typeof(result), e) template opt*[T](v: T): auto = ok(Opt[T], v) template opt*(t: typedesc): auto = err(Result[t, void]) template opt*[T, E: not void](r: Result[T, E]): Opt[T] = if r.isOk: Opt[T].ok(r.get) else: Opt[T].err() template isOk*(res: Result): bool = res.has template isErr*(res: Result): bool = not res.has template isSome*(res: Result): bool = res.isOk template isNone*(res: Result): bool = res.isErr func get*[T, E](res: Result[T, E]): T {.inline.} = res.val func get*[T, E](res: var Result[T, E]): var T = res.val func get*[T, E](res: Result[T, E], v: T): T = if res.has: res.val else: v func error*[T, E](res: Result[T, E]): E {.inline.} = res.ex template valType*[T, E](res: type Result[T, E]): auto = T template errType*[T, E](res: type Result[T, E]): auto = E template `?`*[T, E](res: Result[T, E]): auto = let x = res # for when res is a funcall if x.has: when not (T is void): x.get else: discard else: when typeof(result) is Result[T, E]: return x elif not (E is void) and typeof(result).errType is E: return err(x.error) else: return err()