diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/asyncdispatch.nim | 63 | ||||
-rw-r--r-- | lib/pure/asyncmacro.nim | 4 | ||||
-rw-r--r-- | lib/upcoming/asyncdispatch.nim | 33 |
3 files changed, 75 insertions, 25 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 802c40495..06c21e08d 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -105,6 +105,36 @@ export Port, SocketFlag ## be used to await a procedure returning a ``Future[void]``: ## ``await socket.send("foobar")``. ## +## If an awaited future completes with an error, then ``await`` will re-raise +## this error. To avoid this, you can use the ``yield`` keyword instead of +## ``await``. The following section shows different ways that you can handle +## exceptions in async procs. +## +## Handling Exceptions +## ~~~~~~~~~~~~~~~~~~~ +## +## The most reliable way to handle exceptions is to use ``yield`` on a future +## then check the future's ``failed`` property. For example: +## +## .. code-block:: Nim +## var future = sock.recv(100) +## yield future +## if future.failed: +## # Handle exception +## +## The ``async`` procedures also offer limited support for the try statement. +## +## .. code-block:: Nim +## try: +## let data = await sock.recv(100) +## echo("Received ", data) +## except: +## # Handle exception +## +## Unfortunately the semantics of the try statement may not always be correct, +## and occassionally the compilation may fail altogether. +## As such it is better to use the former style when possible. +## ## Discarding futures ## ------------------ ## @@ -339,17 +369,22 @@ proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = var retFuture = newFuture[void]("asyncdispatch.`and`") fut1.callback = proc () = - if fut2.finished: retFuture.complete() + if not retFuture.finished: + if fut1.failed: retFuture.fail(fut1.error) + elif fut2.finished: retFuture.complete() fut2.callback = proc () = - if fut1.finished: retFuture.complete() + if not retFuture.finished: + if fut2.failed: retFuture.fail(fut2.error) + elif fut1.finished: retFuture.complete() return retFuture proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = ## Returns a future which will complete once either ``fut1`` or ``fut2`` ## complete. var retFuture = newFuture[void]("asyncdispatch.`or`") - proc cb() = + proc cb(fut: Future[T]) = + if fut.failed: retFuture.fail(fut.error) if not retFuture.finished: retFuture.complete() fut1.callback = cb fut2.callback = cb @@ -374,10 +409,13 @@ proc all*[T](futs: varargs[Future[T]]): auto = for fut in futs: fut.callback = proc(f: Future[T]) = - inc(completedFutures) + if f.failed: + retFuture.fail(f.error) + elif not retFuture.finished: + inc(completedFutures) - if completedFutures == totalFutures: - retFuture.complete() + if completedFutures == totalFutures: + retFuture.complete() return retFuture @@ -390,11 +428,14 @@ proc all*[T](futs: varargs[Future[T]]): auto = for i, fut in futs: proc setCallback(i: int) = fut.callback = proc(f: Future[T]) = - retValues[i] = f.read() - inc(completedFutures) - - if completedFutures == len(retValues): - retFuture.complete(retValues) + if f.failed: + retFuture.fail(f.error) + elif not retFuture.finished: + retValues[i] = f.read() + inc(completedFutures) + + if completedFutures == len(retValues): + retFuture.complete(retValues) setCallback(i) diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim index 28e3e2a16..6b565cd3b 100644 --- a/lib/pure/asyncmacro.nim +++ b/lib/pure/asyncmacro.nim @@ -144,11 +144,9 @@ proc processBody(node, retFutureSym: NimNode, of nnkCommand, nnkCall: if node[0].kind == nnkIdent and node[0].ident == !"await": case node[1].kind - of nnkIdent, nnkInfix, nnkDotExpr: + of nnkIdent, nnkInfix, nnkDotExpr, nnkCall, nnkCommand: # await x # await x or y - result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x - of nnkCall, nnkCommand: # await foo(p, x) # await foo p, x var futureValue: NimNode diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim index 689d0272c..460dfbd1a 100644 --- a/lib/upcoming/asyncdispatch.nim +++ b/lib/upcoming/asyncdispatch.nim @@ -339,17 +339,22 @@ proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = var retFuture = newFuture[void]("asyncdispatch.`and`") fut1.callback = proc () = - if fut2.finished: retFuture.complete() + if not retFuture.finished: + if fut1.failed: retFuture.fail(fut1.error) + elif fut2.finished: retFuture.complete() fut2.callback = proc () = - if fut1.finished: retFuture.complete() + if not retFuture.finished: + if fut2.failed: retFuture.fail(fut2.error) + elif fut1.finished: retFuture.complete() return retFuture proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = ## Returns a future which will complete once either ``fut1`` or ``fut2`` ## complete. var retFuture = newFuture[void]("asyncdispatch.`or`") - proc cb() = + proc cb(fut: Future[T]) = + if fut.failed: retFuture.fail(fut.error) if not retFuture.finished: retFuture.complete() fut1.callback = cb fut2.callback = cb @@ -374,10 +379,13 @@ proc all*[T](futs: varargs[Future[T]]): auto = for fut in futs: fut.callback = proc(f: Future[T]) = - inc(completedFutures) + if f.failed: + retFuture.fail(f.error) + elif not retFuture.finished: + inc(completedFutures) - if completedFutures == totalFutures: - retFuture.complete() + if completedFutures == totalFutures: + retFuture.complete() return retFuture @@ -390,11 +398,14 @@ proc all*[T](futs: varargs[Future[T]]): auto = for i, fut in futs: proc setCallback(i: int) = fut.callback = proc(f: Future[T]) = - retValues[i] = f.read() - inc(completedFutures) - - if completedFutures == len(retValues): - retFuture.complete(retValues) + if f.failed: + retFuture.fail(f.error) + elif not retFuture.finished: + retValues[i] = f.read() + inc(completedFutures) + + if completedFutures == len(retValues): + retFuture.complete(retValues) setCallback(i) |