results: Add `isOkOr`, `isErrOr` (#176)

These two helpers complete `valueOr` and `errorOr` to cover `void` cases
where no value should be returned or `Result[void, E]` /
`Result[T, void]` is being used - they can be used for a convient
early-return style in side-effectful proc:s:

```nim
v.update().isOkOr:
  echo "update failed: ", error
```
This commit is contained in:
Jacek Sieka 2023-04-20 13:08:54 +02:00 committed by GitHub
parent 67fdc87e25
commit 9b985e8ea8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 3 deletions

View File

@ -849,11 +849,67 @@ template unsafeError*[T](self: Result[T, void]) =
template value*[T, E](self: Result[T, E]): T = self.get()
template value*[T: not void, E](self: var Result[T, E]): var T = self.get()
template isOkOr*[T, E](self: Result[T, E], body: untyped) =
## Evaluate `body` iff result has been assigned an error
## `body` is evaluated lazily.
##
## Example:
## ```
## let
## v = Result[int, string].err("hello")
## x = v.isOkOr: echo "not ok"
## # experimental: direct error access using an unqualified `error` symbol
## z = v.isOkOr: echo error
## ```
##
## `error` access:
##
## TODO experimental, might change in the future
##
## The template contains a shortcut for accessing the error of the result,
## it can only be used outside of generic code,
## see https://github.com/status-im/nim-stew/issues/161#issuecomment-1397121386
let s = (self) # TODO avoid copy
if not s.oResultPrivate:
when E isnot void:
template error: E {.used, inject.} = s.eResultPrivate
body
template isErrOr*[T, E](self: Result[T, E], body: untyped) =
## Evaluate `body` iff result has been assigned a value
## `body` is evaluated lazily.
##
## Example:
## ```
## let
## v = Result[int, string].err("hello")
## x = v.isOkOr: echo "not ok"
## # experimental: direct error access using an unqualified `error` symbol
## z = v.isOkOr: echo error
## ```
##
## `value` access:
##
## TODO experimental, might change in the future
##
## The template contains a shortcut for accessing the value of the result,
## it can only be used outside of generic code,
## see https://github.com/status-im/nim-stew/issues/161#issuecomment-1397121386
let s = (self) # TODO avoid copy
if s.oResultPrivate:
when T isnot void:
template value: T {.used, inject.} = s.vResultPrivate
body
template valueOr*[T: not void, E](self: Result[T, E], def: untyped): T =
## Fetch value of result if set, or evaluate `def`
## `def` is evaluated lazily, and must be an expression of `T` or exit
## the scope (for example using `return` / `raise`)
##
## See `isOkOr` for a version that works with `Result[void, E]`.
##
## Example:
## ```
## let
@ -869,11 +925,12 @@ template valueOr*[T: not void, E](self: Result[T, E], def: untyped): T =
## TODO experimental, might change in the future
##
## The template contains a shortcut for accessing the error of the result,
## without specifying the error - it can only be used outside of generic code,
## it can only be used outside of generic code,
## see https://github.com/status-im/nim-stew/issues/161#issuecomment-1397121386
##
let s = (self) # TODO avoid copy
if s.oResultPrivate: s.vResultPrivate
if s.oResultPrivate:
s.vResultPrivate
else:
when E isnot void:
template error: E {.used, inject.} = s.eResultPrivate
@ -883,8 +940,11 @@ template errorOr*[T, E: not void](self: Result[T, E], def: untyped): E =
## Fetch error of result if not set, or evaluate `def`
## `def` is evaluated lazily, and must be an expression of `T` or exit
## the scope (for example using `return` / `raise`)
##
## See `isErrOr` for a version that works with `Result[T, void]`.
let s = (self) # TODO avoid copy
if not s.oResultPrivate: s.eResultPrivate
if not s.oResultPrivate:
s.eResultPrivate
else:
when T isnot void:
template value: T {.used, inject.} = s.vResultPrivate

View File

@ -70,6 +70,15 @@ block:
doAssert rOk.get() == rOk.unsafeGet()
rOk.isOkOr: raiseAssert "should not end up in here"
rErr.isErrOr: raiseAssert "should not end up in here"
rErr.isOkOr:
doAssert error == rErr.error()
rOk.isErrOr:
doAssert value == rOk.value()
doAssert rOk.valueOr(failFast()) == rOk.value()
let rErrV = rErr.valueOr:
error.len