@@ -79,32 +79,32 @@ extension Task {
7979 /// TODO: Define the details of task priority; It is likely to be a concept
8080 /// similar to Darwin Dispatch's QoS; bearing in mind that priority is not as
8181 /// 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
8489
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
9092 }
9193 }
9294}
9395
9496// ==== Task Handle ------------------------------------------------------------
9597
9698extension Task {
97-
9899 /// A task handle refers to an in-flight `Task`,
99100 /// allowing for potentially awaiting for its result or canceling it.
100101 ///
101102 /// It is not a programming error to drop a handle without awaiting or canceling it,
102103 /// i.e. the task will run regardless of the handle still being present or not.
103104 /// Dropping a handle however means losing the ability to await on the task's result
104105 /// and losing the ability to cancel it.
105- @_frozen
106106 public struct Handle < Success> {
107- private let task : Builtin . NativeObject
107+ let task : Builtin . NativeObject
108108
109109 /// Wait for the task to complete, returning (or throwing) its result.
110110 ///
@@ -121,7 +121,18 @@ extension Task {
121121 /// and throwing a specific error or using `checkCancellation` the error
122122 /// thrown out of the task will be re-thrown here.
123123 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+ }
125136 }
126137
127138 /// Attempt to cancel the task.
@@ -138,6 +149,78 @@ extension Task {
138149 }
139150}
140151
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+
141224// ==== Detached Tasks ---------------------------------------------------------
142225
143226extension Task {
@@ -172,9 +255,22 @@ extension Task {
172255 /// tasks result or `cancel` it.
173256 public static func runDetached< T> (
174257 priority: Priority = . default,
175- operation: ( ) async -> T
258+ operation: @escaping ( ) async -> T
176259 ) -> 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)
178274 }
179275
180276 /// Run given throwing `operation` as part of a new top-level task.
@@ -209,9 +305,24 @@ extension Task {
209305 /// throw the error the operation has thrown when awaited on.
210306 public static func runDetached< T> (
211307 priority: Priority = . default,
212- operation: ( ) async throws -> T
308+ operation: @escaping ( ) async throws -> T
213309 ) -> 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)
215326 }
216327}
217328
@@ -314,3 +425,48 @@ public func runAsync(_ asyncFun: @escaping () async -> ()) {
314425 let childTask = Builtin . createAsyncTask ( 0 , nil , asyncFun)
315426 runTask ( childTask. 0 )
316427}
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