mirror of
https://github.com/status-im/nim-chronos.git
synced 2025-02-03 15:04:38 +00:00
Undeprecate or
operation. (#93)
* Undeprecate `or` operation. Fix `or` for already finished futures. Add tests. * Bump version to 2.3.9.
This commit is contained in:
parent
9ea1017a06
commit
2ecc5500c2
@ -1,5 +1,5 @@
|
||||
packageName = "chronos"
|
||||
version = "2.3.8"
|
||||
version = "2.3.9"
|
||||
author = "Status Research & Development GmbH"
|
||||
description = "Chronos"
|
||||
license = "Apache License 2.0 or MIT"
|
||||
|
@ -490,13 +490,15 @@ proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] {.
|
||||
retFuture.cancelCallback = cancellation
|
||||
return retFuture
|
||||
|
||||
proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] {.
|
||||
deprecated: "Use one[T](varargs[Future[T]])".} =
|
||||
proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
|
||||
## Returns a future which will complete once either ``fut1`` or ``fut2``
|
||||
## complete.
|
||||
##
|
||||
## If ``fut1`` or ``fut2`` will fail, result future will also fail with an
|
||||
## error stored in ``fut1`` or ``fut2`` respectively.
|
||||
##
|
||||
## If cancelled, ``fut1`` and ``fut2`` futures WILL NOT BE cancelled.
|
||||
var retFuture = newFuture[void]("chronos.`or`")
|
||||
var retFuture = newFuture[void]("chronos.or")
|
||||
proc cb(udata: pointer) {.gcsafe.} =
|
||||
if not(retFuture.finished()):
|
||||
var fut = cast[FutureBase](udata)
|
||||
@ -504,16 +506,33 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] {.
|
||||
fut2.removeCallback(cb)
|
||||
else:
|
||||
fut1.removeCallback(cb)
|
||||
if fut.failed(): retFuture.fail(fut.error)
|
||||
else: retFuture.complete()
|
||||
fut1.callback = cb
|
||||
fut2.callback = cb
|
||||
if fut.failed():
|
||||
retFuture.fail(fut.error)
|
||||
else:
|
||||
retFuture.complete()
|
||||
|
||||
proc cancellation(udata: pointer) {.gcsafe.} =
|
||||
# On cancel we remove all our callbacks only.
|
||||
fut1.removeCallback(cb)
|
||||
fut2.removeCallback(cb)
|
||||
|
||||
if fut1.finished():
|
||||
if fut1.failed():
|
||||
retFuture.fail(fut1.error)
|
||||
else:
|
||||
retFuture.complete()
|
||||
return retFuture
|
||||
|
||||
if fut2.finished():
|
||||
if fut2.failed():
|
||||
retFuture.fail(fut2.error)
|
||||
else:
|
||||
retFuture.complete()
|
||||
return retFuture
|
||||
|
||||
fut1.addCallback(cb)
|
||||
fut2.addCallback(cb)
|
||||
|
||||
retFuture.cancelCallback = cancellation
|
||||
return retFuture
|
||||
|
||||
|
@ -684,6 +684,76 @@ suite "Future[T] behavior test suite":
|
||||
result = fut1.finished() and not(fut1.failed()) and fut1.read() == f10 and
|
||||
fut2.finished() and not(fut2.failed()) and fut2.read() == f21
|
||||
|
||||
proc waitForNeLocal[T](fut: Future[T]): Future[T] =
|
||||
## **Blocks** the current thread until the specified future completes.
|
||||
while not(fut.finished()):
|
||||
poll()
|
||||
result = fut
|
||||
|
||||
proc testOr(): bool =
|
||||
|
||||
proc client1() {.async.} =
|
||||
await sleepAsync(200.milliseconds)
|
||||
|
||||
proc client2() {.async.} =
|
||||
await sleepAsync(300.milliseconds)
|
||||
|
||||
proc client3() {.async.} =
|
||||
await sleepAsync(100.milliseconds)
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
|
||||
proc client4() {.async.} =
|
||||
await sleepAsync(400.milliseconds)
|
||||
if true:
|
||||
raise newException(KeyError, "")
|
||||
|
||||
var f1 = waitForNeLocal(client1() or client2())
|
||||
var f2 = waitForNeLocal(client2() or client1())
|
||||
var f3 = waitForNeLocal(client1() or client4())
|
||||
var f4 = waitForNeLocal(client2() or client4())
|
||||
var f5 = waitForNeLocal(client1() or client3())
|
||||
var f6 = waitForNeLocal(client3() or client1())
|
||||
var f7 = waitForNeLocal(client2() or client4())
|
||||
var f8 = waitForNeLocal(client4() or client2())
|
||||
var f9 = waitForNeLocal(client3() or client4())
|
||||
var f10 = waitForNeLocal(client4() or client3())
|
||||
|
||||
result = (f1.finished() and not(f1.failed())) and
|
||||
(f2.finished() and not(f2.failed())) and
|
||||
(f3.finished() and not(f3.failed())) and
|
||||
(f4.finished() and not(f4.failed())) and
|
||||
(f5.finished() and f5.failed()) and
|
||||
(f6.finished() and f6.failed()) and
|
||||
(f7.finished() and not(f7.failed())) and
|
||||
(f8.finished() and not(f8.failed())) and
|
||||
(f9.finished() and f9.failed()) and
|
||||
(f10.finished() and f10.failed())
|
||||
|
||||
proc testOrCompleted(): bool =
|
||||
proc client1(): Future[int] {.async.} =
|
||||
result = 1
|
||||
proc client2(): Future[int] {.async.} =
|
||||
if true:
|
||||
raise newException(ValueError, "")
|
||||
proc client3(): Future[int] {.async.} =
|
||||
await sleepAsync(100.milliseconds)
|
||||
result = 3
|
||||
|
||||
var f1 = client1() or client2()
|
||||
var f2 = client1() or client3()
|
||||
var f3 = client2() or client3()
|
||||
var f4 = client2() or client1()
|
||||
var f5 = client3() or client1()
|
||||
var f6 = client3() or client2()
|
||||
|
||||
result = (f1.finished() and not(f1.failed())) and
|
||||
(f2.finished() and not(f2.failed())) and
|
||||
(f3.finished() and f3.failed()) and
|
||||
(f4.finished() and f4.failed()) and
|
||||
(f5.finished() and not(f5.failed())) and
|
||||
(f6.finished() and f6.failed())
|
||||
|
||||
proc testCancelIter(): bool =
|
||||
var completed = 0
|
||||
|
||||
@ -907,6 +977,11 @@ suite "Future[T] behavior test suite":
|
||||
test "one() already completed test":
|
||||
check testOneCompleted() == true
|
||||
|
||||
test "or() test":
|
||||
check testOr() == true
|
||||
test "or() already completed test":
|
||||
check testOrCompleted() == true
|
||||
|
||||
test "cancel() async procedure test":
|
||||
check testCancelIter() == true
|
||||
test "cancelAndWait() test":
|
||||
|
Loading…
x
Reference in New Issue
Block a user