Skip to content

Commit 5c49da0

Browse files
committed
s/(ActionDisposable|SimpleDisposable)/AnyDisposable/g.
1 parent 2c329a3 commit 5c49da0

File tree

11 files changed

+186
-160
lines changed

11 files changed

+186
-160
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# master
22
*Please add new entries at the top.*
3+
1. `ActionDisposable` and `SimpleDisposable` have been folded into `AnyDisposable`. (#412, kudos to @andersio)
34

45
# 1.1.3
56
## Deprecation

Sources/Deprecations+Removals.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import Dispatch
33
import Result
44

55
// MARK: Unavailable methods in ReactiveSwift 2.0.
6+
extension AnyDisposable {
7+
@available(*, unavailable, renamed:"init(_:)")
8+
public convenience init(action: @escaping () -> Void) { fatalError() }
9+
}
10+
611
extension Lifetime {
712
@available(*, unavailable, renamed:"hasEnded")
813
public var isDisposed: Bool { fatalError() }
@@ -132,6 +137,12 @@ public func timer(interval: DispatchTimeInterval, on scheduler: DateScheduler) -
132137
public func timer(interval: DispatchTimeInterval, on scheduler: DateScheduler, leeway: DispatchTimeInterval) -> SignalProducer<Date, NoError> { fatalError() }
133138

134139
// MARK: Obsolete types in ReactiveSwift 2.0.
140+
@available(*, unavailable, renamed:"AnyDisposable")
141+
public typealias SimpleDisposable = AnyDisposable
142+
143+
@available(*, unavailable, renamed:"AnyDisposable")
144+
public typealias ActionDisposable = AnyDisposable
145+
135146
@available(*, unavailable, renamed:"Signal.Event")
136147
public typealias Event<Value, Error: Swift.Error> = Signal<Value, Error>.Event
137148

Sources/Disposable.swift

Lines changed: 135 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -40,68 +40,80 @@ extension UnsafeAtomicState where State == DisposableState {
4040

4141
/// A type-erased disposable that forwards operations to an underlying disposable.
4242
public 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.
251340
public 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-
}

Sources/Flatten.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ extension Signal where Value: SignalProducerProtocol, Error == Value.Error {
444444
func startNextIfNeeded() {
445445
while let producer = state.modify({ $0.dequeue() }) {
446446
let producerState = UnsafeAtomicState<ProducerState>(.starting)
447-
let deinitializer = ScopedDisposable(ActionDisposable(action: producerState.deinitialize))
447+
let deinitializer = ScopedDisposable(AnyDisposable(producerState.deinitialize))
448448

449449
producer.startWithSignal { signal, inner in
450450
let handle = disposable.add(inner)

Sources/FoundationExtensions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ extension Reactive where Base: NotificationCenter {
3535
observer.send(value: notification)
3636
}
3737

38-
return ActionDisposable {
38+
return AnyDisposable {
3939
base.removeObserver(notificationObserver)
4040
}
4141
}

0 commit comments

Comments
 (0)