-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
74e065d
commit 7102a40
Showing
4 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// | ||
// Concurrency | ||
// Copyright © 2025 Space Code. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
// MARK: - ITaskFactory | ||
|
||
// swiftlint:disable attributes | ||
/// A protocol for creating and managing tasks with different configurations. | ||
/// Provides methods to create tasks tied to the current actor context or detached tasks | ||
/// that run independently of the current actor. | ||
public protocol ITaskFactory { | ||
/// Creates a task tied to the current actor context that can throw errors. | ||
/// - Parameters: | ||
/// - priority: The priority of the task (optional). | ||
/// - operation: An asynchronous operation to execute within the task. The operation | ||
/// inherits the current actor context and is isolated to that actor. | ||
/// - Returns: A `Task` object that wraps the result or error of the operation. | ||
func task<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> | ||
|
||
/// Creates a task tied to the current actor context that does not throw errors. | ||
/// - Parameters: | ||
/// - priority: The priority of the task (optional). | ||
/// - operation: An asynchronous operation to execute within the task. The operation | ||
/// inherits the current actor context and is isolated to that actor. | ||
/// - Returns: A `Task` object that wraps the result of the operation. | ||
func task<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> | ||
|
||
/// Creates a detached task that runs independently of the current actor context | ||
/// and can throw errors. | ||
/// - Parameters: | ||
/// - priority: The priority of the task (optional). | ||
/// - operation: An asynchronous operation to execute within the task. The operation | ||
/// is isolated and does not inherit the current actor context. | ||
/// - Returns: A `Task` object that wraps the result or error of the operation. | ||
func detached<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> | ||
|
||
/// Creates a detached task that runs independently of the current actor context | ||
/// and does not throw errors. | ||
/// - Parameters: | ||
/// - priority: The priority of the task (optional). | ||
/// - operation: An asynchronous operation to execute within the task. The operation | ||
/// is isolated and does not inherit the current actor context. | ||
/// - Returns: A `Task` object that wraps the result of the operation. | ||
func detached<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> | ||
} | ||
|
||
/// Default implementations for the `ITaskFactory` protocol. | ||
public extension ITaskFactory { | ||
/// Creates a task tied to the current actor context with a default priority | ||
/// that can throw errors. | ||
/// - Parameter operation: An asynchronous operation to execute within the task. | ||
/// - Returns: A `Task` object that wraps the result or error of the operation. | ||
func task<Success: Sendable>( | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> { | ||
task(priority: nil, operation: operation) | ||
} | ||
|
||
/// Creates a task tied to the current actor context with a default priority | ||
/// that does not throw errors. | ||
/// - Parameter operation: An asynchronous operation to execute within the task. | ||
/// - Returns: A `Task` object that wraps the result of the operation. | ||
func task<Success: Sendable>( | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> { | ||
task(priority: nil, operation: operation) | ||
} | ||
|
||
/// Creates a detached task with a default priority that runs independently | ||
/// of the current actor context and can throw errors. | ||
/// - Parameter operation: An asynchronous operation to execute within the task. | ||
/// - Returns: A `Task` object that wraps the result or error of the operation. | ||
func detached<Success: Sendable>( | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> { | ||
detached(priority: nil, operation: operation) | ||
} | ||
|
||
/// Creates a detached task with a default priority that runs independently | ||
/// of the current actor context and does not throw errors. | ||
/// - Parameter operation: An asynchronous operation to execute within the task. | ||
/// - Returns: A `Task` object that wraps the result of the operation. | ||
func detached<Success: Sendable>( | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> { | ||
detached(priority: nil, operation: operation) | ||
} | ||
} | ||
|
||
// swiftlint:enable attributes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// | ||
// Concurrency | ||
// Copyright © 2025 Space Code. All rights reserved. | ||
// | ||
|
||
public final class TaskFactory: ITaskFactory { | ||
// MARK: Initialization | ||
|
||
public init() {} | ||
|
||
// MARK: ITaskFactory | ||
|
||
// swiftlint:disable attributes | ||
public func task<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> { | ||
Task(priority: priority, operation: operation) | ||
} | ||
|
||
public func task<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> { | ||
Task(priority: priority, operation: operation) | ||
} | ||
|
||
public func detached<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> { | ||
Task.detached(priority: priority, operation: operation) | ||
} | ||
|
||
public func detached<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> { | ||
Task.detached(priority: priority, operation: operation) | ||
} | ||
// swiftlint:enable attributes | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// Concurrency | ||
// Copyright © 2025 Space Code. All rights reserved. | ||
// | ||
|
||
// MARK: - ITask | ||
|
||
/// A protocol representing a task that can be awaited until its execution completes. | ||
protocol ITask { | ||
/// Waits for the `Task` to complete by retrieving its result. | ||
func wait() async | ||
} | ||
|
||
// MARK: - Task + ITask | ||
|
||
/// Extends the `Task` type to conform to the `ITask` protocol. | ||
extension Task: ITask { | ||
func wait() async { | ||
_ = await result | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// | ||
// Concurrency | ||
// Copyright © 2025 Space Code. All rights reserved. | ||
// | ||
|
||
import Concurrency | ||
import Foundation | ||
|
||
// MARK: - TestTaskFactory | ||
|
||
public final class TestTaskFactory: @unchecked Sendable { | ||
// MARK: Properties | ||
|
||
private let lock = NSLock() | ||
private var tasks: [ITask] = [] | ||
|
||
// MARK: Intialization | ||
|
||
public init() {} | ||
|
||
// MARK: Public | ||
|
||
/// Waits until all tasks in the queue have completed execution. | ||
public func waitUntilIdle() async { | ||
while let task = popTask() { | ||
await task.wait() | ||
} | ||
} | ||
|
||
// MARK: Private | ||
|
||
private func addTask(_ task: ITask) { | ||
lock.lock() | ||
defer { lock.unlock() } | ||
tasks.append(task) | ||
} | ||
|
||
private func popTask() -> ITask? { | ||
lock.lock() | ||
defer { lock.unlock() } | ||
return tasks.popLast() | ||
} | ||
} | ||
|
||
// MARK: ITaskFactory | ||
|
||
extension TestTaskFactory: ITaskFactory { | ||
public func task<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> { | ||
let task = Task(priority: priority, operation: operation) | ||
addTask(task) | ||
return task | ||
} | ||
|
||
public func task<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> { | ||
let task = Task(priority: priority, operation: operation) | ||
addTask(task) | ||
return task | ||
} | ||
|
||
public func detached<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async throws -> Success | ||
) -> Task<Success, Error> { | ||
let task = Task.detached(priority: priority, operation: operation) | ||
addTask(task) | ||
return task | ||
} | ||
|
||
public func detached<Success: Sendable>( | ||
priority: TaskPriority?, | ||
@_inheritActorContext operation: sending @escaping @isolated(any) () async -> Success | ||
) -> Task<Success, Never> { | ||
let task = Task.detached(priority: priority, operation: operation) | ||
addTask(task) | ||
return task | ||
} | ||
} |