about summary refs log tree commit diff stats
path: root/src/utils/opt.nim
blob: cdf696330cee45701e630f910360da74627d3ff0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# 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()