@@ -10,6 +10,40 @@ public typealias DelayedExecution = (TimeInterval, @escaping () -> Void) -> Void
10
10
public typealias DelayedRunner = ( _ delay: TimeInterval , _ block: @escaping ( ) -> Void )
11
11
-> Cancellable
12
12
13
+ @_unavailableFromAsync ( message: " await the call to the @MainActor closure directly " )
14
+ @available ( iOS, introduced: 9.0 , deprecated: 13.0 , message: " Use MainActor.assumeIsolated instead. " )
15
+ private func backportedAssumeIsolatedToMainActor< T> (
16
+ _ operation: @MainActor ( ) throws -> T ,
17
+ file _: StaticString = #fileID, line _: UInt = #line
18
+ ) rethrows -> T where T: Sendable {
19
+ typealias YesActor = @MainActor ( ) throws -> T
20
+ typealias NoActor = ( ) throws -> T
21
+
22
+ assert ( Thread . isMainThread)
23
+ // To do the unsafe cast, we have to pretend it's @escaping.
24
+ return try withoutActuallyEscaping ( operation) {
25
+ ( _ fn: @escaping YesActor ) throws -> T in
26
+ let rawFn = unsafeBitCast ( fn, to: NoActor . self)
27
+ return try rawFn ( )
28
+ }
29
+ }
30
+
31
+ @_unavailableFromAsync ( message: " await the call to the @MainActor closure directly " )
32
+ public func assumeIsolatedToMainActor< T> (
33
+ _ operation: @MainActor ( ) throws -> T ,
34
+ file _: StaticString = #fileID, line _: UInt = #line
35
+ ) rethrows -> T where T: Sendable {
36
+ if #available( iOS 13 . 0 , tvOS 13 . 0 , * ) {
37
+ try MainActor . assumeIsolated {
38
+ try operation ( )
39
+ }
40
+ } else {
41
+ try backportedAssumeIsolatedToMainActor {
42
+ try operation ( )
43
+ }
44
+ }
45
+ }
46
+
13
47
public func onMainThread( _ block: @escaping ( ) -> Void ) {
14
48
if Thread . isMainThread {
15
49
block ( )
@@ -38,6 +72,19 @@ public func onMainThreadResult<T>(_ function: @escaping () -> Future<T>) -> Futu
38
72
return future
39
73
}
40
74
75
+ /// Executes a @MainActor closure by bypassing actor isolation checks.
76
+ ///
77
+ /// - Warning: Only use if you fully understand the memory safety implications.
78
+ @_unavailableFromAsync
79
+ @inlinable
80
+ @inline ( __always)
81
+ @_spi ( Unsafe)
82
+ public func runUnsafelyOnMainActor< T> ( _ body: @MainActor ( ) throws -> T ) rethrows -> T {
83
+ try withoutActuallyEscaping ( body) { fn in
84
+ try unsafeBitCast( fn, to: ( ( ) throws -> T) . self ) ( )
85
+ }
86
+ }
87
+
41
88
public func onMainThreadAsync( _ block: @escaping ( ) -> Void ) {
42
89
DispatchQueue . main. async ( execute: block)
43
90
}
0 commit comments