results: collections integration (#179)
This set of helpers allows treating Result and Opt as collections of 0 or 1 item, allowing iterating over them and checking "membership" - such integration is useful in generic code which can then be generalised to handle more complex cases - the integration is most useful with Opt. One design tradeoff here is the "explicitness" of `items` vs `values` for `Result` - technically error and value are "equal" and therefore we shouldn't give preference to the value, but there exists a convenience argument to treat the value as the "default" and therefore define `items` / `contains` for `Result` as well - this PR chooses the more conservative and explicit approach - a more liberal version can easily be added later should motivating examples emerge.
This commit is contained in:
parent
000eeb14a3
commit
13e55ed27a
|
@ -1076,3 +1076,49 @@ template `?`*[T, E](self: Result[T, E]): auto =
|
||||||
|
|
||||||
when not(T is void):
|
when not(T is void):
|
||||||
v.vResultPrivate
|
v.vResultPrivate
|
||||||
|
|
||||||
|
# Collection integration
|
||||||
|
|
||||||
|
iterator values*[T, E](self: Result[T, E]): T =
|
||||||
|
## Iterate over a Result as a 0/1-item collection, returning its value if set
|
||||||
|
if self.oResultPrivate:
|
||||||
|
yield self.vResultPrivate
|
||||||
|
|
||||||
|
iterator errors*[T, E](self: Result[T, E]): E =
|
||||||
|
## Iterate over a Result as a 0/1-item collection, returning its error if set
|
||||||
|
if not self.oResultPrivate:
|
||||||
|
yield self.eResultPrivate
|
||||||
|
|
||||||
|
iterator items*[T](self: Opt[T]): T =
|
||||||
|
## Iterate over an Opt as a 0/1-item collection, returning its value if set
|
||||||
|
if self.oResultPrivate:
|
||||||
|
yield self.vResultPrivate
|
||||||
|
|
||||||
|
iterator mvalues*[T, E](self: var Result[T, E]): var T =
|
||||||
|
if self.oResultPrivate:
|
||||||
|
yield self.vResultPrivate
|
||||||
|
|
||||||
|
iterator merrors*[T, E](self: var Result[T, E]): var E =
|
||||||
|
if not self.oResultPrivate:
|
||||||
|
yield self.eResultPrivate
|
||||||
|
|
||||||
|
iterator mitems*[T](self: var Opt[T]): var T =
|
||||||
|
if self.oResultPrivate:
|
||||||
|
yield self.vResultPrivate
|
||||||
|
|
||||||
|
func containsValue*(self: Result, v: auto): bool =
|
||||||
|
## Return true iff the given result is set to a value that equals `v`
|
||||||
|
self.oResultPrivate and self.vResultPrivate == v
|
||||||
|
|
||||||
|
func containsError*(self: Result, e: auto): bool =
|
||||||
|
## Return true iff the given result is set to an error that equals `e`
|
||||||
|
not self.oResultPrivate and self.eResultPrivate == e
|
||||||
|
|
||||||
|
func contains*(self: Opt, v: auto): bool =
|
||||||
|
## Return true iff the given `Opt` is set to a value that equals `v` - can
|
||||||
|
## also be used in the "infix" `in` form:
|
||||||
|
##
|
||||||
|
## ```nim
|
||||||
|
## assert "value" in Opt.some("value")
|
||||||
|
## ```
|
||||||
|
self.oResultPrivate and self.vResultPrivate == v
|
||||||
|
|
|
@ -199,6 +199,37 @@ block:
|
||||||
doAssert rOk.filter(proc(x: int): auto = Result[void, string].err("filter")).error == "filter"
|
doAssert rOk.filter(proc(x: int): auto = Result[void, string].err("filter")).error == "filter"
|
||||||
doAssert rErr.filter(proc(x: int): auto = Result[void, string].err("filter")) == rErr
|
doAssert rErr.filter(proc(x: int): auto = Result[void, string].err("filter")) == rErr
|
||||||
|
|
||||||
|
# Collections
|
||||||
|
block:
|
||||||
|
var i = 0
|
||||||
|
for v in rOk.values:
|
||||||
|
doAssert v == rOk.value()
|
||||||
|
i += 1
|
||||||
|
doAssert i == 1
|
||||||
|
|
||||||
|
for v in rOk.errors:
|
||||||
|
raiseAssert "not an error"
|
||||||
|
|
||||||
|
doAssert rOk.containsValue(rOk.value())
|
||||||
|
doAssert not rOk.containsValue(rOk.value() + 1)
|
||||||
|
|
||||||
|
doAssert not rOk.containsError("test")
|
||||||
|
|
||||||
|
block:
|
||||||
|
var i = 0
|
||||||
|
for v in rErr.values:
|
||||||
|
raiseAssert "not a value"
|
||||||
|
|
||||||
|
for v in rErr.errors:
|
||||||
|
doAssert v == rErr.error()
|
||||||
|
i += 1
|
||||||
|
doAssert i == 1
|
||||||
|
|
||||||
|
doAssert rErr.containsError(rErr.error())
|
||||||
|
doAssert not rErr.containsError(rErr.error() & "X")
|
||||||
|
|
||||||
|
doAssert not rErr.containsValue(42)
|
||||||
|
|
||||||
# Exception conversions - toException must not be inside a block
|
# Exception conversions - toException must not be inside a block
|
||||||
type
|
type
|
||||||
AnEnum = enum
|
AnEnum = enum
|
||||||
|
@ -381,6 +412,17 @@ block: # Result[T, void] aka `Opt`
|
||||||
doAssert oOk.orErr("error").value() == oOk.get()
|
doAssert oOk.orErr("error").value() == oOk.get()
|
||||||
doAssert oErr.orErr("error").error() == "error"
|
doAssert oErr.orErr("error").error() == "error"
|
||||||
|
|
||||||
|
# Collections
|
||||||
|
block:
|
||||||
|
var i = 0
|
||||||
|
for v in oOk:
|
||||||
|
doAssert v == oOk.value()
|
||||||
|
i += 1
|
||||||
|
doAssert i == 1
|
||||||
|
|
||||||
|
doAssert oOk.value() in oOk
|
||||||
|
doAssert oOk.value() + 1 notin oOk
|
||||||
|
|
||||||
block: # `cstring` dangling reference protection
|
block: # `cstring` dangling reference protection
|
||||||
type CSRes = Result[void, cstring]
|
type CSRes = Result[void, cstring]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue