blob: 5df7423e79863398837f06ebc038b305f4a4d862 [file] [log] [blame]
////===----------------------------------------------------------------------===//
////
//// This source file is part of the Swift.org open source project
////
//// Copyright (c) 2020 Apple Inc. and the Swift project authors
//// Licensed under Apache License v2.0 with Runtime Library Exception
////
//// See https://swift.org/LICENSE.txt for license information
//// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
////
////===----------------------------------------------------------------------===//
import Swift
@_implementationOnly import _SwiftConcurrencyShims
// ==== Task Group -------------------------------------------------------------
extension Task {
/// Starts a new task group which provides a scope in which a dynamic number of
/// tasks may be spawned.
///
/// Tasks added to the group by `group.add()` will automatically be awaited on
/// when the scope exits. If the group exits by throwing, all added tasks will
/// be cancelled and their results discarded.
///
/// ### Implicit awaiting
/// When results of tasks added to the group need to be collected, one can
/// gather their results using the following pattern:
///
/// while let result = await group.next() {
/// // some accumulation logic (e.g. sum += result)
/// }
///
/// ### Cancellation
/// If an error is thrown out of the task group, all of its remaining tasks
/// will be cancelled and the `withGroup` call will rethrow that error.
///
/// Individual tasks throwing results in their corresponding `try group.next()`
/// call throwing, giving a chance to handle individual errors or letting the
/// error be rethrown by the group.
///
/// Postcondition:
/// Once `withGroup` returns it is guaranteed that the `group` is *empty*.
///
/// This is achieved in the following way:
/// - if the body returns normally:
/// - the group will await any not yet complete tasks,
/// - if any of those tasks throws, the remaining tasks will be cancelled,
/// - once the `withGroup` returns the group is guaranteed to be empty.
/// - if the body throws:
/// - all tasks remaining in the group will be automatically cancelled.
// TODO: Do we have to add a different group type to accommodate throwing
// tasks without forcing users to use Result? I can't think of how that
// could be propagated out of the callback body reasonably, unless we
// commit to doing multi-statement closure typechecking.
public static func withGroup<TaskResult, BodyResult>(
resultType: TaskResult.Type,
returning returnType: BodyResult.Type = BodyResult.self,
body: (inout Task.Group<TaskResult>) async throws -> BodyResult
) async rethrows -> BodyResult {
fatalError("\(#function) not implemented yet.")
}
/// A task group serves as storage for dynamically started tasks.
///
/// Its intended use is with the
/* @unmoveable */
public struct Group<TaskResult> {
/// No public initializers
private init() {}
// Swift will statically prevent this type from being copied or moved.
// For now, that implies that it cannot be used with generics.
/// Add a child task to the group.
///
/// ### Error handling
/// Operations are allowed to throw.
///
/// in which case the `await try next()`
/// invocation corresponding to the failed task will re-throw the given task.
///
/// - Parameters:
/// - overridingPriority: override priority of the operation task
/// - operation: operation to execute and add to the group
public mutating func add(
overridingPriority: Priority? = nil,
operation: () async throws -> TaskResult
) async {
fatalError("\(#function) not implemented yet.")
}
/// Add a child task and return a `Task.Handle` that can be used to manage it.
///
/// The task's result is accessible either via the returned `handle` or the
/// `group.next()` function (as any other `add`-ed task).
///
/// - Parameters:
/// - overridingPriority: override priority of the operation task
/// - operation: operation to execute and add to the group
public mutating func addWithHandle(
overridingPriority: Priority? = nil,
operation: () async throws -> TaskResult
) async -> Handle<TaskResult> {
fatalError("\(#function) not implemented yet.")
}
/// Wait for a child task to complete and return the result it returned,
/// or else return.
///
///
public mutating func next() async throws -> TaskResult? {
fatalError("\(#function) not implemented yet.")
}
/// Query whether the group has any remaining tasks.
///
/// Task groups are always empty upon entry to the `withGroup` body, and
/// become empty again when `withGroup` returns (either by awaiting on all
/// pending tasks or cancelling them).
///
/// - Returns: `true` if the group has no pending tasks, `false` otherwise.
public var isEmpty: Bool {
fatalError("\(#function) not implemented yet.")
}
/// Cancel all the remaining tasks in the group.
///
/// A cancelled group will not will NOT accept new tasks being added into it.
///
/// Any results, including errors thrown by tasks affected by this
/// cancellation, are silently discarded.
///
/// - SeeAlso: `Task.addCancellationHandler`
public mutating func cancelAll() {
fatalError("\(#function) not implemented yet.")
}
}
}