Compare commits

...

5 Commits

Author SHA1 Message Date
Adam Uhlíř
2906828765
Add errorOption example to Readme
Added example for errorOption conversion in Readme.
2025-10-22 16:12:58 +02:00
Marcin Czenko
2e7f20392b Update Readme.md
Missing "to"
2024-12-04 01:01:47 +01:00
Mark Spanbroek
3dcf21491d without with error variable works for any Result type 2024-05-29 12:45:40 +02:00
Mark Spanbroek
82d90b67bc version 0.10.15 2024-04-20 08:08:31 +02:00
Mark Spanbroek
b098ae696a Workaround for Nim gensym bug
Occasionally different `evaluated` symbols would be
gensymmed to the same symbol.
2024-04-20 08:07:28 +02:00
5 changed files with 36 additions and 11 deletions

View File

@ -12,7 +12,7 @@ Use the [Nimble][3] package manager to add `questionable` to an existing
project. Add the following to its .nimble file: project. Add the following to its .nimble file:
```nim ```nim
requires "questionable >= 0.10.14 & < 0.11.0" requires "questionable >= 0.10.15 & < 0.11.0"
``` ```
If you want to make use of Result types, then you also have to add either the If you want to make use of Result types, then you also have to add either the
@ -151,7 +151,7 @@ have to explicitly import the `questionable/results` module:
import questionable/results import questionable/results
``` ```
You can use `?!` make a Result type. These Result types either hold a value or You can use `?!` to make a Result type. These Result types either hold a value or
an error. For example the type `?!int` is short for `Result[int, ref an error. For example the type `?!int` is short for `Result[int, ref
CatchableError]`. CatchableError]`.
@ -226,6 +226,7 @@ Any Result can be converted to an Option:
```nim ```nim
let converted = works().option # equals @[1, 1, 2, 2, 2].some let converted = works().option # equals @[1, 1, 2, 2, 2].some
let errOption = fails().errorOption # option that is set when the Result holds an error
``` ```
[1]: https://nim-lang.org/docs/options.html [1]: https://nim-lang.org/docs/options.html

View File

@ -1,4 +1,4 @@
version = "0.10.14" version = "0.10.15"
author = "Questionable Authors" author = "Questionable Authors"
description = "Elegant optional types" description = "Elegant optional types"
license = "MIT" license = "MIT"

View File

@ -11,26 +11,28 @@ macro captureBindError*(error: var ref CatchableError, expression): auto =
# name of the error variable as a string literal # name of the error variable as a string literal
let errorVariableName = newLit($error) let errorVariableName = newLit($error)
let evaluated = genSym(nskLet, "evaluated")
quote do: quote do:
# add error variable to the top of the stack # add error variable to the top of the stack
static: errorVariableNames.add(`errorVariableName`) static: errorVariableNames.add(`errorVariableName`)
# evaluate the expression # evaluate the expression
let evaluated = `expression` let `evaluated` = `expression`
# pop error variable from the stack # pop error variable from the stack
static: discard errorVariableNames.pop() static: discard errorVariableNames.pop()
# return the evaluated result # return the evaluated result
evaluated `evaluated`
func unsafeError[T](_: Option[T]): ref CatchableError = func unsafeCatchableError[T](_: Option[T]): ref CatchableError =
newException(ValueError, "Option is set to `none`") newException(ValueError, "Option is set to `none`")
func unsafeError[T](_: ref T): ref CatchableError = func unsafeCatchableError[T](_: ref T): ref CatchableError =
newException(ValueError, "ref is nil") newException(ValueError, "ref is nil")
func unsafeError[T](_: ptr T): ref CatchableError = func unsafeCatchableError[T](_: ptr T): ref CatchableError =
newException(ValueError, "ptr is nil") newException(ValueError, "ptr is nil")
func unsafeError[Proc: proc | iterator](_: Proc): ref CatchableError = func unsafeCatchableError[Proc: proc | iterator](_: Proc): ref CatchableError =
newException(ValueError, "proc or iterator is nil") newException(ValueError, "proc or iterator is nil")
macro bindFailed*(expression: typed) = macro bindFailed*(expression: typed) =
@ -49,4 +51,4 @@ macro bindFailed*(expression: typed) =
# check that the error variable is in scope # check that the error variable is in scope
when compiles(`errorVariable`): when compiles(`errorVariable`):
# assign bind error to error variable # assign bind error to error variable
`errorVariable` = `expression`.unsafeError `errorVariable` = `expression`.unsafeCatchableError

View File

@ -123,6 +123,18 @@ template toOption*[T, E](value: Result[T, E]): ?T =
value.option value.option
proc unsafeCatchableError*[T, E](value: Result[T, E]): ref CatchableError =
## Returns the error from the Result, converted to `ref CatchableError` if
## necessary. Behaviour is undefined when the result holds a value instead of
## an error.
when E is ref CatchableError:
value.unsafeError
else:
when compiles($value.unsafeError):
newException(ResultFailure, $value.unsafeError)
else:
newException(ResultFailure, "Result is an error")
proc errorOption*[T, E](value: Result[T, E]): ?E = proc errorOption*[T, E](value: Result[T, E]): ?E =
## Returns an Option that contains the error from the Result, if it has one. ## Returns an Option that contains the error from the Result, if it has one.

View File

@ -663,7 +663,7 @@ suite "result compatibility":
type R = Result[int, string] type R = Result[int, string]
let good = R.ok 42 let good = R.ok 42
let bad = R.err "error" let bad = R.err "some error"
test "|?, =? and .option work on other types of Result": test "|?, =? and .option work on other types of Result":
check bad |? 43 == 43 check bad |? 43 == 43
@ -681,3 +681,13 @@ suite "result compatibility":
fail fail
without b =? good: without b =? good:
fail fail
test "without statement with error works on other type of Result":
without value =? bad, error:
check error of ResultFailure
check error.msg == "some error"
test "without statement with error works on Result[T, void]":
without value =? Result[int, void].err, error:
check error of ResultFailure
check error.msg == "Result is an error"