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):
|
||||
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 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
|
||||
type
|
||||
AnEnum = enum
|
||||
|
@ -381,6 +412,17 @@ block: # Result[T, void] aka `Opt`
|
|||
doAssert oOk.orErr("error").value() == oOk.get()
|
||||
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
|
||||
type CSRes = Result[void, cstring]
|
||||
|
||||
|
|
Loading…
Reference in New Issue