From 3dcf21491d10a4e3fb7b61843ef476e9f2e58aa2 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 12 Mar 2024 15:15:19 +0100 Subject: [PATCH] `without` with error variable works for any Result type --- questionable/private/binderror.nim | 10 +++++----- questionable/results.nim | 12 ++++++++++++ testmodules/results/test.nim | 12 +++++++++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/questionable/private/binderror.nim b/questionable/private/binderror.nim index 92d40a9..33209e6 100644 --- a/questionable/private/binderror.nim +++ b/questionable/private/binderror.nim @@ -23,16 +23,16 @@ macro captureBindError*(error: var ref CatchableError, expression): auto = # return the evaluated result `evaluated` -func unsafeError[T](_: Option[T]): ref CatchableError = +func unsafeCatchableError[T](_: Option[T]): ref CatchableError = 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") -func unsafeError[T](_: ptr T): ref CatchableError = +func unsafeCatchableError[T](_: ptr T): ref CatchableError = 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") macro bindFailed*(expression: typed) = @@ -51,4 +51,4 @@ macro bindFailed*(expression: typed) = # check that the error variable is in scope when compiles(`errorVariable`): # assign bind error to error variable - `errorVariable` = `expression`.unsafeError + `errorVariable` = `expression`.unsafeCatchableError diff --git a/questionable/results.nim b/questionable/results.nim index f3d4565..adc53b9 100644 --- a/questionable/results.nim +++ b/questionable/results.nim @@ -123,6 +123,18 @@ template toOption*[T, E](value: Result[T, E]): ?T = 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 = ## Returns an Option that contains the error from the Result, if it has one. diff --git a/testmodules/results/test.nim b/testmodules/results/test.nim index 96c0aac..753e845 100644 --- a/testmodules/results/test.nim +++ b/testmodules/results/test.nim @@ -663,7 +663,7 @@ suite "result compatibility": type R = Result[int, string] 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": check bad |? 43 == 43 @@ -681,3 +681,13 @@ suite "result compatibility": fail without b =? good: 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"