Last active
January 12, 2022 21:45
-
-
Save michaelsbradleyjr/8fb421937c14cf128240a65a3ea712e2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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