Last active
April 7, 2025 05:58
-
-
Save marcinczenko/c667fad0b70718d6f157275a2a7e7a93 to your computer and use it in GitHub Desktop.
nim: working with checked exceptions
This file contains hidden or 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
| 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