summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/asyncdispatch.nim55
-rw-r--r--tests/async/tasyncall.nim50
2 files changed, 89 insertions, 16 deletions
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 2c7aaf2bf..7d765ce75 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -355,27 +355,50 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
   fut2.callback = cb
   return retFuture
 
-proc all*[A](futs: seq[Future[A]]): Future[seq[A]] =
-  ## Returns a future which will complete once all futures in ``futs``
-  ## complete.
+proc all*[T](futs: varargs[Future[T]]): auto =
+  ## Returns a future which will complete once
+  ## all futures in ``futs`` complete.
+  ##
+  ## If the awaited futures are not ``Future[void]``, the returned future
+  ## will hold the values of all awaited futures in a sequence.
   ##
-  ## The resulting future will hold the values of all awaited futures,
-  ## in the order they are passed.
+  ## If the awaited futures *are* ``Future[void]``,
+  ## this proc returns ``Future[void]``.
 
-  var
-    retFuture = newFuture[seq[A]]("asyncdispatch.all")
-    retValues = newSeq[A](len(futs))
-    completedFutures = 0
+  when T is void:
+    var
+      retFuture = newFuture[void]("asyncdispatch.all")
+      completedFutures = 0
 
-  for i, fut in futs:
-    fut.callback = proc(f: Future[A]) =
-      retValues[i] = f.read()
-      inc(completedFutures)
+    let totalFutures = len(futs)
 
-      if completedFutures == len(futs):
-        retFuture.complete(retValues)
+    for fut in futs:
+      fut.callback = proc(f: Future[T]) =
+        inc(completedFutures)
 
-  return retFuture
+        if completedFutures == totalFutures:
+          retFuture.complete()
+
+    return retFuture
+
+  else:
+    var
+      retFuture = newFuture[seq[T]]("asyncdispatch.all")
+      retValues = newSeq[T](len(futs))
+      completedFutures = 0
+
+    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)
+
+      setCallback(i)
+
+    return retFuture
 
 type
   PDispatcherBase = ref object of RootRef
diff --git a/tests/async/tasyncall.nim b/tests/async/tasyncall.nim
new file mode 100644
index 000000000..971122ad9
--- /dev/null
+++ b/tests/async/tasyncall.nim
@@ -0,0 +1,50 @@
+discard """
+  file: "tasyncall.nim"
+  exitcode: 0
+"""
+import times, sequtils
+import asyncdispatch
+
+const
+  taskCount = 10
+  sleepDuration = 500
+
+proc futureWithValue(x: int): Future[int] {.async.} =
+  await sleepAsync(sleepDuration)
+  return x
+
+proc futureWithoutValue() {.async.} =
+  await sleepAsync(1000)
+
+proc testFuturesWithValue(x: int): seq[int] =
+  var tasks = newSeq[Future[int]](taskCount)
+
+  for i in 0..<taskCount:
+    tasks[i] = futureWithValue(x)
+
+  result = waitFor all(tasks)
+
+proc testFuturesWithoutValues() =
+  var tasks = newSeq[Future[void]](taskCount)
+
+  for i in 0..<taskCount:
+    tasks[i] = futureWithoutValue()
+
+  waitFor all(tasks)
+
+block:
+  let
+    startTime = cpuTime()
+    results = testFuturesWithValue(42)
+    expected = repeat(42, taskCount)
+    execTime = cpuTime() - startTime
+
+  doAssert execTime * 1000 < taskCount * sleepDuration
+  doAssert results == expected
+
+block:
+  let startTime = cpuTime()
+  testFuturesWithoutValues()
+  let execTime = cpuTime() - startTime
+
+  doAssert execTime * 1000 < taskCount * sleepDuration