Skip to content

Instantly share code, notes, and snippets.

@marcinczenko
Last active April 7, 2025 05:58
Show Gist options
  • Select an option

  • Save marcinczenko/c667fad0b70718d6f157275a2a7e7a93 to your computer and use it in GitHub Desktop.

Select an option

Save marcinczenko/c667fad0b70718d6f157275a2a7e7a93 to your computer and use it in GitHub Desktop.
nim: working with checked exceptions
import std/sequtils
import std/macros
import pkg/chronos
from pkg/chronos/internal/raisesfutures import makeNoRaises
macro newRaisingFuture(T: typedesc, E: typed, fromProc: static[string] = ""): untyped =
let
baseType = T.strVal
e =
case E.getTypeInst().typeKind()
of ntyTypeDesc: @[E]
of ntyArray:
for x in E:
if x.getTypeInst().typeKind != ntyTypeDesc:
error("Expected typedesc, got " & repr(x), x)
E.mapIt(it)
else:
error("Expected typedesc, got " & repr(E), E)
# @[]
let raises = if e.len == 0:
nnkBracket.newTree()
else:
nnkBracket.newTree(e)
let raisesTuple = if e.len == 0:
makeNoRaises()
else:
nnkTupleConstr.newTree(e)
result = nnkStmtList.newTree(
nnkCall.newTree(
nnkPar.newTree(
nnkLambda.newTree(
newEmptyNode(),
newEmptyNode(),
newEmptyNode(),
nnkFormalParams.newTree(
nnkBracketExpr.newTree(
newIdentNode("Future"),
newIdentNode(baseType)
)
),
nnkPragma.newTree(
nnkExprColonExpr.newTree(
newIdentNode("async"),
nnkTupleConstr.newTree(
nnkExprColonExpr.newTree(
newIdentNode("raw"),
newIdentNode("true")
),
nnkExprColonExpr.newTree(
newIdentNode("raises"),
raises
)
)
)
),
newEmptyNode(),
nnkStmtList.newTree(
nnkCall.newTree(
nnkBracketExpr.newTree(
newIdentNode("newInternalRaisesFuture"),
newIdentNode(baseType),
raisesTuple
),
nnkExprEqExpr.newTree(
newIdentNode("fromProc"),
newLit(fromProc)
)
)
)
)
)
)
)
macro RaisingFuture(T: typedesc, E: typed): untyped =
let
baseType = T.strVal
e =
case E.getTypeInst().typeKind()
of ntyTypeDesc: @[E]
of ntyArray:
for x in E:
if x.getTypeInst().typeKind != ntyTypeDesc:
error("Expected typedesc, got " & repr(x), x)
E.mapIt(it)
else:
error("Expected typedesc, got " & repr(E), E)
# @[]
let raises = if e.len == 0:
makeNoRaises()
else:
nnkTupleConstr.newTree(e)
result = nnkBracketExpr.newTree(
ident "InternalRaisesFuture",
newIdentNode(baseType),
raises
)
type
MyError = object of CatchableError
SomeType = object
name: string
handle1: RaisingFuture(void, CancelledError)
handle2: RaisingFuture(void, [CancelledError, MyError])
handle3: RaisingFuture(int, [CancelledError])
SomeType2[T] = object
name: string
handle: RaisingFuture(T, [CancelledError])
proc newSomeType(name: string): SomeType =
let t = SomeType(
name: name,
handle1: newRaisingFuture(void, CancelledError),
handle2: newRaisingFuture(void, [CancelledError, MyError]),
handle3: newRaisingFuture(int, [CancelledError]),
)
t
proc newSomeType2[T](name: string): SomeType2[T] =
let t = SomeType2[T](
name: name,
handle: newRaisingFuture(T, CancelledError),
)
t
let someTypeInstance = newSomeType("test")
echo typeof(someTypeInstance.handle1)
echo typeof(someTypeInstance.handle2)
echo typeof(someTypeInstance.handle3)
let someType2Instance = newSomeType2[int]("test2")
echo typeof(someType2Instance.handle)
proc waitHandle[T](_: typedesc[Future[T]], h: auto): Future[T] {.async: (raises: [CancelledError]).} =
await h
proc waitHandle2[T](_: typedesc[Future[T]], h: RaisingFuture(T, [CancelledError])): Future[T] {.async: (raises: [CancelledError]).} =
return await h
someTypeInstance.handle1.complete()
waitFor Future[void].waitHandle(someTypeInstance.handle1)
echo "done 1"
someType2Instance.handle.complete(42)
echo waitFor Future[int].waitHandle(someType2Instance.handle)
echo "done 2"
let handle = newRaisingFuture(int, CancelledError)
handle.complete(43)
echo waitFor Future[int].waitHandle2(handle)
echo "done 3"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment