-
Notifications
You must be signed in to change notification settings - Fork 0
/
badresults.nim
185 lines (156 loc) · 5.55 KB
/
badresults.nim
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
type
ResultError*[E] = ref object of ValueError
error: E
Result*[T, E] = object
## For documentation, refer to the original nim-results package,
## or this source code. I'm deleting the original documentation
## from here as it's either annoying or incorrect.
case o: bool
of false:
e: E
of true:
v: T
proc isOk*(self: Result): bool = self.o
proc isErr*(self: Result): bool = not self.o
# windows just can't handle .inline. on earlier nims and gc:(refc|m&s)
when (NimMajor, NimMinor) < (1, 5) and defined(windows) and not (defined(gcArc) or defined(gcOrc)):
proc error*[T, E](self: Result[T, E]): E =
## Retrieve the error from a Result; raises ResultError
## if the Result is not in error.
if self.isOk:
raise ResultError[void](msg: "Result does not contain an error")
else:
result = self.e
proc unsafeGet*[T, E](self: var Result[T, E]): var T =
## Fetch value of result if set, undefined behavior if unset
## See also: Option.unsafeGet
assert not isErr(self)
result = self.v
proc unsafeGet*[T, E](self: Result[T, E]): T =
## Fetch value of result if set, undefined behavior if unset
## See also: Option.unsafeGet
assert not isErr(self)
result = self.v
proc unsafeGet*[E](self: Result[void, E]) =
## Raise an exception if Result is an error.
## See also: Option.unsafeGet
assert not self.isErr
else:
proc error*[T, E](self: Result[T, E]): E {.inline.} =
## Retrieve the error from a Result; raises ResultError
## if the Result is not in error.
if self.isOk:
raise ResultError[void](msg: "Result does not contain an error")
else:
result = self.e
proc unsafeGet*[T, E](self: var Result[T, E]): var T {.inline.} =
## Fetch value of result if set, undefined behavior if unset
## See also: Option.unsafeGet
assert not isErr(self)
result = self.v
proc unsafeGet*[T, E](self: Result[T, E]): T {.inline.} =
## Fetch value of result if set, undefined behavior if unset
## See also: Option.unsafeGet
assert not isErr(self)
result = self.v
proc unsafeGet*[E](self: Result[void, E]) {.inline.} =
## Raise an exception if Result is an error.
## See also: Option.unsafeGet
assert not self.isErr
func newResultError[E](e: E; s: string): ResultError[E] {.inline, nimcall.} =
## capturing ResultError...
ResultError[E](error: e, msg: s)
template toException*[E](err: E): ResultError[E] =
mixin `$`
mixin newResultError
when compiles($err):
newResultError(err, "Result isErr: " & $err)
else:
newResultError(err, "Result isErr; no `$` in scope.")
template raiseResultError[T, E](self: Result[T, E]) =
mixin toException
mixin error
when E is ref Exception:
if self.error.isNil: # for example Result.default()!
raise ResultError[void](msg: "Result isErr; no exception.")
else:
raise self.error
else:
raise self.error.toException
proc ok*[E](R: typedesc[Result[void, E]]): Result[void, E] =
## Return a result as success.
R(o: true)
proc ok*[E](self: var Result[void, E]) =
## Set a result to success.
## Example: `result.ok(42)`
self = ok[E](typeOf(self))
proc ok*[T, E](R: typedesc[Result[T, E]]; v: T): Result[T, E] =
## Return a result with a success and value.
## Example: `Result[int, string].ok(42)`
R(o: true, v: v)
proc ok*[T, E](self: var Result[T, E]; v: T) =
## Set the result to success and update value.
## Example: `result.ok(42)`
self = ok[T, E](typeOf(self), v)
proc err*[T, E](R: typedesc[Result[T, E]]; e: E): Result[T, E] =
## Return a result with an error.
## Example: `Result[int, string].err("uh-oh")`
R(o: false, e: e)
proc err*[T, E](self: var Result[T, E]; e: E) =
## Set the result as an error.
## Example: `result.err("uh-oh")`
self = err[T, E](typeOf(self), e)
func `==`*(a, b: Result): bool {.inline.} =
if a.isOk == b.isOk:
if a.isOk: a.v == b.v
else: a.e == b.e
else:
false
template get*[T: not void, E](self: Result[T, E]): untyped =
## Fetch value of result if set, or raise error as an Exception
## See also: Option.get
mixin isErr
mixin unsafeGet
if self.isErr:
raiseResultError self
unsafeGet self
template get*[T, E](self: Result[T, E]; otherwise: T): untyped =
## Fetch value of result if set, or raise error as an Exception
## See also: Option.get
mixin isErr
mixin unsafeGet
if self.isErr:
otherwise
else:
unsafeGet self
template get*[T, E](self: var Result[T, E]): untyped =
## Fetch mutable value of result if set, or raise error as an Exception
## See also: Option.get
mixin isErr
mixin unsafeGet
if self.isErr:
raiseResultError self
unsafeGet self
template get*[E](self: Result[void, E]) =
## Raise error as an Exception if `self.isErr`.
## See also: Option.get
mixin isErr
mixin unsafeGet
if self.isErr:
raiseResultError self
proc `$`*[T: not void; E](self: Result[T, E]): string =
## Returns string representation of `self`
if self.isOk: "Ok(" & $self.v & ")"
else: "Err(" & $self.e & ")"
func `$`*[E](self: Result[void, E]): string =
## Returns string representation of `self`
if self.isOk: "Ok()"
else: "Err(" & $self.e & ")"
template value*[T, E](self: Result[T, E]): T = get self
template value*[T, E](self: var Result[T, E]): T = get self
template value*[E](self: Result[void, E]) = get self
template value*[E](self: var Result[void, E]) = get self
template valueOr*[T, E](self: Result[T, E], def: T): T =
## Fetch value of result if set, or supplied default
## default will not be evaluated iff value is set
self.get(def)