@@ -87,7 +87,7 @@ public enum TaskExecutionState {
87
87
case finished
88
88
}
89
89
90
- fileprivate actor QueuedTask < TaskDescription: TaskDescriptionProtocol > {
90
+ public actor QueuedTask < TaskDescription: TaskDescriptionProtocol > {
91
91
/// Result of `executionTask` / the tasks in `executionTaskCreatedContinuation`.
92
92
/// See doc comment on `executionTask`.
93
93
enum ExecutionTaskFinishStatus {
@@ -147,14 +147,38 @@ fileprivate actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
147
147
/// Gets reset every time `executionTask` finishes.
148
148
nonisolated ( unsafe) private var cancelledToBeRescheduled : AtomicBool = . init( initialValue: false )
149
149
150
+ private nonisolated ( unsafe) var _isExecuting : AtomicBool = . init( initialValue: false )
151
+
152
+ /// Whether the task is currently executing or still queued to be executed later.
153
+ public nonisolated var isExecuting : Bool {
154
+ return _isExecuting. value
155
+ }
156
+
157
+ /// Wait for the task to finish.
158
+ ///
159
+ /// If the tasks that waits for this queued task to finished is cancelled, the QueuedTask will still continue
160
+ /// executing.
161
+ public func waitToFinish( ) async {
162
+ return await resultTask. value
163
+ }
164
+
165
+ /// Wait for the task to finish.
166
+ ///
167
+ /// If the tasks that waits for this queued task to finished is cancelled, the QueuedTask will also be cancelled.
168
+ /// This assumes that the caller of this method has unique control over the task and is the only one interested in its
169
+ /// value.
170
+ public func waitToFinishPropagatingCancellation( ) async {
171
+ return await resultTask. valuePropagatingCancellation
172
+ }
173
+
150
174
/// A callback that will be called when the task starts executing, is cancelled to be rescheduled, or when it finishes
151
175
/// execution.
152
- private let executionStateChangedCallback : ( @Sendable ( TaskExecutionState) async -> Void ) ?
176
+ private let executionStateChangedCallback : ( @Sendable ( QueuedTask , TaskExecutionState) async -> Void ) ?
153
177
154
178
init (
155
179
priority: TaskPriority ? = nil ,
156
180
description: TaskDescription ,
157
- executionStateChangedCallback: ( @Sendable ( TaskExecutionState) async -> Void ) ?
181
+ executionStateChangedCallback: ( @Sendable ( QueuedTask , TaskExecutionState) async -> Void ) ?
158
182
) async {
159
183
self . _priority = . init( initialValue: priority? . rawValue ?? Task . currentPriority. rawValue)
160
184
self . description = description
@@ -214,19 +238,21 @@ fileprivate actor QueuedTask<TaskDescription: TaskDescriptionProtocol> {
214
238
}
215
239
executionTask = task
216
240
executionTaskCreatedContinuation. yield ( task)
217
- await executionStateChangedCallback ? ( . executing)
241
+ _isExecuting. value = true
242
+ await executionStateChangedCallback ? ( self , . executing)
218
243
return await task. value
219
244
}
220
245
221
246
/// Implementation detail of `execute` that is called after `self.description.execute()` finishes.
222
247
private func finalizeExecution( ) async -> ExecutionTaskFinishStatus {
223
248
self . executionTask = nil
249
+ _isExecuting. value = false
224
250
if Task . isCancelled && self . cancelledToBeRescheduled. value {
225
- await executionStateChangedCallback ? ( . cancelledToBeRescheduled)
251
+ await executionStateChangedCallback ? ( self , . cancelledToBeRescheduled)
226
252
self . cancelledToBeRescheduled. value = false
227
253
return ExecutionTaskFinishStatus . cancelledToBeRescheduled
228
254
} else {
229
- await executionStateChangedCallback ? ( . finished)
255
+ await executionStateChangedCallback ? ( self , . finished)
230
256
return ExecutionTaskFinishStatus . terminated
231
257
}
232
258
}
@@ -327,8 +353,10 @@ public actor TaskScheduler<TaskDescription: TaskDescriptionProtocol> {
327
353
public func schedule(
328
354
priority: TaskPriority ? = nil ,
329
355
_ taskDescription: TaskDescription ,
330
- @_inheritActorContext executionStateChangedCallback: ( @Sendable ( TaskExecutionState) async -> Void ) ? = nil
331
- ) async -> Task < Void , Never > {
356
+ @_inheritActorContext executionStateChangedCallback: (
357
+ @Sendable ( QueuedTask < TaskDescription > , TaskExecutionState ) async -> Void
358
+ ) ? = nil
359
+ ) async -> QueuedTask < TaskDescription > {
332
360
let queuedTask = await QueuedTask (
333
361
priority: priority,
334
362
description: taskDescription,
@@ -341,7 +369,7 @@ public actor TaskScheduler<TaskDescription: TaskDescriptionProtocol> {
341
369
// queued task.
342
370
await self . poke ( )
343
371
}
344
- return queuedTask. resultTask
372
+ return queuedTask
345
373
}
346
374
347
375
/// Trigger all queued tasks to update their priority.
0 commit comments