Skip to content

Instantly share code, notes, and snippets.

@michaelsbradleyjr
Last active January 12, 2022 21:45
Show Gist options
  • Save michaelsbradleyjr/8fb421937c14cf128240a65a3ea712e2 to your computer and use it in GitHub Desktop.
Save michaelsbradleyjr/8fb421937c14cf128240a65a3ea712e2 to your computer and use it in GitHub Desktop.
when (NimMajor, NimMinor, NimPatch) >= (1, 4, 0):
{.push raises:[].}
else:
{.push raises: [Defect].}
import chronos except `?`
import stew/results except `?`
export chronos except `?`
export results except `?`
template `?`*[T, E](self: Future[Result[T, E]]): auto =
# h/t @emizzle 🎉
when not declared(chronosInternalRetFuture):
{.fatal: "can only be used within the body of a chronos {.async.} proc!".}
let v = (self)
var rv = await v
if rv.isErr:
when typeof(result) is typeof(rv):
chronosInternalRetFuture.complete(rv)
else:
when E is void:
chronosInternalRetFuture.complete(err(typeof(rv)))
else:
chronosInternalRetFuture.complete(err(typeof(rv), rv.error))
return chronosInternalRetFuture
when not(T is void):
rv.get
template `?`*[T, E](self: Result[T, E]): auto =
let v = (self)
when declared(chronosInternalRetFuture):
let av = proc(): Future[Result[T, E]] {.async.} = return v
? av()
else:
results.`?` v
proc mapErrTo*[T, E1, E2](r: Future[Result[T, E1]], e2: E2):
Future[Result[T, E2]] {.async.} =
return (await r).mapErr(proc (e1: E1): E2 = e2)
proc mapErrTo*[T, E1, E2](r: Result[T, E1], e2: E2):
Result[T, E2] =
r.mapErr(proc (e1: E1): E2 = e2)
# ------------------------------------------------------------------------------
when isMainModule:
var
res: Result[int, string]
resMapped: Result[int, int]
import std/math
proc fn(retErr: bool): Future[Result[int, string]] {.async.} =
if retErr:
return err "there was an error"
else:
return ok 1
proc caller(retErr: bool): Future[Result[int, string]] {.async.} =
let r = ? fn(retErr)
debugEcho "r = ", $r
return ok r
proc callerMapErr(retErr: bool): Future[Result[int, int]] {.async.} =
let r = ? fn(retErr).mapErrTo(0)
return ok r
res = waitFor caller(true)
assert res.isErr
assert res.error == "there was an error"
res = waitFor caller(false)
assert res.isOk
assert res.get == 1
resMapped = waitFor callerMapErr(true)
assert resMapped.isErr
assert resMapped.error == 0
resMapped = waitFor callerMapErr(false)
assert resMapped.isOk
assert resMapped.get == 1
proc fn2(retErr: bool): Result[int, string] =
if retErr:
return err "there was an error 2"
else:
return ok 2
proc caller2(retErr: bool): Future[Result[int, string]] {.async.} =
let r = ? fn2(retErr)
debugEcho "r = ", $r
return ok r
proc caller2MapErr(retErr: bool): Future[Result[int, int]] {.async.} =
let r = ? fn2(retErr).mapErrTo(0)
return ok r
res = waitFor caller2(true)
assert res.isErr
assert res.error == "there was an error 2"
res = waitFor caller2(false)
assert res.isOk
assert res.get == 2
resMapped = waitFor caller2MapErr(true)
assert resMapped.isErr
assert resMapped.error == 0
resMapped = waitFor caller2MapErr(false)
assert resMapped.isOk
assert resMapped.get == 2
proc fn3(retErr: bool): Result[int, string] =
if retErr:
err "there was an error 3"
else:
ok 3
proc caller3(retErr: bool): Result[int, string] =
let r = ? fn3(retErr)
debugEcho "r = ", $r
ok r
proc caller3MapErr(retErr: bool): Result[int, int] =
let r = ? fn3(retErr).mapErrTo(0)
return ok r
res = caller3(true)
assert res.isErr
assert res.error == "there was an error 3"
res = caller3(false)
assert res.isOk
assert res.get == 3
resMapped = caller3MapErr(true)
assert resMapped.isErr
assert resMapped.error == 0
resMapped = caller3MapErr(false)
assert resMapped.isOk
assert resMapped.get == 3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment