@@ -40,68 +40,80 @@ extension UnsafeAtomicState where State == DisposableState {
4040
4141/// A type-erased disposable that forwards operations to an underlying disposable.
4242public final class AnyDisposable : Disposable {
43- private let disposable : Disposable
44-
45- public var isDisposed : Bool {
46- return disposable . isDisposed
47- }
48-
49- public init ( _ disposable : Disposable ) {
50- self . disposable = disposable
43+ private enum Backing {
44+ case wrapping ( Disposable )
45+
46+ // We need to ability to release the closure. However, the way Swift packs multi-
47+ // payload enum discriminator via both extra inhabitants and unused bits may
48+ // result in corrupted reads even after masking. So an unsafe allocation is used
49+ // instead.
50+ case action ( UnsafeAtomicState < DisposableState > , UnsafeMutablePointer < ( ) -> Void > ? )
5151 }
5252
53- public func dispose( ) {
54- disposable. dispose ( )
55- }
56- }
57-
58- /// A disposable that only flips `isDisposed` upon disposal, and performs no other
59- /// work.
60- public final class SimpleDisposable : Disposable {
61- private var state = UnsafeAtomicState ( DisposableState . active)
53+ private let base : Backing
6254
6355 public var isDisposed : Bool {
64- return state. is ( . disposed)
56+ switch base {
57+ case let . action( state, _) :
58+ return state. is ( . disposed)
59+ case let . wrapping( disposable) :
60+ return disposable. isDisposed
61+ }
6562 }
6663
67- public init ( ) { }
64+ /// Create a disposable which runs the given action upon disposal.
65+ ///
66+ /// - parameters:
67+ /// - action: A closure to run when calling `dispose()`.
68+ public init ( _ action: @escaping ( ) -> Void ) {
69+ let actionPointer = UnsafeMutablePointer < ( ) -> Void > . allocate ( capacity: 1 )
70+ actionPointer. initialize ( to: action)
6871
69- public func dispose( ) {
70- _ = state. tryDispose ( )
72+ base = . action( UnsafeAtomicState ( DisposableState . active) , actionPointer)
7173 }
7274
73- deinit {
74- state. deinitialize ( )
75+ /// Create a disposable.
76+ public init ( ) {
77+ base = . action( UnsafeAtomicState ( DisposableState . active) , nil )
7578 }
76- }
77-
78- /// A disposable that will run an action upon disposal.
79- public final class ActionDisposable : Disposable {
80- private var action : ( ( ) -> Void ) ?
81- private var state : UnsafeAtomicState < DisposableState >
8279
83- public var isDisposed : Bool {
84- return state. is ( . disposed)
85- }
86-
87- /// Initialize the disposable to run the given action upon disposal.
80+ /// Create a disposable which wraps the given disposable.
8881 ///
8982 /// - parameters:
90- /// - action: A closure to run when calling `dispose()`.
91- public init ( action: @escaping ( ) -> Void ) {
92- self . action = action
93- self . state = UnsafeAtomicState ( DisposableState . active)
83+ /// - disposable: The disposable to be wrapped.
84+ public init ( _ disposable: Disposable ) {
85+ base = . wrapping( disposable)
9486 }
9587
96- public func dispose( ) {
97- if state. tryDispose ( ) {
98- action ? ( )
99- action = nil
88+ deinit {
89+ switch base {
90+ case let . action( state, actionPointer) :
91+ if !state. is ( . disposed) {
92+ actionPointer? . deinitialize ( )
93+ actionPointer? . deallocate ( capacity: 1 )
94+ }
95+
96+ state. deinitialize ( )
97+
98+ case . wrapping:
99+ break
100100 }
101101 }
102102
103- deinit {
104- state. deinitialize ( )
103+ public func dispose( ) {
104+ switch base {
105+ case let . action( state, actionPointer) :
106+ if state. tryDispose ( ) {
107+ if let pointer = actionPointer {
108+ pointer. pointee ( )
109+ pointer. deinitialize ( )
110+ pointer. deallocate ( capacity: 1 )
111+ }
112+ }
113+
114+ case let . wrapping( disposable) :
115+ disposable. dispose ( )
116+ }
105117 }
106118}
107119
@@ -179,7 +191,7 @@ public final class CompositeDisposable: Disposable {
179191 guard disposables != nil else { return nil }
180192
181193 let token = disposables!. insert ( d)
182- return ActionDisposable { [ weak self] in
194+ return AnyDisposable { [ weak self] in
183195 self ? . disposables. modify {
184196 $0? . remove ( using: token)
185197 }
@@ -197,12 +209,51 @@ public final class CompositeDisposable: Disposable {
197209 /// `disposable` is `nil`.
198210 @discardableResult
199211 public func add( _ action: @escaping ( ) -> Void ) -> Disposable ? {
200- return add ( ActionDisposable ( action : action) )
212+ return add ( AnyDisposable ( action) )
201213 }
202214
203215 deinit {
204216 state. deinitialize ( )
205217 }
218+
219+ /// Adds the right-hand-side disposable to the left-hand-side
220+ /// `CompositeDisposable`.
221+ ///
222+ /// ````
223+ /// disposable += producer
224+ /// .filter { ... }
225+ /// .map { ... }
226+ /// .start(observer)
227+ /// ````
228+ ///
229+ /// - parameters:
230+ /// - lhs: Disposable to add to.
231+ /// - rhs: Disposable to add.
232+ ///
233+ /// - returns: An instance of `DisposableHandle` that can be used to opaquely
234+ /// remove the disposable later (if desired).
235+ @discardableResult
236+ public static func += ( lhs: CompositeDisposable , rhs: Disposable ? ) -> Disposable ? {
237+ return lhs. add ( rhs)
238+ }
239+
240+ /// Adds the right-hand-side `ActionDisposable` to the left-hand-side
241+ /// `CompositeDisposable`.
242+ ///
243+ /// ````
244+ /// disposable += { ... }
245+ /// ````
246+ ///
247+ /// - parameters:
248+ /// - lhs: Disposable to add to.
249+ /// - rhs: Closure to add as a disposable.
250+ ///
251+ /// - returns: An instance of `DisposableHandle` that can be used to opaquely
252+ /// remove the disposable later (if desired).
253+ @discardableResult
254+ public static func += ( lhs: CompositeDisposable , rhs: @escaping ( ) -> ( ) ) -> Disposable ? {
255+ return lhs. add ( rhs)
256+ }
206257}
207258
208259/// A disposable that, upon deinitialization, will automatically dispose of
@@ -246,6 +297,44 @@ extension ScopedDisposable where Inner == AnyDisposable {
246297 }
247298}
248299
300+ extension ScopedDisposable where Inner == CompositeDisposable {
301+ /// Adds the right-hand-side disposable to the left-hand-side
302+ /// `ScopedDisposable<CompositeDisposable>`.
303+ ///
304+ /// ````
305+ /// disposable += { ... }
306+ /// ````
307+ ///
308+ /// - parameters:
309+ /// - lhs: Disposable to add to.
310+ /// - rhs: Disposable to add.
311+ ///
312+ /// - returns: An instance of `DisposableHandle` that can be used to opaquely
313+ /// remove the disposable later (if desired).
314+ @discardableResult
315+ public static func += ( lhs: ScopedDisposable < CompositeDisposable > , rhs: Disposable ? ) -> Disposable ? {
316+ return lhs. inner. add ( rhs)
317+ }
318+
319+ /// Adds the right-hand-side disposable to the left-hand-side
320+ /// `ScopedDisposable<CompositeDisposable>`.
321+ ///
322+ /// ````
323+ /// disposable += { ... }
324+ /// ````
325+ ///
326+ /// - parameters:
327+ /// - lhs: Disposable to add to.
328+ /// - rhs: Closure to add as a disposable.
329+ ///
330+ /// - returns: An instance of `DisposableHandle` that can be used to opaquely
331+ /// remove the disposable later (if desired).
332+ @discardableResult
333+ public static func += ( lhs: ScopedDisposable < CompositeDisposable > , rhs: @escaping ( ) -> ( ) ) -> Disposable ? {
334+ return lhs. inner. add ( rhs)
335+ }
336+ }
337+
249338/// A disposable that disposes of its wrapped disposable, and allows its
250339/// wrapped disposable to be replaced.
251340public final class SerialDisposable : Disposable {
@@ -293,78 +382,3 @@ public final class SerialDisposable: Disposable {
293382 state. deinitialize ( )
294383 }
295384}
296-
297- /// Adds the right-hand-side disposable to the left-hand-side
298- /// `CompositeDisposable`.
299- ///
300- /// ````
301- /// disposable += producer
302- /// .filter { ... }
303- /// .map { ... }
304- /// .start(observer)
305- /// ````
306- ///
307- /// - parameters:
308- /// - lhs: Disposable to add to.
309- /// - rhs: Disposable to add.
310- ///
311- /// - returns: An instance of `DisposableHandle` that can be used to opaquely
312- /// remove the disposable later (if desired).
313- @discardableResult
314- public func += ( lhs: CompositeDisposable , rhs: Disposable ? ) -> Disposable ? {
315- return lhs. add ( rhs)
316- }
317-
318- /// Adds the right-hand-side `ActionDisposable` to the left-hand-side
319- /// `CompositeDisposable`.
320- ///
321- /// ````
322- /// disposable += { ... }
323- /// ````
324- ///
325- /// - parameters:
326- /// - lhs: Disposable to add to.
327- /// - rhs: Closure to add as a disposable.
328- ///
329- /// - returns: An instance of `DisposableHandle` that can be used to opaquely
330- /// remove the disposable later (if desired).
331- @discardableResult
332- public func += ( lhs: CompositeDisposable , rhs: @escaping ( ) -> ( ) ) -> Disposable ? {
333- return lhs. add ( rhs)
334- }
335-
336- /// Adds the right-hand-side disposable to the left-hand-side
337- /// `ScopedDisposable<CompositeDisposable>`.
338- ///
339- /// ````
340- /// disposable += { ... }
341- /// ````
342- ///
343- /// - parameters:
344- /// - lhs: Disposable to add to.
345- /// - rhs: Disposable to add.
346- ///
347- /// - returns: An instance of `DisposableHandle` that can be used to opaquely
348- /// remove the disposable later (if desired).
349- @discardableResult
350- public func += ( lhs: ScopedDisposable < CompositeDisposable > , rhs: Disposable ? ) -> Disposable ? {
351- return lhs. inner. add ( rhs)
352- }
353-
354- /// Adds the right-hand-side disposable to the left-hand-side
355- /// `ScopedDisposable<CompositeDisposable>`.
356- ///
357- /// ````
358- /// disposable += { ... }
359- /// ````
360- ///
361- /// - parameters:
362- /// - lhs: Disposable to add to.
363- /// - rhs: Closure to add as a disposable.
364- ///
365- /// - returns: An instance of `DisposableHandle` that can be used to opaquely
366- /// remove the disposable later (if desired).
367- @discardableResult
368- public func += ( lhs: ScopedDisposable < CompositeDisposable > , rhs: @escaping ( ) -> ( ) ) -> Disposable ? {
369- return lhs. inner. add ( rhs)
370- }
0 commit comments