mirror of
https://github.com/logos-storage/questionable.git
synced 2026-03-25 05:53:44 +00:00
Attempt to fix #11
This commit is contained in:
parent
d7e9f0bf7f
commit
ba353b27e4
@ -7,19 +7,11 @@ proc option[T](option: Option[T]): Option[T] =
|
||||
proc placeholder(T: type): T =
|
||||
discard
|
||||
|
||||
template bindLet(name, expression): bool =
|
||||
let option = expression.option
|
||||
template unpack*(expression: Option): untyped =
|
||||
let option = expression
|
||||
type T = typeof(option.unsafeGet())
|
||||
let name {.used.} = if option.isSome: option.unsafeGet() else: placeholder(T)
|
||||
option.isSome
|
||||
|
||||
template bindVar(name, expression): bool =
|
||||
let option = expression.option
|
||||
type T = typeof(option.unsafeGet())
|
||||
var name {.used.} : T = placeholder(T)
|
||||
if option.isSome:
|
||||
name = option.unsafeGet()
|
||||
option.isSome
|
||||
let res = if option.isSome: option.unsafeGet() else: placeholder(T)
|
||||
(res, option.isSome)
|
||||
|
||||
macro `=?`*(name, expression): bool =
|
||||
## The `=?` operator lets you bind the value inside an Option or Result to a
|
||||
@ -28,7 +20,14 @@ macro `=?`*(name, expression): bool =
|
||||
|
||||
name.expectKind({nnkIdent, nnkVarTy})
|
||||
if name.kind == nnkIdent:
|
||||
quote do: bindLet(`name`, `expression`)
|
||||
quote do:
|
||||
mixin unpack
|
||||
let (`name`, isOk) = unpack(`expression`)
|
||||
isOk
|
||||
|
||||
else:
|
||||
let name = name[0]
|
||||
quote do: bindVar(`name`, `expression`)
|
||||
quote do:
|
||||
mixin unpack
|
||||
var (`name`, isOk) = unpack(`expression`)
|
||||
isOk
|
||||
|
||||
@ -99,6 +99,13 @@ template `|?`*[T,E](value: Result[T,E], fallback: T): T =
|
||||
|
||||
value.valueOr(fallback)
|
||||
|
||||
template unpack*(expression: Result): untyped =
|
||||
let res = expression
|
||||
when declaredInScope(internalWithoutError):
|
||||
if res.isFailure:
|
||||
internalWithoutError = res.error
|
||||
unpack(res.option)
|
||||
|
||||
proc option*[T,E](value: Result[T,E]): ?T =
|
||||
## Converts a Result into an Option.
|
||||
|
||||
|
||||
@ -21,19 +21,13 @@ template without*(condition, errorname, body) =
|
||||
## Used to place guards that ensure that a Result contains a value.
|
||||
## Exposes error when Result does not contain a value.
|
||||
|
||||
var error: ref CatchableError
|
||||
|
||||
# override =? operator such that it stores the error if there is one
|
||||
template `override=?`(name, expression): bool {.gensym, used.} =
|
||||
let optional = expression
|
||||
when optional is Result:
|
||||
if optional.isFailure:
|
||||
error = optional.error
|
||||
when optional is Option:
|
||||
if optional.isNone:
|
||||
error = newException(ValueError, "Option is set to `none`")
|
||||
name =? optional
|
||||
|
||||
without replaceInfix(condition, `=?`, `override=?`):
|
||||
template errorname: ref CatchableError = error
|
||||
when not declaredInScope(internalWithoutError):
|
||||
var internalWithoutError {.inject.}: ref CatchableError
|
||||
else:
|
||||
internalWithoutError = nil
|
||||
|
||||
without condition:
|
||||
template errorname: ref CatchableError = internalWithoutError
|
||||
if isNil(errorname):
|
||||
errorname = newException(ValueError, "Option is set to `none`")
|
||||
body
|
||||
|
||||
@ -265,6 +265,15 @@ suite "result":
|
||||
|
||||
test()
|
||||
|
||||
test "without statement works in generic code":
|
||||
proc test(_: type) =
|
||||
without a =? int.failure "error", e:
|
||||
check e.msg == "error"
|
||||
return
|
||||
fail
|
||||
|
||||
test(int)
|
||||
|
||||
test "catch can be used to convert exceptions to results":
|
||||
check parseInt("42").catch == 42.success
|
||||
check parseInt("foo").catch.error of ValueError
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user