@@ -79,32 +79,32 @@ extension Task {
79
79
/// TODO: Define the details of task priority; It is likely to be a concept
80
80
/// similar to Darwin Dispatch's QoS; bearing in mind that priority is not as
81
81
/// much of a thing on other platforms (i.e. server side Linux systems).
82
- public struct Priority : Comparable {
83
- public static let `default` : Task . Priority = . init( ) // TODO: replace with actual values
82
+ public enum Priority : Int , Comparable {
83
+ case userInteractive = 0x21
84
+ case userInitiated = 0x19
85
+ case `default` = 0x15
86
+ case utility = 0x11
87
+ case background = 0x09
88
+ case unspecified = 0x00
84
89
85
- // TODO: specifics of implementation are not decided yet
86
- private let __value : Int = 0
87
-
88
- public static func < ( lhs: Self , rhs: Self ) -> Bool {
89
- lhs. __value < rhs. __value
90
+ public static func < ( lhs: Priority , rhs: Priority ) -> Bool {
91
+ lhs. rawValue < rhs. rawValue
90
92
}
91
93
}
92
94
}
93
95
94
96
// ==== Task Handle ------------------------------------------------------------
95
97
96
98
extension Task {
97
-
98
99
/// A task handle refers to an in-flight `Task`,
99
100
/// allowing for potentially awaiting for its result or canceling it.
100
101
///
101
102
/// It is not a programming error to drop a handle without awaiting or canceling it,
102
103
/// i.e. the task will run regardless of the handle still being present or not.
103
104
/// Dropping a handle however means losing the ability to await on the task's result
104
105
/// and losing the ability to cancel it.
105
- @_frozen
106
106
public struct Handle < Success> {
107
- private let task : Builtin . NativeObject
107
+ let task : Builtin . NativeObject
108
108
109
109
/// Wait for the task to complete, returning (or throwing) its result.
110
110
///
@@ -121,7 +121,18 @@ extension Task {
121
121
/// and throwing a specific error or using `checkCancellation` the error
122
122
/// thrown out of the task will be re-thrown here.
123
123
public func get( ) async throws -> Success {
124
- fatalError ( " \( #function) not implemented yet. " )
124
+ let rawResult = taskFutureWait (
125
+ on: task, waiting: Builtin . getCurrentAsyncTask ( ) )
126
+ switch TaskFutureWaitResult < Success > ( raw: rawResult) {
127
+ case . executing:
128
+ fatalError ( " don't know how to synchronously return " )
129
+
130
+ case . success( let result) :
131
+ return result
132
+
133
+ case . failure( let error) :
134
+ throw error
135
+ }
125
136
}
126
137
127
138
/// Attempt to cancel the task.
@@ -138,6 +149,78 @@ extension Task {
138
149
}
139
150
}
140
151
152
+ // ==== Job Flags --------------------------------------------------------------
153
+
154
+ extension Task {
155
+ /// Flags for schedulable jobs.
156
+ ///
157
+ /// This is a port of the C++ FlagSet.
158
+ struct JobFlags {
159
+ /// Kinds of schedulable jobs.
160
+ enum Kind : Int {
161
+ case task = 0
162
+ } ;
163
+
164
+ /// The actual bit representation of these flags.
165
+ var bits : Int = 0
166
+
167
+ /// The kind of job described by these flags.
168
+ var kind : Kind {
169
+ get {
170
+ Kind ( rawValue: bits & 0xFF ) !
171
+ }
172
+
173
+ set {
174
+ bits = ( bits & ~ 0xFF ) | newValue. rawValue
175
+ }
176
+ }
177
+
178
+ /// Whether this is an asynchronous task.
179
+ var isAsyncTask : Bool { kind == . task }
180
+
181
+ /// The priority given to the job.
182
+ var priority : Priority {
183
+ get {
184
+ Priority ( rawValue: ( bits & 0xFF00 ) >> 8 ) !
185
+ }
186
+
187
+ set {
188
+ bits = ( bits & ~ 0xFF00 ) | ( newValue. rawValue << 8 )
189
+ }
190
+ }
191
+
192
+ /// Whether this is a child task.
193
+ var isChildTask : Bool {
194
+ get {
195
+ ( bits & ( 1 << 24 ) ) != 0
196
+ }
197
+
198
+ set {
199
+ if newValue {
200
+ bits = bits | 1 << 24
201
+ } else {
202
+ bits = ( bits & ~ ( 1 << 24 ) )
203
+ }
204
+ }
205
+ }
206
+
207
+ /// Whether this is a future.
208
+ var isFuture : Bool {
209
+ get {
210
+ ( bits & ( 1 << 25 ) ) != 0
211
+ }
212
+
213
+ set {
214
+ if newValue {
215
+ bits = bits | 1 << 25
216
+ } else {
217
+ bits = ( bits & ~ ( 1 << 25 ) )
218
+ }
219
+ }
220
+ }
221
+ }
222
+ }
223
+
141
224
// ==== Detached Tasks ---------------------------------------------------------
142
225
143
226
extension Task {
@@ -172,9 +255,22 @@ extension Task {
172
255
/// tasks result or `cancel` it.
173
256
public static func runDetached< T> (
174
257
priority: Priority = . default,
175
- operation: ( ) async -> T
258
+ operation: @escaping ( ) async -> T
176
259
) -> Handle < T > {
177
- fatalError ( " \( #function) not implemented yet. " )
260
+ // Set up the job flags for a new task.
261
+ var flags = JobFlags ( )
262
+ flags. kind = . task
263
+ flags. priority = priority
264
+ flags. isFuture = true
265
+
266
+ // Create the asynchronous task future.
267
+ let ( task, context) =
268
+ Builtin . createAsyncTaskFuture ( flags. bits, nil , operation)
269
+
270
+ // FIXME: Launch the task on an executor... somewhere....
271
+ runTask ( task)
272
+
273
+ return Handle < T > ( task: task)
178
274
}
179
275
180
276
/// Run given throwing `operation` as part of a new top-level task.
@@ -209,9 +305,24 @@ extension Task {
209
305
/// throw the error the operation has thrown when awaited on.
210
306
public static func runDetached< T> (
211
307
priority: Priority = . default,
212
- operation: ( ) async throws -> T
308
+ operation: @escaping ( ) async throws -> T
213
309
) -> Handle < T > {
214
- fatalError ( " \( #function) not implemented yet. " )
310
+ // Set up the job flags for a new task.
311
+ var flags = JobFlags ( )
312
+ flags. kind = . task
313
+ flags. priority = priority
314
+ flags. isFuture = true
315
+
316
+ // Create the asynchronous task future.
317
+ let ( task, context) =
318
+ Builtin . createAsyncTaskFuture ( flags. bits, nil , operation)
319
+
320
+ print ( task)
321
+
322
+ // FIXME: Launch the task on an executor... somewhere....
323
+ runTask ( task)
324
+
325
+ return Handle < T > ( task: task)
215
326
}
216
327
}
217
328
@@ -314,3 +425,48 @@ public func runAsync(_ asyncFun: @escaping () async -> ()) {
314
425
let childTask = Builtin . createAsyncTask ( 0 , nil , asyncFun)
315
426
runTask ( childTask. 0 )
316
427
}
428
+
429
+ /// Describes the result of waiting for a future.
430
+ enum TaskFutureWaitResult < T> {
431
+ /// The future is still executing, and our waiting task has been placed
432
+ /// on its queue for when the future completes.
433
+ case executing
434
+
435
+ /// The future has succeeded with the given value.
436
+ case success( T )
437
+
438
+ /// The future has thrown the given error.
439
+ case failure( Error )
440
+
441
+ /// Initialize this instance from a raw result, taking any instance within
442
+ /// that result.
443
+ init ( raw: RawTaskFutureWaitResult ) {
444
+ switch raw. kind {
445
+ case 0 :
446
+ self = . executing
447
+
448
+ case 1 :
449
+ // Take the value on success
450
+ let storagePtr = raw. storage. bindMemory ( to: T . self, capacity: 1 )
451
+ self = . success( UnsafeMutablePointer < T > ( mutating: storagePtr) . move ( ) )
452
+
453
+ case 2 :
454
+ // Take the error on error.
455
+ self = . failure( unsafeBitCast ( raw. storage, to: Error . self) )
456
+
457
+ default :
458
+ assert ( false )
459
+ self = . executing
460
+ }
461
+ }
462
+ }
463
+
464
+ struct RawTaskFutureWaitResult {
465
+ let kind : Int
466
+ let storage : UnsafeRawPointer
467
+ }
468
+
469
+ @_silgen_name ( " swift_task_future_wait " )
470
+ func taskFutureWait(
471
+ on task: Builtin . NativeObject , waiting waitingTask: Builtin . NativeObject
472
+ ) -> RawTaskFutureWaitResult
0 commit comments