Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
public extension Task where Success == Never, Failure == Never {
/// Blueprint for a task that should be run, but not yet.
struct Blueprint<Output> {
public var priority: TaskPriority
public var operation: @Sendable () async throws -> Output
public init(
priority: TaskPriority = .medium,
operation: @escaping @Sendable () async throws -> Output
) {
self.priority = priority
self.operation = operation
}
}
}
public extension Task where Success == Never, Failure == Never {
/// Race for the first result by any of the provided tasks.
///
/// This will return the first valid result or throw the first thrown error by any task.
static func race<Output>(firstResolved tasks: [Blueprint<Output>]) async throws -> Output {
assert(!tasks.isEmpty, "You must race at least 1 task.")
return try await withThrowingTaskGroup(of: Output.self) { group -> Output in
for task in tasks {
group.addTask(priority: task.priority) {
try await task.operation()
}
}
defer { group.cancelAll() }
if let firstToResolve = try await group.next() {
return firstToResolve
} else {
// There will be at least 1 task.
fatalError("At least 1 task should be scheduled.")
}
}
}
/// Race for the first valid value.
///
/// Ignores errors that may be thrown and waits for the first result.
/// If all tasks fail, returns `nil`.
static func race<Output>(firstValue tasks: [Blueprint<Output>]) async -> Output? {
return await withThrowingTaskGroup(of: Output.self) { group -> Output? in
for task in tasks {
group.addTask(priority: task.priority) {
try await task.operation()
}
}
defer { group.cancelAll() }
while let nextResult = await group.nextResult() {
switch nextResult {
case .failure:
continue
case .success(let result):
return result
}
}
// If all the racing tasks error, we will reach this point.
return nil
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment