Skip to content

Commit

Permalink
Add a helper for setting or cascading optional promises (#2697)
Browse files Browse the repository at this point in the history
Motivation:

Many operations accept an optional promise. It's not uncommon to batch
operations (which may each have their own promise) and complete them
as a single operation. Combining these optional promises is slightly
tedious.

Modifications:

- Add an extension to `Optional` to set or cascade a promise
- If a promise exists, its result is cascaded to the provided promise.
  Otherwise the optional is set to the provided promise.

Result:

It's easier to combine optional promises.
  • Loading branch information
glbrntt committed Apr 9, 2024
1 parent 082ac21 commit b222c26
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
20 changes: 20 additions & 0 deletions Sources/NIOCore/EventLoopFuture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1840,3 +1840,23 @@ extension EventLoopPromise where Value == Void {
succeed(Void())
}
}

extension Optional {
/// Sets or cascades the future result of self to the provided promise, if present.
///
/// If `promise` is `nil` then this function is a no-op. Otherwise, if `self` is `nil` then
/// `self` is set to `promise`. If `self` isn't `nil` then its `futureResult` will be cascaded
/// to `promise`.
///
/// - Parameter promise: The promise to set or cascade to.
public mutating func setOrCascade<Value>(to promise: EventLoopPromise<Value>?) where Wrapped == EventLoopPromise<Value> {
guard let promise = promise else { return }

switch self {
case .none:
self = .some(promise)
case .some(let existing):
existing.futureResult.cascade(to: promise)
}
}
}
29 changes: 29 additions & 0 deletions Tests/NIOPosixTests/EventLoopFutureTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1541,4 +1541,33 @@ class EventLoopFutureTest : XCTestCase {
}
}

func testSetOrCascadeReplacesNil() throws {
let eventLoop = EmbeddedEventLoop()

var promise: EventLoopPromise<Void>? = nil
let other = eventLoop.makePromise(of: Void.self)
promise.setOrCascade(to: other)
XCTAssertNotNil(promise)
promise?.succeed()
try other.futureResult.wait()
}

func testSetOrCascadeCascadesToExisting() throws {
let eventLoop = EmbeddedEventLoop()

var promise: EventLoopPromise<Void>? = eventLoop.makePromise(of: Void.self)
let other = eventLoop.makePromise(of: Void.self)
promise.setOrCascade(to: other)
promise?.succeed()
try other.futureResult.wait()
}

func testSetOrCascadeNoOpOnNil() throws {
let eventLoop = EmbeddedEventLoop()

var promise: EventLoopPromise<Void>? = eventLoop.makePromise(of: Void.self)
promise.setOrCascade(to: nil)
XCTAssertNotNil(promise)
promise?.succeed()
}
}

0 comments on commit b222c26

Please sign in to comment.