|
| 1 | +import c |
| 2 | +import Cache |
| 3 | + |
| 4 | +/// A `TaskManager` is a cache for asynchronous tasks. |
| 5 | +open class TaskManager<Key: Hashable>: Cache<Key, Task<Sendable, Error>> { |
| 6 | + /// Initializes a new instance of `TaskManager`. |
| 7 | + /// |
| 8 | + /// - Parameter initialValues: A dictionary of initial key-value pairs to be added to the cache. |
| 9 | + public required init(initialValues: [Key: Value] = [:]) { |
| 10 | + super.init(initialValues: initialValues) |
| 11 | + } |
| 12 | + |
| 13 | + deinit { |
| 14 | + cancelAll() |
| 15 | + } |
| 16 | + |
| 17 | + /// Cancels a task for a given key. |
| 18 | + /// |
| 19 | + /// - Parameter key: The key for the task to be canceled. |
| 20 | + open func cancel(key: Key) { |
| 21 | + get(key)?.cancel() |
| 22 | + remove(key) |
| 23 | + } |
| 24 | + |
| 25 | + /// Cancels all tasks in the cache. |
| 26 | + open func cancelAll() { |
| 27 | + let allTasks = allValues |
| 28 | + |
| 29 | + allTasks.forEach { managedTask in |
| 30 | + cancel(key: managedTask.key) |
| 31 | + } |
| 32 | + } |
| 33 | + |
| 34 | + /// Adds a new task to the cache for a given key. |
| 35 | + /// |
| 36 | + /// - Parameters: |
| 37 | + /// - key: The key for the new task. |
| 38 | + /// - priority: The priority of the task. Default value is `nil`. |
| 39 | + /// - operation: The operation to be performed by the task. |
| 40 | + open func task( |
| 41 | + key: Key, |
| 42 | + priority: TaskPriority? = nil, |
| 43 | + operation: @escaping () async throws -> Sendable |
| 44 | + ) { |
| 45 | + cancel(key: key) |
| 46 | + |
| 47 | + let managedTask = Task(priority: priority) { |
| 48 | + try await operation() |
| 49 | + } |
| 50 | + |
| 51 | + set(value: managedTask, forKey: key) |
| 52 | + } |
| 53 | + |
| 54 | + /// Wait for the task with the given key to complete, but ignore its result. |
| 55 | + /// |
| 56 | + /// - Parameter key: The key of the task to wait for. |
| 57 | + open func wait(for key: Key) async throws { |
| 58 | + let _ = try await value(for: key, as: Sendable.self) |
| 59 | + } |
| 60 | + |
| 61 | + /// Wait for the result of the task with the given key. |
| 62 | + /// |
| 63 | + /// - Parameters: |
| 64 | + /// - key: The key of the task to get the result of. |
| 65 | + /// - type: The expected type of the result. |
| 66 | + /// |
| 67 | + /// - Returns: The result of the task, if it has completed and its result is of the expected type. |
| 68 | + /// |
| 69 | + /// - Throws: An `InvalidTypeError` if the task result is not of the expected type. |
| 70 | + open func value<Success: Sendable>( |
| 71 | + for key: Key, |
| 72 | + as type: Success.Type = Success.self |
| 73 | + ) async throws -> Success { |
| 74 | + let managedTask = try resolve(key) |
| 75 | + |
| 76 | + let value = try await managedTask.value |
| 77 | + |
| 78 | + guard let success = value as? Success else { |
| 79 | + throw c.InvalidTypeError(expectedType: type, actualValue: value) |
| 80 | + } |
| 81 | + |
| 82 | + return success |
| 83 | + } |
| 84 | +} |
0 commit comments