From 653eacd6e1c66b0816cc7f209ae7e978a06c4b8e Mon Sep 17 00:00:00 2001 From: Pawan Joshi Date: Wed, 15 Jan 2020 21:32:10 +0530 Subject: [PATCH] swiftformatted code. v5 --- .../Contents.swift | 25 +-- .../Contents.swift | 7 +- .../Contents.swift | 2 +- .../Contents.swift | 8 +- .../Contents.swift | 5 +- Sources/Atomic.swift | 3 +- Sources/Bindable.swift | 34 ++- Sources/Connectable.swift | 21 +- Sources/Deallocatable.swift | 40 ++-- Sources/Deprecations.swift | 32 +-- Sources/Disposable.swift | 98 ++++----- Sources/ExecutionContext.swift | 22 +- Sources/LoadingProperty.swift | 31 ++- Sources/LoadingSignal.swift | 144 ++++++------- Sources/Lock.swift | 2 - Sources/ObservableObject.swift | 48 +++-- Sources/Observer.swift | 23 +-- Sources/Property.swift | 26 ++- Sources/Published.swift | 45 ++-- Sources/Reactive.swift | 28 ++- Sources/Scheduler.swift | 5 +- Sources/Signal.Event.swift | 11 +- Sources/Signal.swift | 26 +-- Sources/SignalProtocol+Arities.swift | 181 ++++++++-------- Sources/SignalProtocol+Combining.swift | 54 +++-- Sources/SignalProtocol+ErrorHandling.swift | 36 ++-- Sources/SignalProtocol+Event.swift | 18 +- Sources/SignalProtocol+Filtering.swift | 45 ++-- Sources/SignalProtocol+Monad.swift | 48 ++--- Sources/SignalProtocol+Optional.swift | 13 +- Sources/SignalProtocol+Result.swift | 20 +- Sources/SignalProtocol+Sequence.swift | 8 +- Sources/SignalProtocol+Threading.swift | 3 +- Sources/SignalProtocol+Transforming.swift | 19 +- Sources/SignalProtocol+Utilities.swift | 63 +++--- Sources/SignalProtocol.swift | 26 +-- Sources/Subjects.swift | 33 ++- Sources/Subscriber.swift | 2 - Sources/Subscribers/Accumulator.swift | 32 ++- Sources/Subscribers/Completion.swift | 1 - Sources/Subscribers/Demand.swift | 4 +- Sources/Subscribers/Sink.swift | 22 +- Tests/LinuxMain.swift | 4 +- Tests/ReactiveKitTests/PropertyTests.swift | 46 ++--- Tests/ReactiveKitTests/Scheduler.swift | 3 +- Tests/ReactiveKitTests/SignalTests.swift | 154 +++++++------- Tests/ReactiveKitTests/Stress.swift | 22 +- Tests/ReactiveKitTests/SubjectTests.swift | 195 +++++++++--------- 48 files changed, 781 insertions(+), 957 deletions(-) diff --git a/Playground.playground/Pages/Creating Signals.xcplaygroundpage/Contents.swift b/Playground.playground/Pages/Creating Signals.xcplaygroundpage/Contents.swift index f596a10..ce3b58f 100644 --- a/Playground.playground/Pages/Creating Signals.xcplaygroundpage/Contents.swift +++ b/Playground.playground/Pages/Creating Signals.xcplaygroundpage/Contents.swift @@ -1,8 +1,8 @@ //: [Previous](@previous) import Foundation -import ReactiveKit import PlaygroundSupport +import ReactiveKit PlaygroundPage.current.needsIndefiniteExecution = true @@ -10,24 +10,24 @@ PlaygroundPage.current.needsIndefiniteExecution = true //: Uncomment the `observe { ... }` line to explore the behaviour! SafeSignal(just: "Jim") -//.observe { print($0) } +// .observe { print($0) } SafeSignal(just: "Jim after 1 second", after: 1) -//.observe { print($0) } +// .observe { print($0) } SafeSignal(sequence: [1, 2, 3]) -//.observe { print($0) } +// .observe { print($0) } SafeSignal(sequence: [1, 2, 3], interval: 1) -//.observe { print($0) } +// .observe { print($0) } SafeSignal(sequence: 1..., interval: 1) -//.observe { print($0) } +// .observe { print($0) } SafeSignal(performing: { - (0...1000).reduce(0, +) + (0 ... 1000).reduce(0, +) }) -//.observe { print($0) } +// .observe { print($0) } Signal(evaluating: { if let file = try? String(contentsOf: URL(fileURLWithPath: "list.txt")) { @@ -36,12 +36,12 @@ Signal(evaluating: { return .failure(NSError(domain: "No such file", code: 0, userInfo: nil)) } }) -//.observe { print($0) } +// .observe { print($0) } Signal(catching: { try String(contentsOf: URL(string: "https://pokeapi.co/api/v2/pokemon/ditto/")!, encoding: .utf8) }) -//.observe { print($0) } +// .observe { print($0) } Signal { observer in observer.receive(1) @@ -51,13 +51,14 @@ Signal { observer in print("disposed") } } -//.observe { print($0) } + +// .observe { print($0) } var didTapReload: () -> Void = {} let reloadTaps = Signal(takingOver: &didTapReload) reloadTaps -//.observeNext { print("reload") } +// .observeNext { print("reload") } didTapReload() didTapReload() diff --git a/Playground.playground/Pages/Exploration.xcplaygroundpage/Contents.swift b/Playground.playground/Pages/Exploration.xcplaygroundpage/Contents.swift index 848250c..5923753 100644 --- a/Playground.playground/Pages/Exploration.xcplaygroundpage/Contents.swift +++ b/Playground.playground/Pages/Exploration.xcplaygroundpage/Contents.swift @@ -1,7 +1,7 @@ //: Playground - noun: a place where people can play -import ReactiveKit import PlaygroundSupport +import ReactiveKit //: Explore ReactiveKit here @@ -9,8 +9,7 @@ enum MyError: Error { case unknown } -let a = Signal(sequence: 0...4, interval: 0.5) -let b = SafeSignal(sequence: 0...2, interval: 2) +let a = Signal(sequence: 0 ... 4, interval: 0.5) +let b = SafeSignal(sequence: 0 ... 2, interval: 2) b.concat(with: b) - diff --git a/Playground.playground/Pages/Observing Signals.xcplaygroundpage/Contents.swift b/Playground.playground/Pages/Observing Signals.xcplaygroundpage/Contents.swift index 0442f09..7d84334 100644 --- a/Playground.playground/Pages/Observing Signals.xcplaygroundpage/Contents.swift +++ b/Playground.playground/Pages/Observing Signals.xcplaygroundpage/Contents.swift @@ -1,8 +1,8 @@ //: [Previous](@previous) import Foundation -import ReactiveKit import PlaygroundSupport +import ReactiveKit PlaygroundPage.current.needsIndefiniteExecution = true diff --git a/Playground.playground/Pages/Transforming Signals.xcplaygroundpage/Contents.swift b/Playground.playground/Pages/Transforming Signals.xcplaygroundpage/Contents.swift index c38a9e9..d199c67 100644 --- a/Playground.playground/Pages/Transforming Signals.xcplaygroundpage/Contents.swift +++ b/Playground.playground/Pages/Transforming Signals.xcplaygroundpage/Contents.swift @@ -1,8 +1,8 @@ //: [Previous](@previous) import Foundation -import ReactiveKit import PlaygroundSupport +import ReactiveKit PlaygroundPage.current.needsIndefiniteExecution = true @@ -20,7 +20,6 @@ pokemons .map { $0.uppercased() } // .observe { print($0) } - // If we are interested only in some elements of the signal, for // example in Pokemons whose name starts with "S", we can use the filter operator: @@ -109,7 +108,6 @@ pokemonDetails // Try commenting out `.shareReplay()` line and see what happens in that case! - // There are many more operators on signals. Let's go through few of them. // When we are interested only in the first few elements, we can apply `take(first:)` operator: @@ -136,7 +134,7 @@ pokemons // in our case into the name, ignoring the number. let aPokemonEverySecond = pokemons - .zip(with: SafeSignal(sequence: 0..., interval: 1)) { name, index in name } + .zip(with: SafeSignal(sequence: 0..., interval: 1)) { name, _ in name } aPokemonEverySecond // .observe { print($0) } @@ -152,7 +150,7 @@ aPokemonEverySecond // from the two signals. aPokemonEverySecond - .combineLatest(with: SafeSignal(sequence: 0...6, interval: 0.5)) + .combineLatest(with: SafeSignal(sequence: 0 ... 6, interval: 0.5)) .observe { print($0) } //: [Next](@next) diff --git a/Playground.playground/Pages/Working with UI.xcplaygroundpage/Contents.swift b/Playground.playground/Pages/Working with UI.xcplaygroundpage/Contents.swift index 7a8a3a0..2434e73 100644 --- a/Playground.playground/Pages/Working with UI.xcplaygroundpage/Contents.swift +++ b/Playground.playground/Pages/Working with UI.xcplaygroundpage/Contents.swift @@ -1,8 +1,8 @@ //: [Previous](@previous) import Foundation -import ReactiveKit import PlaygroundSupport +import ReactiveKit import UIKit PlaygroundPage.current.needsIndefiniteExecution = true @@ -33,7 +33,8 @@ class PokeProfile: UIView { addSubview(stackView) backgroundColor = .white } - required init?(coder aDecoder: NSCoder) { fatalError() } + + required init?(coder _: NSCoder) { fatalError() } } // Open Assistent Editor to see the view! diff --git a/Sources/Atomic.swift b/Sources/Atomic.swift index a8c2ae5..8891db0 100644 --- a/Sources/Atomic.swift +++ b/Sources/Atomic.swift @@ -9,12 +9,11 @@ import Foundation final class Atomic { - private var _value: T private let lock: NSLocking init(_ value: T, lock: NSLocking = NSRecursiveLock()) { - self._value = value + _value = value self.lock = lock } diff --git a/Sources/Bindable.swift b/Sources/Bindable.swift index 96ddd91..75fd36e 100644 --- a/Sources/Bindable.swift +++ b/Sources/Bindable.swift @@ -26,17 +26,15 @@ import Foundation /// Bindable is like an observer, but knows to manage the subscription by itself. public protocol BindableProtocol { - /// Type of the received elements. associatedtype Element - + /// Establish a one-way binding between the signal and the receiver. /// - Warning: You are recommended to use `bind(to:)` on the signal when binding. func bind(signal: Signal) -> Disposable } extension SignalProtocol where Error == Never { - /// Establish a one-way binding between the source and the bindable. /// - Parameter bindable: A binding target that will receive signal events. /// - Returns: A disposable that can cancel the binding. @@ -44,7 +42,7 @@ extension SignalProtocol where Error == Never { public func bind(to bindable: B) -> Disposable where B.Element == Element { return bindable.bind(signal: toSignal()) } - + /// Establish a one-way binding between the source and the bindable. /// - Parameter bindable: A binding target that will receive signal events. /// - Returns: A disposable that can cancel the binding. @@ -55,7 +53,6 @@ extension SignalProtocol where Error == Never { } extension BindableProtocol where Self: SignalProtocol, Self.Error == Never { - /// Establish a two-way binding between the source and the bindable. /// - Parameter target: A binding target that will receive events from /// the receiver and a source that will send events to the receiver. @@ -70,7 +67,6 @@ extension BindableProtocol where Self: SignalProtocol, Self.Error == Never { } extension SignalProtocol where Error == Never { - /// Bind the receiver to the target using the given setter closure. Closure is /// called whenever the signal emits `next` event. /// @@ -85,11 +81,10 @@ extension SignalProtocol where Error == Never { /// - Returns: A disposable that can cancel the binding. @discardableResult public func bind(to target: Target, setter: @escaping (Target, Element) -> Void) -> Disposable - where Target: BindingExecutionContextProvider - { + where Target: BindingExecutionContextProvider { return bind(to: target, context: target.bindingExecutionContext, setter: setter) } - + /// Bind the receiver to the target using the given setter closure. Closure is /// called whenever the signal emits `next` event. /// @@ -112,7 +107,7 @@ extension SignalProtocol where Error == Never { } } } - + /// Bind the receiver to target's property specified by the key path. The property is /// updated whenever the signal emits `next` event. /// @@ -125,13 +120,12 @@ extension SignalProtocol where Error == Never { /// - keyPath: A key path to the property that will be updated with each sent element. /// - Returns: A disposable that can cancel the binding. @discardableResult - public func bind(to target: Target, keyPath: ReferenceWritableKeyPath) -> Disposable where Target: BindingExecutionContextProvider - { - return bind(to: target) { (target, element) in + public func bind(to target: Target, keyPath: ReferenceWritableKeyPath) -> Disposable where Target: BindingExecutionContextProvider { + return bind(to: target) { target, element in target[keyPath: keyPath] = element } } - + /// Bind the receiver to target's property specified by the key path. The property is /// updated whenever the signal emits `next` event. /// @@ -145,16 +139,14 @@ extension SignalProtocol where Error == Never { /// - context: An execution context on which to execute the setter. /// - Returns: A disposable that can cancel the binding. @discardableResult - public func bind(to target: Target, keyPath: ReferenceWritableKeyPath, context: ExecutionContext) -> Disposable - { - return bind(to: target, context: context) { (target, element) in + public func bind(to target: Target, keyPath: ReferenceWritableKeyPath, context: ExecutionContext) -> Disposable { + return bind(to: target, context: context) { target, element in target[keyPath: keyPath] = element } } } extension SignalProtocol where Error == Never, Element == Void { - /// Bind the receiver to the target using the given setter closure. Closure is /// called whenever the signal emits `next` event. /// @@ -169,11 +161,10 @@ extension SignalProtocol where Error == Never, Element == Void { /// - Returns: A disposable that can cancel the binding. @discardableResult public func bind(to target: Target, setter: @escaping (Target) -> Void) -> Disposable - where Target: BindingExecutionContextProvider - { + where Target: BindingExecutionContextProvider { return bind(to: target, context: target.bindingExecutionContext, setter: setter) } - + /// Bind the receiver to the target using the given setter closure. Closure is /// called whenever the signal emits `next` event. /// @@ -200,7 +191,6 @@ extension SignalProtocol where Error == Never, Element == Void { /// Provides an execution context used to deliver binding events. public protocol BindingExecutionContextProvider { - /// An execution context used to deliver binding events. var bindingExecutionContext: ExecutionContext { get } } diff --git a/Sources/Connectable.swift b/Sources/Connectable.swift index dee1977..7aec1c5 100644 --- a/Sources/Connectable.swift +++ b/Sources/Connectable.swift @@ -26,22 +26,20 @@ import Foundation /// Represents a signal that is started by calling `connect` on it. public protocol ConnectableSignalProtocol: SignalProtocol { - /// Start the signal. func connect() -> Disposable } /// Makes a signal connectable through the given subject. public final class ConnectableSignal: ConnectableSignalProtocol { - private let source: Source private let subject: Subject - + public init(source: Source, subject: Subject) { self.source = source self.subject = subject } - + /// Start the signal. public func connect() -> Disposable { if !subject.isTerminated { @@ -50,7 +48,7 @@ public final class ConnectableSignal: ConnectableSignalP return SimpleDisposable(isDisposed: true) } } - + /// Register an observer that will receive events from the signal. /// Note that the events will not be generated until `connect` is called. public func observe(with observer: @escaping (Signal.Event) -> Void) -> Disposable { @@ -59,13 +57,12 @@ public final class ConnectableSignal: ConnectableSignalP } extension ConnectableSignalProtocol { - /// Convert connectable signal into the ordinary signal by calling `connect` /// on the first observation and calling dispose when number of observers goes down to zero. public func refCount() -> Signal { let lock = NSRecursiveLock(name: "com.reactive_kit.connectable_signal.ref_count") var _count = 0 - var _connectionDisposable: Disposable? = nil + var _connectionDisposable: Disposable? return Signal { observer in lock.lock(); defer { lock.unlock() } _count = _count + 1 @@ -87,7 +84,6 @@ extension ConnectableSignalProtocol { } extension SignalProtocol { - public func multicast(_ createSubject: () -> Subject) -> ConnectableSignal { return ConnectableSignal(source: self, subject: createSubject()) } @@ -95,7 +91,7 @@ extension SignalProtocol { public func multicast(subject: Subject) -> ConnectableSignal { return ConnectableSignal(source: self, subject: subject) } - + /// Ensure that all observers see the same sequence of elements. Connectable. public func replay(limit: Int = Int.max) -> ConnectableSignal { if limit == 0 { @@ -106,12 +102,12 @@ extension SignalProtocol { return multicast(subject: ReplaySubject(bufferSize: limit)) } } - + /// Convert signal to a connectable signal. public func publish() -> ConnectableSignal { return multicast(subject: PassthroughSubject()) } - + /// Ensure that all observers see the same sequence of elements. /// Shorthand for `replay(limit).refCount()`. public func share(limit: Int = Int.max) -> Signal { @@ -120,7 +116,6 @@ extension SignalProtocol { } extension SignalProtocol where Element: LoadingStateProtocol { - /// Ensure that all observers see the same sequence of elements. Connectable. public func replayValues(limit: Int = Int.max) -> ConnectableSignal, Error>> { if limit == 0 { @@ -129,7 +124,7 @@ extension SignalProtocol where Element: LoadingStateProtocol { return ConnectableSignal(source: map { $0.asLoadingState }, subject: ReplayLoadingValueSubject(bufferSize: limit)) } } - + /// Ensure that all observers see the same sequence of elements. /// Shorthand for `replay(limit).refCount()`. public func shareReplayValues(limit: Int = Int.max) -> Signal, Error> { diff --git a/Sources/Deallocatable.swift b/Sources/Deallocatable.swift index 7da0533..b040977 100644 --- a/Sources/Deallocatable.swift +++ b/Sources/Deallocatable.swift @@ -7,20 +7,19 @@ // /// A type that notifies about its own deallocation. -/// +/// /// `Deallocatable` can be used as a binding target. For example, /// instead of observing a signal, one can bind it to a `Deallocatable`. /// /// class View: Deallocatable { ... } -/// +/// /// let view: View = ... /// let signal: SafeSignal = ... /// /// signal.bind(to: view) { view, number in /// view.display(number) /// } -public protocol Deallocatable: class { - +public protocol Deallocatable: AnyObject { /// A signal that fires `completed` event when the receiver is deallocated. var deallocated: SafeSignal { get } } @@ -28,13 +27,11 @@ public protocol Deallocatable: class { /// A type that provides a dispose bag. /// `DisposeBagProvider` conforms to `Deallocatable` out of the box. public protocol DisposeBagProvider: Deallocatable { - /// A `DisposeBag` that can be used to dispose observations and bindings. var bag: DisposeBag { get } } extension DisposeBagProvider { - /// A signal that fires `completed` event when the receiver is deallocated. public var deallocated: SafeSignal { return bag.deallocated @@ -43,24 +40,23 @@ extension DisposeBagProvider { #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) -import ObjectiveC.runtime + import ObjectiveC.runtime -extension NSObject: DisposeBagProvider { - - private struct AssociatedKeys { - static var DisposeBagKey = "DisposeBagKey" - } - - /// A `DisposeBag` that can be used to dispose observations and bindings. - public var bag: DisposeBag { - if let disposeBag = objc_getAssociatedObject(self, &NSObject.AssociatedKeys.DisposeBagKey) { - return disposeBag as! DisposeBag - } else { - let disposeBag = DisposeBag() - objc_setAssociatedObject(self, &NSObject.AssociatedKeys.DisposeBagKey, disposeBag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) - return disposeBag + extension NSObject: DisposeBagProvider { + private struct AssociatedKeys { + static var DisposeBagKey = "DisposeBagKey" + } + + /// A `DisposeBag` that can be used to dispose observations and bindings. + public var bag: DisposeBag { + if let disposeBag = objc_getAssociatedObject(self, &NSObject.AssociatedKeys.DisposeBagKey) { + return disposeBag as! DisposeBag + } else { + let disposeBag = DisposeBag() + objc_setAssociatedObject(self, &NSObject.AssociatedKeys.DisposeBagKey, disposeBag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) + return disposeBag + } } } -} #endif diff --git a/Sources/Deprecations.swift b/Sources/Deprecations.swift index cd35d9b..7757f7d 100644 --- a/Sources/Deprecations.swift +++ b/Sources/Deprecations.swift @@ -47,7 +47,6 @@ public typealias ReplaySubject1 = ReplaySubject public typealias ReplayOneSubject1 = ReplayOneSubject extension SignalProtocol { - @available(*, deprecated, renamed: "init(just:)") public static func just(_ element: Element) -> Signal { return Signal(just: element) @@ -80,7 +79,6 @@ public func combineLatest(_ signals: [Signal Signal { return replaceNils(with: replacement) @@ -93,7 +91,6 @@ extension SignalProtocol where Element: OptionalProtocol { } extension Signal where Error == Never { - @available(*, deprecated, message: "Replace with compactMap { $0.element }`") public func elements() -> Signal where Element == Signal.Event { return compactMap { $0.element } @@ -106,7 +103,6 @@ extension Signal where Error == Never { } extension SignalProtocol { - @available(*, deprecated, renamed: "debounce(interval:queue:)") public func debounce(interval: Double, on queue: DispatchQueue) -> Signal { return debounce(interval: interval, queue: queue) @@ -124,7 +120,6 @@ extension SignalProtocol { } extension SignalProtocol where Element: Equatable { - @available(*, deprecated, renamed: "distinctUntilChanged") public func distinct() -> Signal { return distinctUntilChanged() @@ -132,7 +127,6 @@ extension SignalProtocol where Element: Equatable { } extension SignalProtocol where Element: Sequence { - @available(*, deprecated, renamed: "flattenElements") public func unwrap() -> Signal { return flattenElements() @@ -146,7 +140,6 @@ public final class PublishSubject: Subject = PublishSubject extension ObserverProtocol { - @available(*, deprecated, renamed: "receive(_:)") public func next(_ element: Element) { on(.next(element)) @@ -170,7 +163,6 @@ extension ObserverProtocol { } extension ObserverProtocol where Element == Void { - @available(*, deprecated, renamed: "receive") public func next() { next(()) @@ -178,8 +170,6 @@ extension ObserverProtocol where Element == Void { } extension SubjectProtocol { - - @available(*, deprecated, renamed: "send(_:)") public func next(_ element: Element) { on(.next(element)) @@ -203,7 +193,6 @@ extension SubjectProtocol { } extension SubjectProtocol where Element == Void { - @available(*, deprecated, renamed: "send") public func next() { next(()) @@ -211,7 +200,6 @@ extension SubjectProtocol where Element == Void { } extension Subject { - @available(*, deprecated, renamed: "receive(event:)") open func send(_ event: Event) { on(event) @@ -219,7 +207,6 @@ extension Subject { } extension SignalProtocol { - @available(*, deprecated, renamed: "share(limit:)") public func shareReplay(limit: Int = Int.max) -> Signal { return share(limit: limit) @@ -227,7 +214,6 @@ extension SignalProtocol { } extension SignalProtocol { - /// Set the execution context in which to execute the signal (i.e. in which to run /// the signal's producer). @available(*, deprecated, renamed: "subscribe(on:)") @@ -256,7 +242,6 @@ extension SignalProtocol { } extension SignalProtocol { - /// Emit first element and then all elements that are not equal to their predecessor(s). /// /// Check out interactive example at [https://rxmarbles.com/#distinctUntilChanged](https://rxmarbles.com/#distinctUntilChanged) @@ -272,7 +257,7 @@ extension SignalProtocol { public func debounce(interval: Double, queue: DispatchQueue = DispatchQueue(label: "com.reactive_kit.signal.debounce")) -> Signal { return debounce(for: interval, queue: queue) } - + /// Emit only the element at given index (if such element is produced). /// /// Check out interactive example at [https://rxmarbles.com/#elementAt](https://rxmarbles.com/#elementAt) @@ -344,7 +329,6 @@ extension SignalProtocol { } extension SignalProtocol where Element: Equatable { - /// Emit first element and then all elements that are not equal to their predecessor(s). /// /// Check out interactive example at [https://rxmarbles.com/#distinctUntilChanged](https://rxmarbles.com/#distinctUntilChanged) @@ -355,7 +339,6 @@ extension SignalProtocol where Element: Equatable { } extension SignalProtocol { - /// Batch signal elements into arrays of the given size. /// /// Check out interactive example at [https://rxmarbles.com/#bufferCount](https://rxmarbles.com/#bufferCount) @@ -402,18 +385,18 @@ extension SignalProtocol { /// Do side-effect upon various events. @available(*, deprecated, renamed: "handleEvents(receiveSubscription:receiveOutput:receiveCompletion:receiveCancel:)") - public func doOn(next: ((Element) -> ())? = nil, + public func doOn(next: ((Element) -> Void)? = nil, start: (() -> Void)? = nil, failed: ((Error) -> Void)? = nil, completed: (() -> Void)? = nil, - disposed: (() -> ())? = nil) -> Signal { + disposed: (() -> Void)? = nil) -> Signal { return Signal { observer in start?() let disposable = self.observe { event in switch event { - case .next(let value): + case let .next(value): next?(value) - case .failed(let error): + case let .failed(error): failed?(error) case .completed: completed?() @@ -429,7 +412,6 @@ extension SignalProtocol { } extension SignalProtocol { - /// First propagate all elements from the source signal and then all elements from the `other` signal. /// /// Check out interactive example at [https://rxmarbles.com/#concat](https://rxmarbles.com/#concat) @@ -443,12 +425,11 @@ extension SignalProtocol { /// Check out interactive example at [https://rxmarbles.com/#concat](https://rxmarbles.com/#concat) @available(*, deprecated, renamed: "append(_:)") public func concat(with other: O) -> Signal where O.Element == Element, O.Error == Never { - return append((other.castError() as Signal)) + return append(other.castError() as Signal) } } extension SignalProtocol where Error == Never { - /// First propagate all elements from the source signal and then all elements from the `other` signal. /// /// Check out interactive example at [https://rxmarbles.com/#concat](https://rxmarbles.com/#concat) @@ -459,7 +440,6 @@ extension SignalProtocol where Error == Never { } extension SignalProtocol { - @available(*, deprecated, message: "Please provide `receiveCompletion` argument when observing signals with error type other than `Never`.") public func sink(receiveValue: @escaping ((Element) -> Void)) -> AnyCancellable { return sink(receiveCompletion: { _ in }, receiveValue: receiveValue) diff --git a/Sources/Disposable.swift b/Sources/Disposable.swift index d393a3c..4f219cb 100644 --- a/Sources/Disposable.swift +++ b/Sources/Disposable.swift @@ -35,16 +35,14 @@ import Foundation /// /// disposable.dispose() public protocol Disposable: Cancellable { - /// Dispose the signal observation or binding. func dispose() - + /// Returns `true` is already disposed. var isDisposed: Bool { get } } extension Disposable { - @inlinable public func cancel() { dispose() @@ -53,13 +51,12 @@ extension Disposable { /// A disposable that cannot be disposed. public struct NonDisposable: Disposable { - public static let instance = NonDisposable() - + private init() {} - + public func dispose() {} - + public var isDisposed: Bool { return false } @@ -67,7 +64,6 @@ public struct NonDisposable: Disposable { /// A disposable that just encapsulates disposed state. public final class SimpleDisposable: Disposable { - private let lock = NSRecursiveLock(name: "com.reactive_kit.simple_disposable") private var _isDisposed: Bool @@ -81,32 +77,31 @@ public final class SimpleDisposable: Disposable { _isDisposed = newValue } } - + public func dispose() { lock.lock(); defer { lock.unlock() } _isDisposed = true } - + public init(isDisposed: Bool = false) { - self._isDisposed = isDisposed + _isDisposed = isDisposed } } /// A disposable that executes the given block upon disposing. public final class BlockDisposable: Disposable { - private let lock = NSRecursiveLock(name: "com.reactive_kit.block_disposable") - private var handler: (() -> ())? + private var handler: (() -> Void)? public var isDisposed: Bool { lock.lock(); defer { lock.unlock() } return handler == nil } - public init(_ handler: @escaping () -> ()) { + public init(_ handler: @escaping () -> Void) { self.handler = handler } - + public func dispose() { lock.lock() guard let handler = handler else { @@ -121,7 +116,6 @@ public final class BlockDisposable: Disposable { /// A disposable that disposes itself upon deallocation. public final class DeinitDisposable: Disposable { - private let lock = NSRecursiveLock(name: "com.reactive_kit.deinit_disposable") private var _otherDisposable: Disposable? @@ -135,16 +129,16 @@ public final class DeinitDisposable: Disposable { return _otherDisposable } } - + public var isDisposed: Bool { lock.lock(); defer { lock.unlock() } return _otherDisposable == nil } - + public init(disposable: Disposable) { _otherDisposable = disposable } - + public func dispose() { lock.lock() guard let otherDisposable = _otherDisposable else { @@ -155,7 +149,7 @@ public final class DeinitDisposable: Disposable { lock.unlock() otherDisposable.dispose() } - + deinit { dispose() } @@ -163,7 +157,6 @@ public final class DeinitDisposable: Disposable { /// A disposable that disposes a collection of disposables upon its own disposing. public final class CompositeDisposable: Disposable { - private let lock = NSRecursiveLock(name: "com.reactive_kit.composite_disposable") private var disposables: [Disposable]? @@ -173,13 +166,13 @@ public final class CompositeDisposable: Disposable { } public init() { - self.disposables = [] + disposables = [] } - + public init(_ disposables: [Disposable]) { self.disposables = disposables } - + public func add(disposable: Disposable) { lock.lock(); defer { lock.unlock() } if disposables == nil { @@ -188,11 +181,11 @@ public final class CompositeDisposable: Disposable { disposables = disposables.map { $0 + [disposable] } } } - + public static func += (left: CompositeDisposable, right: Disposable) { left.add(disposable: right) } - + public func dispose() { lock.lock() guard let disposables = disposables else { @@ -207,7 +200,6 @@ public final class CompositeDisposable: Disposable { /// A disposable that disposes other disposable upon its own disposing. public final class SerialDisposable: Disposable { - private let lock = NSRecursiveLock(name: "com.reactive_kit.serial_disposable") private var _isDisposed = false @@ -215,7 +207,7 @@ public final class SerialDisposable: Disposable { lock.lock(); defer { lock.unlock() } return _isDisposed } - + /// Will dispose other disposable immediately if self is already disposed. public var otherDisposable: Disposable? { didSet { @@ -229,11 +221,11 @@ public final class SerialDisposable: Disposable { } } } - + public init(otherDisposable: Disposable?) { self.otherDisposable = otherDisposable } - + public func dispose() { lock.lock() if !_isDisposed { @@ -272,46 +264,44 @@ public protocol DisposeBagProtocol: Disposable { /// /// When bag gets deallocated, it will dispose all disposables it contains. public final class DisposeBag: DisposeBagProtocol { - private let lockDisposables = NSRecursiveLock(name: "com.reactive_kit.dispose_bag.lock_disposables") private let lockSubject = NSRecursiveLock(name: "com.reactive_kit.dispose_bag.lock_subject") private var disposables: [Disposable] = [] - private var subject: ReplayOneSubject? = nil + private var subject: ReplayOneSubject? /// `true` if bag is empty, `false` otherwise. public var isDisposed: Bool { lockDisposables.lock(); defer { lockDisposables.unlock() } return disposables.count == 0 } - - public init() { - } - + + public init() {} + /// Add the given disposable to the bag. /// Disposable will be disposed when the bag is deallocated. public func add(disposable: Disposable) { lockDisposables.lock(); defer { lockDisposables.unlock() } disposables.append(disposable) } - + /// Add the given disposables to the bag. /// Disposables will be disposed when the bag is deallocated. public func add(disposables: [Disposable]) { lockDisposables.lock(); defer { lockDisposables.unlock() } self.disposables.append(contentsOf: disposables) } - + /// Add a disposable to a dispose bag. public static func += (left: DisposeBag, right: Disposable) { left.add(disposable: right) } - + /// Add multiple disposables to a dispose bag. public static func += (left: DisposeBag, right: [Disposable]) { left.add(disposables: right) } - + /// Disposes all disposables that are currenty in the bag. public func dispose() { lockDisposables.lock() @@ -320,7 +310,7 @@ public final class DisposeBag: DisposeBagProtocol { lockDisposables.unlock() disposables.forEach { $0.dispose() } } - + /// A signal that fires `completed` event when the bag gets deallocated. public var deallocated: SafeSignal { lockSubject.lock(); defer { lockSubject.unlock() } @@ -329,7 +319,7 @@ public final class DisposeBag: DisposeBagProtocol { } return subject!.toSignal() } - + deinit { dispose() subject?.send(completion: .finished) @@ -339,17 +329,15 @@ public final class DisposeBag: DisposeBagProtocol { /// A type-erasing cancellable object that executes a provided closure when canceled (disposed). /// The closure will be executed upon deinit if it has not been executed already. public final class AnyCancellable: Disposable { - private let lock = NSRecursiveLock(name: "com.reactive_kit.any_cancellable") - private var handler: (() -> ())? + private var handler: (() -> Void)? public var isDisposed: Bool { lock.lock(); defer { lock.unlock() } return handler == nil } - - public init(_ handler: @escaping () -> ()) { + public init(_ handler: @escaping () -> Void) { self.handler = handler } @@ -370,32 +358,30 @@ public final class AnyCancellable: Disposable { } extension AnyCancellable: Hashable { - public static func == (lhs: AnyCancellable, rhs: AnyCancellable) -> Bool { - return lhs === rhs - } + public static func == (lhs: AnyCancellable, rhs: AnyCancellable) -> Bool { + return lhs === rhs + } - public func hash(into hasher: inout Hasher) { - hasher.combine(ObjectIdentifier(self)) - } + public func hash(into hasher: inout Hasher) { + hasher.combine(ObjectIdentifier(self)) + } } extension AnyCancellable { - public convenience init(_ disposable: Disposable) { self.init(disposable.dispose) } - final public func store(in collection: inout C) where C: RangeReplaceableCollection, C.Element == AnyCancellable { + public final func store(in collection: inout C) where C: RangeReplaceableCollection, C.Element == AnyCancellable { collection.append(self) } - final public func store(in set: inout Set) { + public final func store(in set: inout Set) { set.insert(self) } } extension Disposable { - /// Put the disposable in the given bag. Disposable will be disposed when /// the bag is either deallocated or disposed. public func dispose(in disposeBag: DisposeBagProtocol) { diff --git a/Sources/ExecutionContext.swift b/Sources/ExecutionContext.swift index 635fc59..6d54954 100644 --- a/Sources/ExecutionContext.swift +++ b/Sources/ExecutionContext.swift @@ -22,8 +22,8 @@ // THE SOFTWARE. // -import Foundation import Dispatch +import Foundation /// Execution context is an abstraction over a thread or a dispatch queue. /// @@ -34,14 +34,13 @@ import Dispatch /// } /// public struct ExecutionContext { - public let context: (@escaping () -> Void) -> Void - + /// Execution context is just a function that executes other function. public init(_ context: @escaping (@escaping () -> Void) -> Void) { self.context = context } - + /// Execute given block in the context. @inlinable public func execute(_ block: @escaping () -> Void) { @@ -50,9 +49,9 @@ public struct ExecutionContext { /// Execution context that executes immediately and synchronously on current thread or queue. public static var immediate: ExecutionContext { - return ExecutionContext { block in block () } + return ExecutionContext { block in block() } } - + /// Executes immediately and synchronously if current thread is main thread. Otherwise executes /// asynchronously on main dispatch queue (main thread). public static var immediateOnMain: ExecutionContext { @@ -64,18 +63,18 @@ public struct ExecutionContext { } } } - + /// Execution context bound to main dispatch queue. public static var main: ExecutionContext { return DispatchQueue.main.context } - + /// Execution context bound to global dispatch queue. @available(macOS 10.10, *) public static func global(qos: DispatchQoS.QoSClass = .default) -> ExecutionContext { return DispatchQueue.global(qos: qos).context } - + /// Execution context that breaks recursive class by ingoring them. public static func nonRecursive() -> ExecutionContext { var updating: Bool = false @@ -89,20 +88,19 @@ public struct ExecutionContext { } extension DispatchQueue { - /// Creates ExecutionContext from the queue. public var context: ExecutionContext { return ExecutionContext { block in self.async(execute: block) } } - + /// Schedule given block for execution after given interval passes. @available(*, deprecated, message: "Please use asyncAfter(deadline:execute:)") public func after(when interval: Double, block: @escaping () -> Void) { asyncAfter(deadline: .now() + interval, execute: block) } - + /// Schedule given block for execution after given interval passes. /// Scheduled execution can be cancelled by disposing the returned disposable. public func disposableAfter(when interval: Double, block: @escaping () -> Void) -> Disposable { diff --git a/Sources/LoadingProperty.swift b/Sources/LoadingProperty.swift index 6c6a858..eb84821 100644 --- a/Sources/LoadingProperty.swift +++ b/Sources/LoadingProperty.swift @@ -27,24 +27,23 @@ import Foundation /// A property that lazily loads its value using the given signal producer closure. /// The value will be loaded when the property is observed for the first time. public class LoadingProperty: PropertyProtocol, SignalProtocol, DisposeBagProvider { - private let lock = NSRecursiveLock(name: "com.reactive_kit.loading_property") - + private let signalProducer: () -> LoadingSignal private let subject = PassthroughSubject, Never>() private var _loadingDisposable: Disposable? - + public var bag: DisposeBag { return subject.disposeBag } - + private var _loadingState: LoadingState = .loading { didSet { subject.send(_loadingState) } } - + /// Current state of the property. In `.loading` state until the value is loaded. /// When the property is observed for the first time, the value will be loaded and /// the state will be updated to either `.loaded` or `.failed` state. @@ -52,7 +51,7 @@ public class LoadingProperty: PropertyP lock.lock(); defer { lock.unlock() } return _loadingState } - + /// Underlying value. `nil` if not yet loaded or if the property is in error state. public var value: LoadingValue? { get { @@ -63,19 +62,19 @@ public class LoadingProperty: PropertyP _loadingState = newValue.flatMap { .loaded($0) } ?? .loading } } - + /// Create a loading property with the given signal producer closure. /// The closure will be executed when the propery is observed for the first time. public init(_ signalProducer: @escaping () -> LoadingSignal) { self.signalProducer = signalProducer } - + /// Create a signal that when observed reloads the property. /// - parameter silently: When `true` (default), do not transition property to loading or failed states during reload. public func reload(silently: Bool = true) -> LoadingSignal { return load(silently: silently) } - + private func load(silently: Bool) -> LoadingSignal { return LoadingSignal { observer in self.lock.lock(); defer { self.lock.unlock() } @@ -85,7 +84,7 @@ public class LoadingProperty: PropertyP observer.receive(.loading) self._loadingDisposable = self.signalProducer().observe { event in switch event { - case .next(let anyLoadingState): + case let .next(anyLoadingState): let loadingSate = anyLoadingState.asLoadingState switch loadingSate { case .loading: @@ -106,7 +105,7 @@ public class LoadingProperty: PropertyP break // Never } } - + return BlockDisposable { self.lock.lock(); defer { self.lock.unlock() } self._loadingDisposable?.dispose() @@ -114,7 +113,7 @@ public class LoadingProperty: PropertyP } } } - + public func observe(with observer: @escaping (Signal, Never>.Event) -> Void) -> Disposable { lock.lock(); defer { lock.unlock() } if case .loading = _loadingState, _loadingDisposable == nil { @@ -129,21 +128,19 @@ public class LoadingProperty: PropertyP } extension SignalProtocol { - /// Pauses the propagation of the receiver's elements until the given property is reloaded. public func reloading(_ property: LoadingProperty) -> Signal { return flatMapLatest { (element: Element) -> Signal in - return property.reload().dematerializeLoadingState().map { _ in element } + property.reload().dematerializeLoadingState().map { _ in element } } } } extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { - /// Pauses the propagation of the receiver's loading values until the given property is reloaded. - public func reloading(_ property: LoadingProperty, strategy: FlattenStrategy = .latest) -> LoadingSignal { + public func reloading(_ property: LoadingProperty, strategy _: FlattenStrategy = .latest) -> LoadingSignal { return flatMapValue { (value: LoadingValue) -> LoadingSignal in - return property.reload().mapValue { _ in value } + property.reload().mapValue { _ in value } } } } diff --git a/Sources/LoadingSignal.swift b/Sources/LoadingSignal.swift index 1eab428..1fb1129 100644 --- a/Sources/LoadingSignal.swift +++ b/Sources/LoadingSignal.swift @@ -26,15 +26,13 @@ import Foundation /// Represents loading state of a value. Element of LoadingSignal. public protocol LoadingStateProtocol { - associatedtype LoadingValue associatedtype LoadingError: Error - + var asLoadingState: LoadingState { get } } extension LoadingStateProtocol { - /// True if self is `.loading`. public var isLoading: Bool { if case .loading = asLoadingState { @@ -43,19 +41,19 @@ extension LoadingStateProtocol { return false } } - + /// Value if self is `.loaded`. public var value: LoadingValue? { - if case .loaded(let value) = asLoadingState { + if case let .loaded(value) = asLoadingState { return value } else { return nil } } - + /// Error if self is `.failed`. public var error: LoadingError? { - if case .failed(let error) = asLoadingState { + if case let .failed(error) = asLoadingState { return error } else { return nil @@ -65,16 +63,15 @@ extension LoadingStateProtocol { /// Represents loading state of an asynchronous action. Element of LoadingSignal. public enum LoadingState: LoadingStateProtocol { - /// Value is loading. case loading - + /// Value is loaded. case loaded(LoadingValue) - + /// Value loading failed with the given error. case failed(LoadingError) - + public var asLoadingState: LoadingState { return self } @@ -87,7 +84,6 @@ public protocol ObservedLoadingStateProtocol: LoadingStateProtocol { } extension ObservedLoadingStateProtocol { - /// True if self is `.reloading`. public var isReloading: Bool { if case .reloading = asObservedLoadingState { @@ -101,46 +97,44 @@ extension ObservedLoadingStateProtocol { /// Loading state as observed by the observer. Just like LoadingState, but with `.reloading` case. /// To get observed loading state from a loading signal, apply `deriveObservedLoadingState()` operator. public enum ObservedLoadingState: ObservedLoadingStateProtocol { - /// Value is loading. case loading - + /// Value is reloading. case reloading - + /// Value is loaded. case loaded(LoadingValue) - + /// Value loading failed with the given error. case failed(LoadingError) - + public var asLoadingState: LoadingState { switch self { case .loading, .reloading: return .loading - case .loaded(let value): + case let .loaded(value): return .loaded(value) - case .failed(let error): + case let .failed(error): return .failed(error) } } - + public var asObservedLoadingState: ObservedLoadingState { switch self { case .loading: return .loading case .reloading: return .reloading - case .loaded(let value): + case let .loaded(value): return .loaded(value) - case .failed(let error): + case let .failed(error): return .failed(error) } } } extension LoadingState { - /// True if `other` is the same state as the receiver; Does not compare underlying value or error! public func isSameStateAs(_ other: LoadingState) -> Bool { switch (self, other) { @@ -160,69 +154,68 @@ extension LoadingState { public typealias LoadingSignal = SafeSignal> extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { - public typealias LoadingValue = Element.LoadingValue public typealias LoadingError = Element.LoadingError - + /// Create LoadingSignal that just emits `.loading` state. public static func loading() -> LoadingSignal { return Signal(just: .loading) } - + /// Create LoadingSignal that just emits the given value in `.loaded` state. public static func loaded(_ value: LoadingValue) -> LoadingSignal { return Signal(just: .loaded(value)) } - + /// Create LoadingSignal that just emits the given error in `.failed` state. public static func failed(_ error: LoadingError) -> LoadingSignal { return Signal(just: .failed(error)) } - + /// Convert receiver into a SafeSignal by passing values from `.loaded` events and ignoring `.loading` or `.failed` states. public func value() -> SafeSignal { return compactMap { $0.value } } - + /// Map loading value. public func mapValue(_ transform: @escaping (LoadingValue) -> NewValue) -> LoadingSignal { return map { (element: Element) -> LoadingState in switch element.asLoadingState { case .loading: return .loading - case .loaded(let value): + case let .loaded(value): return .loaded(transform(value)) - case .failed(let error): + case let .failed(error): return .failed(error) } } } - + /// Map loading error. public func mapLoadingError(_ transform: @escaping (LoadingError) -> NewError) -> LoadingSignal { return map { (element: Element) -> LoadingState in switch element.asLoadingState { case .loading: return .loading - case .loaded(let value): + case let .loaded(value): return .loaded(value) - case .failed(let error): + case let .failed(error): return .failed(transform(error)) } } } - + /// Convert LoadingSignal into a regular Signal by propagating loaded values as signal elements and loading error as signal error. /// The signal will terminate and dispose itself if it receives a loading error! public func dematerializeLoadingState() -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let anyLoadingState): + case let .next(anyLoadingState): switch anyLoadingState.asLoadingState { - case .loaded(let value): + case let .loaded(value): observer.receive(value) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .loading: break @@ -235,7 +228,7 @@ extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { } } } - + /// Lift loading signal values into a regular signal, apply the given transform to that singal and convert the result /// back into the loading signal. Enables you to use regular Signal operators on LoadingSignal. For example: /// @@ -246,7 +239,7 @@ extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { public func liftValue(_ transfrom: @escaping (Signal) -> Signal) -> LoadingSignal { return liftValue { transfrom($0).toLoadingSignal() } } - + /// Lift loading signal values into a regular signal, apply the given transform to that singal and convert the result /// back into the loading signal. Enables you to use regular Signal operators on LoadingSignal. For example: /// @@ -260,11 +253,11 @@ extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { let d1 = transfrom(subject.toSignal()).observe(with: observer.on) let d2 = self.observe { event in switch event { - case .next(let anyLoadingState): + case let .next(anyLoadingState): switch anyLoadingState.asLoadingState { - case .loaded(let value): + case let .loaded(value): subject.receive(value) - case .failed(let error): + case let .failed(error): observer.receive(.failed(error)) case .loading: observer.receive(.loading) @@ -278,43 +271,42 @@ extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { return CompositeDisposable([d1, d2]) } } - + /// Map value into a loading signal and flatten that signal. public func flatMapValue(_ strategy: FlattenStrategy = .latest, transfrom: @escaping (LoadingValue) -> LoadingSignal) -> LoadingSignal { - let apply = { (anyLoadingSate: Element) -> LoadingSignal in switch anyLoadingSate.asLoadingState { case .loading: return .loading() - case .loaded(let value): + case let .loaded(value): return transfrom(value) - case .failed(let error): + case let .failed(error): return .failed(error) } } - + return flatMap(strategy, apply) } - + /// Map value into a signal and flatten that signal into a loading signal. public func flatMapValue(_ strategy: FlattenStrategy = .latest, transfrom: @escaping (LoadingValue) -> Signal) -> LoadingSignal { return flatMapValue(strategy) { (value: LoadingValue) -> LoadingSignal in - return transfrom(value).toLoadingSignal() + transfrom(value).toLoadingSignal() } } - + /// Convert LoadingState into ObservedLoadingState by mapping subsequent loads into reloads. /// /// - parameter loadsAgainOnFailure: `.loading` state that follows a `.failed` state will be kept as `.loading` if `true` is passed. Otherwise it will be mapped into `.reloading`. Default is true. /// public func deriveObservedLoadingState(loadsAgainOnFailure: Bool = true) -> Signal, Never> { let lock = NSRecursiveLock(name: "com.reactive_kit.loading_signal.derive_observe_loading_state") - var _previousLoadingState: LoadingState? = nil + var _previousLoadingState: LoadingState? var _hasProducedNonLoadingState = false return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let anyLoadingState): + case let .next(anyLoadingState): lock.lock(); defer { lock.unlock() } let loadingState = anyLoadingState.asLoadingState switch loadingState { @@ -325,10 +317,10 @@ extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { } else { observer.receive(.loading) } - case .loaded(let value): + case let .loaded(value): _hasProducedNonLoadingState = true observer.receive(.loaded(value)) - case .failed(let error): + case let .failed(error): _hasProducedNonLoadingState = !loadsAgainOnFailure observer.receive(.failed(error)) } @@ -344,7 +336,6 @@ extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { } extension SignalProtocol { - /// Convert signal into a loading signal. The signal will automatically start with `.loading` state, each element will /// be mapped into a `.loaded` state and the error will be mapped into a `.failed` state. public func toLoadingSignal() -> LoadingSignal { @@ -353,34 +344,30 @@ extension SignalProtocol { } /// A consumer of ObservedLoadingState. For example, a view what updates its appearance based on loading state. -public protocol LoadingStateListener: class { - +public protocol LoadingStateListener: AnyObject { /// Consume observed loading state. func setLoadingState(_ state: ObservedLoadingState) - + var loadingStateListenerNeedsWeakReference: Bool { get } } extension LoadingStateListener { - public var loadingStateListenerNeedsWeakReference: Bool { return true } } extension SignalProtocol where Element: ObservedLoadingStateProtocol, Error == Never { - /// Update loading state of the listener on each `.next` (loading state) event. - public func updateLoadingState(of listener: (LoadingStateListener & BindingExecutionContextProvider)) -> Signal, Never> { + public func updateLoadingState(of listener: LoadingStateListener & BindingExecutionContextProvider) -> Signal, Never> { return updateLoadingState(of: listener, context: listener.bindingExecutionContext) } - + /// Update loading state of the listener on each `.next` (loading state) event. public func updateLoadingState(of listener: LoadingStateListener, context: ExecutionContext) -> Signal, Never> { - let _observe = { (listener: LoadingStateListener?, event: Signal.Event, observer: AtomicObserver, Never>) in switch event { - case .next(let anyObservedLoadingState): + case let .next(anyObservedLoadingState): let observedLoadingState = anyObservedLoadingState.asObservedLoadingState if let listener = listener { context.execute { @@ -392,27 +379,27 @@ extension SignalProtocol where Element: ObservedLoadingStateProtocol, Error == N observer.receive(completion: .finished) } } - + if listener.loadingStateListenerNeedsWeakReference { return Signal { [weak listener] observer in - return self.observe { [weak listener] event in + self.observe { [weak listener] event in _observe(listener, event, observer) } } } else { return Signal { observer in - return self.observe { event in + self.observe { event in _observe(listener, event, observer) } } } } - + /// Consume loading state by the listener and return SafeSignal of loaded values. - public func consumeLoadingState(by listener: (LoadingStateListener & BindingExecutionContextProvider)) -> SafeSignal { + public func consumeLoadingState(by listener: LoadingStateListener & BindingExecutionContextProvider) -> SafeSignal { return updateLoadingState(of: listener, context: listener.bindingExecutionContext).value() } - + /// Consume loading state by the listener and return SafeSignal of loaded values. public func consumeLoadingState(by listener: LoadingStateListener, context: ExecutionContext) -> SafeSignal { return updateLoadingState(of: listener, context: context).value() @@ -420,22 +407,21 @@ extension SignalProtocol where Element: ObservedLoadingStateProtocol, Error == N } extension SignalProtocol where Element: LoadingStateProtocol, Error == Never { - /// Update loading state of the listener on each `.next` (loading state) event. - public func updateLoadingState(of listener: (LoadingStateListener & BindingExecutionContextProvider)) -> LoadingSignal { + public func updateLoadingState(of listener: LoadingStateListener & BindingExecutionContextProvider) -> LoadingSignal { return deriveObservedLoadingState().updateLoadingState(of: listener).map { $0.asLoadingState } } - + /// Update loading state of the listener on each `.next` (loading state) event. public func updateLoadingState(of listener: LoadingStateListener, context: ExecutionContext) -> LoadingSignal { return deriveObservedLoadingState().updateLoadingState(of: listener, context: context).map { $0.asLoadingState } } - + /// Consume loading state by the listener and return SafeSignal of loaded values. - public func consumeLoadingState(by listener: (LoadingStateListener & BindingExecutionContextProvider)) -> SafeSignal { + public func consumeLoadingState(by listener: LoadingStateListener & BindingExecutionContextProvider) -> SafeSignal { return deriveObservedLoadingState().consumeLoadingState(by: listener) } - + /// Consume loading state by the listener and return SafeSignal of loaded values. public func consumeLoadingState(by listener: LoadingStateListener, context: ExecutionContext) -> SafeSignal { return deriveObservedLoadingState().consumeLoadingState(by: listener, context: context) diff --git a/Sources/Lock.swift b/Sources/Lock.swift index f93d9e2..be4e8eb 100644 --- a/Sources/Lock.swift +++ b/Sources/Lock.swift @@ -25,7 +25,6 @@ import Foundation extension NSLock { - public convenience init(name: String) { self.init() self.name = name @@ -33,7 +32,6 @@ extension NSLock { } extension NSRecursiveLock { - public convenience init(name: String) { self.init() self.name = name diff --git a/Sources/ObservableObject.swift b/Sources/ObservableObject.swift index 1e9b4c9..d35968e 100644 --- a/Sources/ObservableObject.swift +++ b/Sources/ObservableObject.swift @@ -8,34 +8,32 @@ #if compiler(>=5.1) -import Foundation - -/// A type of object with a publisher that emits before the object has changed. -/// -/// By default an `ObservableObject` will synthesize an `objectWillChange` -/// publisher that emits before any of its `@Published` properties changes: -public protocol ObservableObject: AnyObject { - - /// The type of signal that emits before the object has changed. - associatedtype ObjectWillChangeSignal: SignalProtocol = Signal where Self.ObjectWillChangeSignal.Error == Never - - /// A signal that emits before the object has changed. - var objectWillChange: Self.ObjectWillChangeSignal { get } -} - -extension ObservableObject where Self.ObjectWillChangeSignal == Signal { + import Foundation + + /// A type of object with a publisher that emits before the object has changed. + /// + /// By default an `ObservableObject` will synthesize an `objectWillChange` + /// publisher that emits before any of its `@Published` properties changes: + public protocol ObservableObject: AnyObject { + /// The type of signal that emits before the object has changed. + associatedtype ObjectWillChangeSignal: SignalProtocol = Signal where Self.ObjectWillChangeSignal.Error == Never + + /// A signal that emits before the object has changed. + var objectWillChange: Self.ObjectWillChangeSignal { get } + } - /// A publisher that emits before the object has changed. - public var objectWillChange: Signal { - var subjects: [PassthroughSubject] = [] - let mirror = Mirror(reflecting: self) - for child in mirror.children { - if let publishedProperty = child.value as? PublishedProtocol { - subjects.append(publishedProperty.willChangeSubject) + extension ObservableObject where Self.ObjectWillChangeSignal == Signal { + /// A publisher that emits before the object has changed. + public var objectWillChange: Signal { + var subjects: [PassthroughSubject] = [] + let mirror = Mirror(reflecting: self) + for child in mirror.children { + if let publishedProperty = child.value as? PublishedProtocol { + subjects.append(publishedProperty.willChangeSubject) + } } + return Signal(flattening: subjects, strategy: .merge) } - return Signal(flattening: subjects, strategy: .merge) } -} #endif diff --git a/Sources/Observer.swift b/Sources/Observer.swift index 7efd412..7486376 100644 --- a/Sources/Observer.swift +++ b/Sources/Observer.swift @@ -32,13 +32,12 @@ public typealias SafeObserver = (Signal.Event) -> Void /// Represents a type that receives events. public protocol ObserverProtocol { - /// Type of elements being received. associatedtype Element - + /// Type of error that can be received. associatedtype Error: Swift.Error - + /// Send the event to the observer. func on(_ event: Signal.Event) } @@ -46,14 +45,13 @@ public protocol ObserverProtocol { /// Represents a type that receives events. Observer is just a convenience /// wrapper around a closure observer `Observer`. public struct AnyObserver: ObserverProtocol { - public let observer: Observer - + /// Creates an observer that wraps a closure observer. public init(observer: @escaping Observer) { self.observer = observer } - + /// Calles wrapped closure with the given element. @inlinable public func on(_ event: Signal.Event) { @@ -63,7 +61,6 @@ public struct AnyObserver: ObserverProtocol { /// Observer that ensures events are sent atomically. public final class AtomicObserver: ObserverProtocol, Disposable { - private var observer: Observer? private var upstreamDisposables: [Disposable] = [] private let observerLock = NSRecursiveLock(name: "com.reactive_kit.atomic_observer.observer") @@ -93,7 +90,7 @@ public final class AtomicObserver: ObserverProtocol self.observer = nil observerLock.unlock() disposablesLock.lock() - self.upstreamDisposables.forEach { $0.dispose() } + upstreamDisposables.forEach { $0.dispose() } disposablesLock.unlock() } else { observerLock.unlock() @@ -106,11 +103,11 @@ public final class AtomicObserver: ObserverProtocol public func attach(_ producer: Signal.Producer) { let disposable = producer(self) - if self.isDisposed { + if isDisposed { disposable.dispose() } else { disposablesLock.lock() - self.upstreamDisposables.append(disposable) + upstreamDisposables.append(disposable) disposablesLock.unlock() } } @@ -120,7 +117,7 @@ public final class AtomicObserver: ObserverProtocol observer = nil observerLock.unlock() disposablesLock.lock() - self.upstreamDisposables.forEach { $0.dispose() } + upstreamDisposables.forEach { $0.dispose() } disposablesLock.unlock() } } @@ -128,7 +125,6 @@ public final class AtomicObserver: ObserverProtocol // MARK: - Extensions extension ObserverProtocol { - /// Convenience method to send `.next` event. public func receive(_ element: Element) { on(.next(element)) @@ -139,7 +135,7 @@ extension ObserverProtocol { switch completion { case .finished: on(.completed) - case .failure(let error): + case let .failure(error): on(.failed(error)) } } @@ -157,7 +153,6 @@ extension ObserverProtocol { } extension ObserverProtocol where Element == Void { - /// Convenience method to send `.next` event. public func receive() { on(.next(())) diff --git a/Sources/Property.swift b/Sources/Property.swift index ec38f60..e281ed3 100644 --- a/Sources/Property.swift +++ b/Sources/Property.swift @@ -32,7 +32,6 @@ public protocol PropertyProtocol { /// Represents mutable state that can be observed as a signal of events. public final class Property: PropertyProtocol, SubjectProtocol, BindableProtocol, DisposeBagProvider { - private let lock = NSRecursiveLock(name: "com.reactive_kit.property") private let subject: Subject @@ -40,7 +39,7 @@ public final class Property: PropertyProtocol, SubjectProtocol, BindableP public var bag: DisposeBag { return subject.disposeBag } - + /// Underlying value. Changing it emits `.next` event with new value. private var _value: Value public var value: Value { @@ -54,35 +53,35 @@ public final class Property: PropertyProtocol, SubjectProtocol, BindableP subject.send(newValue) } } - + public init(_ value: Value, subject: Subject = PassthroughSubject()) { _value = value self.subject = subject } - + public func on(_ event: Signal.Event) { lock.lock(); defer { lock.unlock() } - if case .next(let element) = event { + if case let .next(element) = event { _value = element } subject.on(event) } - + public func observe(with observer: @escaping (Signal.Event) -> Void) -> Disposable { lock.lock(); defer { lock.unlock() } return subject.prepend(_value).observe(with: observer) } - + public var readOnlyView: AnyProperty { return AnyProperty(property: self) } - + /// Change the underlying value without notifying the observers. public func silentUpdate(value: Value) { lock.lock(); defer { lock.unlock() } _value = value } - + public func bind(signal: Signal) -> Disposable { return signal .prefix(untilOutputFrom: bag.deallocated) @@ -91,7 +90,7 @@ public final class Property: PropertyProtocol, SubjectProtocol, BindableP self?.on(.next(element)) } } - + deinit { subject.send(completion: .finished) } @@ -99,17 +98,16 @@ public final class Property: PropertyProtocol, SubjectProtocol, BindableP /// Represents mutable state that can be observed as a signal of events. public final class AnyProperty: PropertyProtocol, SignalProtocol { - private let property: Property - + public var value: Value { return property.value } - + public init(property: Property) { self.property = property } - + public func observe(with observer: @escaping (Signal.Event) -> Void) -> Disposable { return property.observe(with: observer) } diff --git a/Sources/Published.swift b/Sources/Published.swift index b4e0ca2..515ac1c 100644 --- a/Sources/Published.swift +++ b/Sources/Published.swift @@ -8,35 +8,34 @@ #if compiler(>=5.1) -import Foundation + import Foundation -internal protocol PublishedProtocol { - var willChangeSubject: PassthroughSubject { get } -} - -@propertyWrapper -public struct Published: PublishedProtocol { - - internal let willChangeSubject = PassthroughSubject() - internal let property: Property - - public init(wrappedValue: Value) { - property = Property(wrappedValue) + internal protocol PublishedProtocol { + var willChangeSubject: PassthroughSubject { get } } - public var wrappedValue: Value { - get { - return property.value + @propertyWrapper + public struct Published: PublishedProtocol { + internal let willChangeSubject = PassthroughSubject() + internal let property: Property + + public init(wrappedValue: Value) { + property = Property(wrappedValue) } - nonmutating set { - willChangeSubject.send() - property.value = newValue + + public var wrappedValue: Value { + get { + return property.value + } + nonmutating set { + willChangeSubject.send() + property.value = newValue + } } - } - public var projectedValue: Signal { - return property.toSignal() + public var projectedValue: Signal { + return property.toSignal() + } } -} #endif diff --git a/Sources/Reactive.swift b/Sources/Reactive.swift index a425123..9b8a938 100644 --- a/Sources/Reactive.swift +++ b/Sources/Reactive.swift @@ -40,21 +40,20 @@ public protocol ReactiveExtensions { public struct Reactive: ReactiveExtensions { public let base: Base - + public init(_ base: Base) { self.base = base } } -public protocol ReactiveExtensionsProvider: class {} +public protocol ReactiveExtensionsProvider: AnyObject {} extension ReactiveExtensionsProvider { - /// Reactive extensions of `self`. public var reactive: Reactive { return Reactive(self) } - + /// Reactive extensions of `Self`. public static var reactive: Reactive.Type { return Reactive.self @@ -65,17 +64,16 @@ extension NSObject: ReactiveExtensionsProvider {} #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) -extension ReactiveExtensions where Base: NSObject { - - /// A signal that fires completion event when the object is deallocated. - public var deallocated: SafeSignal { - return base.bag.deallocated - } - - /// A `DisposeBag` that can be used to dispose observations and bindings. - public var bag: DisposeBag { - return base.bag + extension ReactiveExtensions where Base: NSObject { + /// A signal that fires completion event when the object is deallocated. + public var deallocated: SafeSignal { + return base.bag.deallocated + } + + /// A `DisposeBag` that can be used to dispose observations and bindings. + public var bag: DisposeBag { + return base.bag + } } -} #endif diff --git a/Sources/Scheduler.swift b/Sources/Scheduler.swift index ccb3a7b..d7fcb24 100644 --- a/Sources/Scheduler.swift +++ b/Sources/Scheduler.swift @@ -22,18 +22,16 @@ // THE SOFTWARE. // -import Foundation import Dispatch +import Foundation /// A protocol that defines when and how to execute a closure. public protocol Scheduler { - /// Performs the action at the next possible opportunity. func schedule(_ action: @escaping () -> Void) } extension ExecutionContext: Scheduler { - @inlinable public func schedule(_ action: @escaping () -> Void) { context(action) @@ -41,7 +39,6 @@ extension ExecutionContext: Scheduler { } extension DispatchQueue: Scheduler { - @inlinable public func schedule(_ action: @escaping () -> Void) { async(execute: action) diff --git a/Sources/Signal.Event.swift b/Sources/Signal.Event.swift index 78bde4f..11bec02 100644 --- a/Sources/Signal.Event.swift +++ b/Sources/Signal.Event.swift @@ -23,10 +23,8 @@ // extension Signal { - /// An event of a sequence. public enum Event { - /// An event that carries next element. case next(Element) @@ -39,7 +37,6 @@ extension Signal { } extension Signal.Event { - /// Return `true` in case of `.next` event. public var isNext: Bool { switch self { @@ -49,7 +46,7 @@ extension Signal.Event { return false } } - + /// Return `true` in case of `.failed` event. public var isFailed: Bool { switch self { @@ -59,7 +56,7 @@ extension Signal.Event { return false } } - + /// Return `true` in case of `.completed` event. public var isCompleted: Bool { switch self { @@ -83,7 +80,7 @@ extension Signal.Event { /// Returns the next element, or nil if the event is not `.next` public var element: Element? { switch self { - case .next(let element): + case let .next(element): return element default: return nil @@ -93,7 +90,7 @@ extension Signal.Event { /// Return the failed error, or nil if the event is not `.failed` public var error: Error? { switch self { - case .failed(let error): + case let .failed(error): return error default: return nil diff --git a/Sources/Signal.swift b/Sources/Signal.swift index 219e050..40f5948 100644 --- a/Sources/Signal.swift +++ b/Sources/Signal.swift @@ -27,16 +27,15 @@ import Foundation /// A signal represents a sequence of elements. public struct Signal: SignalProtocol { - public typealias Producer = (AtomicObserver) -> Disposable - + private let producer: Producer - + /// Create a new signal given the producer closure. public init(_ producer: @escaping Producer) { self.producer = producer } - + /// Register the observer that will receive events from the signal. public func observe(with observer: @escaping Observer) -> Disposable { let observer = AtomicObserver(observer) @@ -49,7 +48,6 @@ public struct Signal: SignalProtocol { public typealias SafeSignal = Signal extension Signal { - /// Create a signal that completes immediately without emitting any elements. public static func completed() -> Signal { return Signal { observer in @@ -70,8 +68,8 @@ extension Signal { /// Create a signal that never completes and never fails. public static func never() -> Signal { - return Signal { observer in - return NonDisposable.instance + return Signal { _ in + NonDisposable.instance } } @@ -83,7 +81,6 @@ extension Signal { } extension Signal { - /// Create a signal that emits the given element and completes immediately. /// /// - Parameter element: An element to emit in the `next` event. @@ -124,7 +121,7 @@ extension Signal { /// - Parameter makeSignal: A closure to creates the signal. public init(deferring makeSignal: @escaping () -> Other) where Other.Element == Element, Other.Error == Error { self.init { observer in - return makeSignal().observe(with: observer) + makeSignal().observe(with: observer) } } @@ -135,9 +132,9 @@ extension Signal { public init(evaluating body: @escaping () -> Result) { self.init { observer in switch body() { - case .success(let element): + case let .success(element): observer.receive(lastElement: element) - case .failure(let error): + case let .failure(error): observer.receive(completion: .failure(error)) } return NonDisposable.instance @@ -206,14 +203,13 @@ extension Signal { /// Guaranteed to have the same number of elements as the given array of signals. public init(combiningLatest signals: S, combine: @escaping (_ elements: [S.Element.Element]) -> Element) where S.Element: SignalProtocol, S.Element.Error == Error { - self = signals.dropFirst().reduce(signals.first?.map { [$0] }) { (running, new) in - return running?.combineLatest(with: new) { $0 + [$1] } + self = signals.dropFirst().reduce(signals.first?.map { [$0] }) { running, new in + running?.combineLatest(with: new) { $0 + [$1] } }?.map(combine) ?? Signal.completed() } } extension Signal where Error == Swift.Error { - /// Create a new signal by evaluating a throwing closure, capturing the /// returned value as a next event followed by a completion event, or any thrown error as a failure event. /// @@ -224,7 +220,6 @@ extension Signal where Error == Swift.Error { } extension Signal where Error == Never { - /// Create a new signal and assign its next element observer to the given variable. /// Calling the closure assigned to the varaible will send the next element on the signal. /// @@ -239,7 +234,6 @@ extension Signal where Error == Never { } extension Signal where Element == Void, Error == Never { - /// Create a new signal and assign its next element observer to the given variable. /// Calling the closure assigned to the varaible will send the next element on the signal. /// diff --git a/Sources/SignalProtocol+Arities.swift b/Sources/SignalProtocol+Arities.swift index 4f225f5..ffa6a0b 100644 --- a/Sources/SignalProtocol+Arities.swift +++ b/Sources/SignalProtocol+Arities.swift @@ -34,251 +34,250 @@ private func tuple(a: A, b: B, c: C, d: D, e: E, f: F) -> (A, /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, combine: @escaping (A.Element, B.Element) -> Result) -> Signal + +(_ a: A, _ b: B, combine: @escaping (A.Element, B.Element) -> Result) -> Signal where A.Error == B.Error { - return a.combineLatest(with: b, combine: combine) + return a.combineLatest(with: b, combine: combine) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C, combine: @escaping (A.Element, B.Element, C.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, combine: @escaping (A.Element, B.Element, C.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error { - return combineLatest(a, b).combineLatest(with: c, combine: { combine($0.0, $0.1, $1) }) + return combineLatest(a, b).combineLatest(with: c, combine: { combine($0.0, $0.1, $1) }) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C, _ d: D, combine: @escaping (A.Element, B.Element, C.Element, D.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, combine: @escaping (A.Element, B.Element, C.Element, D.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error { - return combineLatest(a, b, c).combineLatest(with: d, combine: { combine($0.0, $0.1, $0.2, $1) }) + return combineLatest(a, b, c).combineLatest(with: d, combine: { combine($0.0, $0.1, $0.2, $1) }) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error { - return combineLatest(a, b, c, d).combineLatest(with: e, combine: { combine($0.0, $0.1, $0.2, $0.3, $1) }) + return combineLatest(a, b, c, d).combineLatest(with: e, combine: { combine($0.0, $0.1, $0.2, $0.3, $1) }) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error, A.Error == F.Error { - return combineLatest(a, b, c, d, e).combineLatest(with: f, combine: { combine($0.0, $0.1, $0.2, $0.3, $0.4, $1) }) + return combineLatest(a, b, c, d, e).combineLatest(with: f, combine: { combine($0.0, $0.1, $0.2, $0.3, $0.4, $1) }) } // MARK: Combine Latest with default combine. /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B) -> Signal<(A.Element, B.Element), A.Error> + +(_ a: A, _ b: B) -> Signal<(A.Element, B.Element), A.Error> where A.Error == B.Error { - return combineLatest(a, b, combine: tuple) + return combineLatest(a, b, combine: tuple) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C) -> Signal<(A.Element, B.Element, C.Element), A.Error> + +(_ a: A, _ b: B, _ c: C) -> Signal<(A.Element, B.Element, C.Element), A.Error> where A.Error == B.Error, A.Error == C.Error { - return combineLatest(a, b, c, combine: tuple) + return combineLatest(a, b, c, combine: tuple) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C, _ d: D) -> Signal<(A.Element, B.Element, C.Element, D.Element), A.Error> + +(_ a: A, _ b: B, _ c: C, _ d: D) -> Signal<(A.Element, B.Element, C.Element, D.Element), A.Error> where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error { - return combineLatest(a, b, c, d, combine: tuple) + return combineLatest(a, b, c, d, combine: tuple) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element), A.Error> + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element), A.Error> where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error { - return combineLatest(a, b, c, d, e, combine: tuple) + return combineLatest(a, b, c, d, e, combine: tuple) } /// Combine multiple signals into one. See `combineLatest(with:)` for more info. public func combineLatest - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element, F.Element), A.Error> + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element, F.Element), A.Error> where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error, A.Error == F.Error { - return combineLatest(a, b, c, d, e, f, combine: tuple) + return combineLatest(a, b, c, d, e, f, combine: tuple) } // MARK: Zip /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, combine: @escaping (A.Element, B.Element) -> Result) -> Signal + +(_ a: A, _ b: B, combine: @escaping (A.Element, B.Element) -> Result) -> Signal where A.Error == B.Error { - return a.zip(with: b, combine: combine) + return a.zip(with: b, combine: combine) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C, combine: @escaping (A.Element, B.Element, C.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, combine: @escaping (A.Element, B.Element, C.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error { - return zip(a, b).zip(with: c, combine: { combine($0.0, $0.1, $1) }) + return zip(a, b).zip(with: c, combine: { combine($0.0, $0.1, $1) }) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C, _ d: D, combine: @escaping (A.Element, B.Element, C.Element, D.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, combine: @escaping (A.Element, B.Element, C.Element, D.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error { - return zip(a, b, c).zip(with: d, combine: { combine($0.0, $0.1, $0.2, $1) }) + return zip(a, b, c).zip(with: d, combine: { combine($0.0, $0.1, $0.2, $1) }) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error { - return zip(a, b, c, d).zip(with: e, combine: { combine($0.0, $0.1, $0.2, $0.3, $1) }) + return zip(a, b, c, d).zip(with: e, combine: { combine($0.0, $0.1, $0.2, $0.3, $1) }) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element) -> Result) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F, combine: @escaping (A.Element, B.Element, C.Element, D.Element, E.Element, F.Element) -> Result) -> Signal where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error, A.Error == F.Error { - return zip(a, b, c, d, e).zip(with: f, combine: { combine($0.0, $0.1, $0.2, $0.3, $0.4, $1) }) + return zip(a, b, c, d, e).zip(with: f, combine: { combine($0.0, $0.1, $0.2, $0.3, $0.4, $1) }) } // MARK: Zip with default combine. /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B) -> Signal<(A.Element, B.Element), A.Error> + +(_ a: A, _ b: B) -> Signal<(A.Element, B.Element), A.Error> where A.Error == B.Error { - return zip(a, b, combine: tuple) + return zip(a, b, combine: tuple) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C) -> Signal<(A.Element, B.Element, C.Element), A.Error> + +(_ a: A, _ b: B, _ c: C) -> Signal<(A.Element, B.Element, C.Element), A.Error> where A.Error == B.Error, A.Error == C.Error { - return zip(a, b, c, combine: tuple) + return zip(a, b, c, combine: tuple) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C, _ d: D) -> Signal<(A.Element, B.Element, C.Element, D.Element), A.Error> + +(_ a: A, _ b: B, _ c: C, _ d: D) -> Signal<(A.Element, B.Element, C.Element, D.Element), A.Error> where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error { - return zip(a, b, c, d, combine: tuple) + return zip(a, b, c, d, combine: tuple) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element), A.Error> + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element), A.Error> where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error { - return zip(a, b, c, d, e, combine: tuple) + return zip(a, b, c, d, e, combine: tuple) } /// Zip multiple signals into one. See `zip(with:)` for more info. public func zip - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element, F.Element), A.Error> + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal<(A.Element, B.Element, C.Element, D.Element, E.Element, F.Element), A.Error> where A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error, A.Error == F.Error { - return zip(a, b, c, d, e, f, combine: tuple) + return zip(a, b, c, d, e, f, combine: tuple) } - // MARK: Merge /// Merge multiple signals into one. See `merge(with:)` for more info. public func merge - - (_ a: A, _ b: B) -> Signal + +(_ a: A, _ b: B) -> Signal where A.Element == B.Element, A.Error == B.Error { - return a.merge(with: b) + return a.merge(with: b) } /// Merge multiple signals into one. See `merge(with:)` for more info. public func merge - - (_ a: A, _ b: B, _ c: C) -> Signal + +(_ a: A, _ b: B, _ c: C) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Error == B.Error, A.Error == C.Error { - return merge(a, b).merge(with: c) + return merge(a, b).merge(with: c) } /// Merge multiple signals into one. See `merge(with:)` for more info. public func merge - - (_ a: A, _ b: B, _ c: C, _ d: D) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Element == D.Element, A.Error == B.Error, A.Error == C.Error, A.Error == D.Error { - return merge(a, b, c).merge(with: d) + return merge(a, b, c).merge(with: d) } /// Merge multiple signals into one. See `merge(with:)` for more info. public func merge - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Element == D.Element, A.Element == E.Element, A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error { - return merge(a, b, c, d).merge(with: e) + return merge(a, b, c, d).merge(with: e) } /// Merge multiple signals into one. See `merge(with:)` for more info. public func merge - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Element == D.Element, A.Element == E.Element, A.Element == F.Element, A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error, A.Error == F.Error { - return merge(a, b, c, d, e).merge(with: f) + return merge(a, b, c, d, e).merge(with: f) } // MARK: Amb /// Amb multiple signals into one. See `amb(with:)` for more info. public func amb - - (_ a: A, _ b: B) -> Signal + +(_ a: A, _ b: B) -> Signal where A.Element == B.Element, A.Error == B.Error { - return a.amb(with: b) + return a.amb(with: b) } /// Amb multiple signals into one. See `amb(with:)` for more info. public func amb - - (_ a: A, _ b: B, _ c: C) -> Signal + +(_ a: A, _ b: B, _ c: C) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Error == B.Error, A.Error == C.Error { - return amb(a, b).amb(with: c) + return amb(a, b).amb(with: c) } /// Amb multiple signals into one. See `amb(with:)` for more info. public func amb - - (_ a: A, _ b: B, _ c: C, _ d: D) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Element == D.Element, A.Error == B.Error, A.Error == C.Error, A.Error == D.Error { - return amb(a, b, c).amb(with: d) + return amb(a, b, c).amb(with: d) } /// Amb multiple signals into one. See `amb(with:)` for more info. public func amb - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Element == D.Element, A.Element == E.Element, A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error { - return amb(a, b, c, d).amb(with: e) + return amb(a, b, c, d).amb(with: e) } /// Amb multiple signals into one. See `amb(with:)` for more info. public func amb - - (_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal + +(_ a: A, _ b: B, _ c: C, _ d: D, _ e: E, _ f: F) -> Signal where A.Element == B.Element, A.Element == C.Element, A.Element == D.Element, A.Element == E.Element, A.Element == F.Element, A.Error == B.Error, A.Error == C.Error, A.Error == D.Error, A.Error == E.Error, A.Error == F.Error { - return amb(a, b, c, d, e).amb(with: f) + return amb(a, b, c, d, e).amb(with: f) } diff --git a/Sources/SignalProtocol+Combining.swift b/Sources/SignalProtocol+Combining.swift index 086c42c..f443f24 100644 --- a/Sources/SignalProtocol+Combining.swift +++ b/Sources/SignalProtocol+Combining.swift @@ -25,7 +25,6 @@ import Foundation extension SignalProtocol { - /// Propagate elements only from the signal that starts emitting first. Also known as the `race` operator. /// /// Check out interactive example at [https://rxmarbles.com/#race](https://rxmarbles.com/#race) @@ -60,7 +59,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#race](https://rxmarbles.com/#race) public func amb(with other: O) -> Signal where O.Element == Element, O.Error == Never { - return amb(with: (other.castError() as Signal)) + return amb(with: other.castError() as Signal) } /// Emit a combination of latest elements from each signal. Starts when both signals emit at least one element. @@ -80,17 +79,17 @@ extension SignalProtocol { } } func _onAnyCompleted() { - if _completions.me == true && _completions.other == true { + if _completions.me == true, _completions.other == true { observer.receive(completion: .finished) } } compositeDisposable += self.observe { event in lock.lock(); defer { lock.unlock() } switch event { - case .next(let element): + case let .next(element): _elements.my = element _onAnyNext() - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: _completions.me = true @@ -100,10 +99,10 @@ extension SignalProtocol { compositeDisposable += other.observe { event in lock.lock(); defer { lock.unlock() } switch event { - case .next(let element): + case let .next(element): _elements.other = element _onAnyNext() - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: _completions.other = true @@ -127,7 +126,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#combineLatest](https://rxmarbles.com/#combineLatest) public func combineLatest(with other: O, combine: @escaping (Element, O.Element) -> U) -> Signal where O.Error == Never { - return combineLatest(with: (other.castError() as Signal), combine: combine) + return combineLatest(with: other.castError() as Signal, combine: combine) } /// Emit a pair of the latest elements from each signal. Starts when both signals emit at least one element. @@ -135,7 +134,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#combineLatest](https://rxmarbles.com/#combineLatest) public func combineLatest(with other: O) -> Signal<(Element, O.Element), Error> where O.Error == Never { - return combineLatest(with: (other.castError() as Signal)) + return combineLatest(with: other.castError() as Signal) } /// First propagate all elements from the source signal and then all elements from the `other` signal. @@ -146,9 +145,9 @@ extension SignalProtocol { let serialDisposable = SerialDisposable(otherDisposable: nil) serialDisposable.otherDisposable = self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: serialDisposable.otherDisposable = other.observe(with: observer.on) @@ -162,7 +161,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#concat](https://rxmarbles.com/#concat) public func append(_ other: O) -> Signal where O.Element == Element, O.Error == Never { - return append((other.castError() as Signal)) + return append(other.castError() as Signal) } /// First propagate all elements from the other signal and then all elements from the source signal. @@ -176,7 +175,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#concat](https://rxmarbles.com/#concat) public func prepend(_ other: O) -> Signal where O.Element == Element, O.Error == Never { - return prepend((other.castError() as Signal)) + return prepend(other.castError() as Signal) } /// Merge emissions from both the receiver and the `other` signal into one signal. @@ -195,7 +194,7 @@ extension SignalProtocol { /// Replay the latest element when the other signal emits an element. public func replayLatest(when other: S) -> Signal where S.Error == Never { - return combineLatest(with: other.scan((), { _, _ in }).castError()) { my, _ in my } + return combineLatest(with: other.scan(()) { _, _ in }.castError()) { my, _ in my } } /// Combine the receiver and the `other` signal into a signal whose elements are combinations of the @@ -209,10 +208,10 @@ extension SignalProtocol { let compositeDisposable = CompositeDisposable() compositeDisposable += other.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } _latest = element - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: break @@ -222,9 +221,9 @@ extension SignalProtocol { switch event { case .completed: observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } if let latest = _latest { observer.receive(combine(element, latest)) @@ -248,7 +247,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#withLatestFrom](https://rxmarbles.com/#withLatestFrom) public func with(latestFrom other: O, combine: @escaping (Element, O.Element) -> U) -> Signal where O.Error == Never { - return with(latestFrom: (other.castError() as Signal), combine: combine) + return with(latestFrom: other.castError() as Signal, combine: combine) } /// Combine the receiver and the `other` signal into a signal whose elements are combinations of the @@ -256,7 +255,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#withLatestFrom](https://rxmarbles.com/#withLatestFrom) public func with(latestFrom other: O) -> Signal<(Element, O.Element), Error> where O.Error == Never { - return with(latestFrom: (other.castError() as Signal)) + return with(latestFrom: other.castError() as Signal) } /// Zip elements from the receiver and the `other` signal. @@ -270,7 +269,7 @@ extension SignalProtocol { var _completions: (me: Bool, other: Bool) = (false, false) let compositeDisposable = CompositeDisposable() let _dispatchIfPossible = { - while !_buffers.my.isEmpty && !_buffers.other.isEmpty { + while !_buffers.my.isEmpty, !_buffers.other.isEmpty { let element = combine(_buffers.my[0], _buffers.other[0]) observer.receive(element) _buffers.my.removeFirst() @@ -285,9 +284,9 @@ extension SignalProtocol { compositeDisposable += self.observe { event in lock.lock(); defer { lock.unlock() } switch event { - case .next(let element): + case let .next(element): _buffers.my.append(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: _completions.me = true @@ -298,9 +297,9 @@ extension SignalProtocol { compositeDisposable += other.observe { event in lock.lock(); defer { lock.unlock() } switch event { - case .next(let element): + case let .next(element): _buffers.other.append(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: _completions.other = true @@ -325,7 +324,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#zip](https://rxmarbles.com/#zip) public func zip(with other: O, combine: @escaping (Element, O.Element) -> U) -> Signal where O.Error == Never { - return zip(with: (other.castError() as Signal), combine: combine) + return zip(with: other.castError() as Signal, combine: combine) } /// Zip elements from the receiver and the `other` signal. @@ -333,12 +332,11 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#zip](https://rxmarbles.com/#zip) public func zip(with other: O) -> Signal<(Element, O.Element), Error> where O.Error == Never { - return zip(with: (other.castError() as Signal)) + return zip(with: other.castError() as Signal) } } extension SignalProtocol where Error == Never { - /// Propagate elements only from the signal that starts emitting first. Also known as the `race` operator. /// /// Check out interactive example at [https://rxmarbles.com/#race](https://rxmarbles.com/#race) diff --git a/Sources/SignalProtocol+ErrorHandling.swift b/Sources/SignalProtocol+ErrorHandling.swift index 577dccd..e294920 100644 --- a/Sources/SignalProtocol+ErrorHandling.swift +++ b/Sources/SignalProtocol+ErrorHandling.swift @@ -25,15 +25,14 @@ import Foundation extension SignalProtocol { - /// Transform error by applying `transform` on it. public func mapError(_ transform: @escaping (Error) -> F) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(transform(error))) case .completed: observer.receive(completion: .finished) @@ -57,11 +56,11 @@ extension SignalProtocol { /// Convert signal into a non-failable signal by suppressing the error. public func suppressError(logging: Bool, file: String = #file, line: Int = #line) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .finished) if logging { print("Signal at \(file):\(line) encountered an error: \(error)") @@ -81,9 +80,9 @@ extension SignalProtocol { /// Recover the signal by propagating default element if an error happens. public func replaceError(with element: Element) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(element) case .failed: observer.receive(element) @@ -107,9 +106,9 @@ extension SignalProtocol { serialDisposable.otherDisposable?.dispose() serialDisposable.otherDisposable = self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): lock.lock(); defer { lock.unlock() } if _remainingAttempts > 0 { _remainingAttempts -= 1 @@ -149,14 +148,14 @@ extension SignalProtocol { serialDisposable.otherDisposable = compositeDisposable compositeDisposable += self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(element) case .completed: lock.lock(); defer { lock.unlock() } _attempt = nil serialDisposable.otherDisposable?.dispose() observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): if shouldRetry(error) { compositeDisposable += other.first().observe { otherEvent in lock.lock(); defer { lock.unlock() } @@ -194,7 +193,7 @@ extension SignalProtocol { let lock = NSRecursiveLock(name: "com.reactive_kit.signal.timeout") var _completed = false let timeoutWhenPossible: () -> Disposable = { - return queue.disposableAfter(when: interval) { + queue.disposableAfter(when: interval) { lock.lock(); defer { lock.unlock() } if !_completed { _completed = true @@ -216,13 +215,13 @@ extension SignalProtocol { /// Map failable signal into a non-failable signal of errors. Ignores `.next` events. public func toErrorSignal() -> Signal { return Signal { observer in - return self.observe { taskEvent in + self.observe { taskEvent in switch taskEvent { case .next: break case .completed: observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): observer.receive(error) observer.receive(completion: .finished) } @@ -232,13 +231,12 @@ extension SignalProtocol { } extension SignalProtocol where Error == Never { - /// Safe error casting from Never to some Error type. public func castError() -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(element) case .completed: observer.receive(completion: .finished) diff --git a/Sources/SignalProtocol+Event.swift b/Sources/SignalProtocol+Event.swift index 9b9ccee..c121284 100644 --- a/Sources/SignalProtocol+Event.swift +++ b/Sources/SignalProtocol+Event.swift @@ -25,15 +25,14 @@ import Foundation extension SignalProtocol { - /// Unwrap events into elements. public func materialize() -> Signal.Event, Never> { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(.next(element)) - case .failed(let error): + case let .failed(error): observer.receive(.failed(error)) observer.receive(completion: .finished) case .completed: @@ -47,18 +46,18 @@ extension SignalProtocol { /// Inverse of `materialize`. public func dematerialize() -> Signal where Element == Signal.Event, E == Error { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let innerEvent): + case let .next(innerEvent): switch innerEvent { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: observer.receive(completion: .finished) } - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: observer.receive(completion: .finished) @@ -69,7 +68,6 @@ extension SignalProtocol { } extension SignalProtocol where Error == Never { - /// Inverse of `materialize`. public func dematerialize() -> Signal where Element == Signal.Event { return (castError() as Signal).dematerialize() diff --git a/Sources/SignalProtocol+Filtering.swift b/Sources/SignalProtocol+Filtering.swift index 18189aa..b08e3c8 100644 --- a/Sources/SignalProtocol+Filtering.swift +++ b/Sources/SignalProtocol+Filtering.swift @@ -25,7 +25,6 @@ import Foundation extension SignalProtocol { - /// Emit an element only if `interval` time passes without emitting another element. /// /// Check out interactive example at [https://rxmarbles.com/#debounceTime](https://rxmarbles.com/#debounceTime) @@ -39,7 +38,7 @@ extension SignalProtocol { timerSubscription?.dispose() lock.unlock() switch event { - case .next(let element): + case let .next(element): lock.lock() previousElement = element timerSubscription = queue.disposableAfter(when: seconds) { @@ -50,7 +49,7 @@ extension SignalProtocol { } } lock.unlock() - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: if let previousElement = previousElement { @@ -58,7 +57,6 @@ extension SignalProtocol { observer.receive(completion: .finished) } } - } } } @@ -84,9 +82,9 @@ extension SignalProtocol { /// Check out interactive example at [https://rxmarbles.com/#filter](https://rxmarbles.com/#filter) public func filter(_ isIncluded: @escaping (Element) -> Bool) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): if isIncluded(element) { observer.receive(element) } @@ -101,7 +99,7 @@ extension SignalProtocol { /// propagate that element only if the returned signal emits `true`. public func flatMapFilter(_ strategy: FlattenStrategy = .concat, _ isIncluded: @escaping (Element) -> SafeSignal) -> Signal { return flatMap(strategy) { element -> Signal in - return isIncluded(element) + isIncluded(element) .first() .map { isIncluded -> Element? in if isIncluded { @@ -132,8 +130,8 @@ extension SignalProtocol { /// Ignore all terminal events (just propagate next events). The signal will never complete or error out. public func ignoreTerminal() -> Signal { return Signal { observer in - return self.observe { event in - if case .next(let element) = event { + self.observe { event in + if case let .next(element) = event { observer.receive(element) } } @@ -180,7 +178,7 @@ extension SignalProtocol { queue.asyncAfter(deadline: .now() + interval) { lock.lock(); defer { lock.unlock() } guard !serialDisposable.isDisposed else { - _dispatch = nil; + _dispatch = nil return } if let element = _latestElement { @@ -192,7 +190,7 @@ extension SignalProtocol { } serialDisposable.otherDisposable = self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } _latestElement = element default: @@ -215,7 +213,7 @@ extension SignalProtocol { var _count = count return self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } if _count > 0 { _count -= 1 @@ -233,13 +231,13 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#skip](https://rxmarbles.com/#skip) public func dropLast(_ count: Int) -> Signal { - guard count > 0 else { return self.toSignal() } + guard count > 0 else { return toSignal() } return Signal { observer in let lock = NSRecursiveLock(name: "com.reactive_kit.signal.skip") var _buffer: [Element] = [] return self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } _buffer.append(element) if _buffer.count > count { @@ -279,7 +277,7 @@ extension SignalProtocol { var _taken = 0 return self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } if _taken < maxLength { _taken += 1 @@ -303,15 +301,15 @@ extension SignalProtocol { let lock = NSRecursiveLock(name: "com.reactive_kit.signal.take") var _values: [Element] = [] _values.reserveCapacity(maxLength) - return self.observe(with: { (event) in + return self.observe(with: { event in switch event { case .completed: lock.lock(); defer { lock.unlock() } _values.forEach(observer.receive(_:)) observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) - case .next(let element): + case let .next(element): if event.isTerminal { observer.on(event) } else { @@ -331,9 +329,9 @@ extension SignalProtocol { /// Check out interactive example at [https://rxmarbles.com/#takeWhile](https://rxmarbles.com/#takeWhile) public func prefix(while shouldContinue: @escaping (Element) -> Bool) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): if shouldContinue(element) { observer.receive(element) } else { @@ -358,9 +356,9 @@ extension SignalProtocol { switch event { case .completed: observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) - case .next(let element): + case let .next(element): observer.receive(element) } } @@ -377,7 +375,7 @@ extension SignalProtocol { var _lastEventTime: DispatchTime? return self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } let now = DispatchTime.now() if _lastEventTime == nil || now.rawValue > (_lastEventTime! + seconds).rawValue { @@ -393,7 +391,6 @@ extension SignalProtocol { } extension SignalProtocol where Element: Equatable { - /// Emit first element and then all elements that are not equal to their predecessor(s). /// /// Check out interactive example at [https://rxmarbles.com/#distinctUntilChanged](https://rxmarbles.com/#distinctUntilChanged) diff --git a/Sources/SignalProtocol+Monad.swift b/Sources/SignalProtocol+Monad.swift index cffb269..b4cd8ce 100644 --- a/Sources/SignalProtocol+Monad.swift +++ b/Sources/SignalProtocol+Monad.swift @@ -25,17 +25,16 @@ import Foundation extension SignalProtocol { - /// Transform each element by applying `transform` on it. /// /// Check out interactive example at [https://rxmarbles.com/#map](https://rxmarbles.com/#map) public func map(_ transform: @escaping (Element) -> U) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): observer.receive(transform(element)) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: observer.receive(completion: .finished) @@ -85,11 +84,11 @@ extension SignalProtocol { let serialDisposable = SerialDisposable(otherDisposable: nil) serialDisposable.otherDisposable = self.observe { taskEvent in switch taskEvent { - case .next(let value): + case let .next(value): observer.receive(value) case .completed: observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): serialDisposable.otherDisposable = recover(error).observe(with: observer.on) } } @@ -99,22 +98,21 @@ extension SignalProtocol { } extension SignalProtocol where Error == Swift.Error { - /// Transform each element by applying `transform` on it. /// Throwing an error will be emitted as `.failed` event on the Signal. /// /// Check out interactive example at [https://rxmarbles.com/#map](https://rxmarbles.com/#map) public func map(_ transform: @escaping (Element) throws -> U) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): do { observer.receive(try transform(element)) } catch { observer.receive(completion: .failure(error)) } - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: observer.receive(completion: .finished) @@ -127,7 +125,6 @@ extension SignalProtocol where Error == Swift.Error { /// Flattening strategy defines how to flatten (join) inner signals into one, flattened, signal. /// - Tag: FlattenStrategy public enum FlattenStrategy { - /// Flatten the signal by sequentially observing inner signals in order in which they /// arrive, starting next observation only after previous one completes. case concat @@ -141,7 +138,6 @@ public enum FlattenStrategy { } extension SignalProtocol where Element: SignalProtocol, Element.Error == Error { - public typealias InnerElement = Element.Element /// Flatten the signal using the given strategy. @@ -172,21 +168,21 @@ extension SignalProtocol where Element: SignalProtocol, Element.Error == Error { } compositeDisposable += self.observe { outerEvent in switch outerEvent { - case .next(let innerSignal): + case let .next(innerSignal): lock.lock(); defer { lock.unlock() } _numberOfOperations += 1 compositeDisposable += innerSignal.observe { innerEvent in switch innerEvent { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: lock.lock(); defer { lock.unlock() } _decrementNumberOfOperations() } } - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: lock.lock(); defer { lock.unlock() } @@ -206,15 +202,15 @@ extension SignalProtocol where Element: SignalProtocol, Element.Error == Error { var _completions = (outer: false, inner: false) compositeDisposable += self.observe { outerEvent in switch outerEvent { - case .next(let innerSignal): + case let .next(innerSignal): lock.lock(); defer { lock.unlock() } _completions.inner = false serialDisposable.otherDisposable?.dispose() serialDisposable.otherDisposable = innerSignal.observe { innerEvent in switch innerEvent { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: lock.lock(); defer { lock.unlock() } @@ -224,7 +220,7 @@ extension SignalProtocol where Element: SignalProtocol, Element.Error == Error { } } } - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: lock.lock(); defer { lock.unlock() } @@ -255,9 +251,9 @@ extension SignalProtocol where Element: SignalProtocol, Element.Error == Error { serialDisposable.otherDisposable = innerSignal.observe { event in lock.lock(); defer { lock.unlock() } switch event { - case .next(let element): + case let .next(element): observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: _completions.inner = true @@ -272,12 +268,12 @@ extension SignalProtocol where Element: SignalProtocol, Element.Error == Error { compositeDisposable += self.observe { outerEvent in lock.lock(); defer { lock.unlock() } switch outerEvent { - case .next(let innerSignal): + case let .next(innerSignal): _innerSignalQueue.append(innerSignal) if _completions.inner { _startNextOperation() } - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: _completions.outer = true @@ -292,7 +288,6 @@ extension SignalProtocol where Element: SignalProtocol, Element.Error == Error { } extension SignalProtocol where Error == Never { - /// Map each element into a signal and then flatten inner signals using the given strategy. /// `flatMap` is just a shorthand for `map(transform).flatten(strategy)`. /// @@ -308,7 +303,7 @@ extension SignalProtocol where Error == Never { /// Shorthand for `flatMap(.concat, transform)`. /// /// Check out interactive example at [https://rxmarbles.com/#concatMap](https://rxmarbles.com/#concatMap) - public func flatMapConcat(_ transform: @escaping (Element) -> O) -> Signal { + public func flatMapConcat(_ transform: @escaping (Element) -> O) -> Signal { return flatMap(.concat, transform) } @@ -330,7 +325,6 @@ extension SignalProtocol where Error == Never { } extension SignalProtocol where Element: SignalProtocol, Error == Never { - /// Flatten the signal using the given strategy. /// /// - parameter strategy: Flattening strategy to use. Check out [FlattenStrategy](x-source-tag://FlattenStrategy) type from more info. diff --git a/Sources/SignalProtocol+Optional.swift b/Sources/SignalProtocol+Optional.swift index 15e3f61..9a5fb0a 100644 --- a/Sources/SignalProtocol+Optional.swift +++ b/Sources/SignalProtocol+Optional.swift @@ -25,7 +25,6 @@ import Foundation extension SignalProtocol { - /// Map element into a result, propagating `.some` value as a next event or skipping an element in case of a `nil`. /// Shorthand for `map(transform).ignoreNils()`. public func compactMap(_ transform: @escaping (Element) -> NewWrapped?) -> Signal { @@ -34,7 +33,6 @@ extension SignalProtocol { } extension SignalProtocol where Element: OptionalProtocol { - /// Map inner optional. /// Shorthand for `map { $0.map(transform) }`. public func mapWrapped(_ transform: @escaping (Element.Wrapped) -> NewWrapped) -> Signal { @@ -49,13 +47,13 @@ extension SignalProtocol where Element: OptionalProtocol { /// Suppress all `nil`-elements. public func ignoreNils() -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let element): + case let .next(element): if let element = element._unbox { observer.receive(element) } - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: observer.receive(completion: .finished) @@ -67,14 +65,13 @@ extension SignalProtocol where Element: OptionalProtocol { public protocol OptionalProtocol { associatedtype Wrapped - var _unbox: Optional { get } + var _unbox: Wrapped? { get } init(nilLiteral: ()) init(_ some: Wrapped) } extension Optional: OptionalProtocol { - - public var _unbox: Optional { + public var _unbox: Wrapped? { return self } } diff --git a/Sources/SignalProtocol+Result.swift b/Sources/SignalProtocol+Result.swift index 513e586..6598c6e 100644 --- a/Sources/SignalProtocol+Result.swift +++ b/Sources/SignalProtocol+Result.swift @@ -25,14 +25,13 @@ import Foundation extension SignalProtocol { - /// Maps signal elements into `Result.success` elements and signal errors into `Result.failure` elements. public func mapToResult() -> Signal, Never> { return materialize().compactMap { (event) -> Result? in switch event { - case .next(let element): + case let .next(element): return .success(element) - case .failed(let error): + case let .failed(error): return .failure(error) case .completed: return nil @@ -48,7 +47,6 @@ extension SignalProtocol { } extension SignalProtocol where Error == Never { - /// Map element into a result, propagating success value as a next event or failure as a failed event. /// Shorthand for `map(transform).getValues()`. public func tryMap(_ transform: @escaping (Element) -> Result) -> Signal { @@ -57,7 +55,6 @@ extension SignalProtocol where Error == Never { } extension SignalProtocol where Element: _ResultProtocol { - /// Map inner result. /// Shorthand for `map { $0.map(transform) }`. public func mapValue(_ transform: @escaping (Element.Value) -> NewSuccess) -> Signal, Error> { @@ -66,23 +63,22 @@ extension SignalProtocol where Element: _ResultProtocol { } extension SignalProtocol where Element: _ResultProtocol, Error == Element.Error { - /// Unwraps values from result elements into elements of the signal. /// A failure result will trigger signal failure. public func getValues() -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let result): + case let .next(result): switch result._unbox { - case .success(let element): + case let .success(element): observer.receive(element) - case .failure(let error): + case let .failure(error): observer.receive(completion: .failure(error)) } case .completed: observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) } } @@ -91,7 +87,6 @@ extension SignalProtocol where Element: _ResultProtocol, Error == Element.Error } extension SignalProtocol where Element: _ResultProtocol, Error == Never { - /// Unwraps values from result elements into elements of the signal. /// A failure result will trigger signal failure. public func getValues() -> Signal { @@ -106,7 +101,6 @@ public protocol _ResultProtocol { } extension Result: _ResultProtocol { - public var _unbox: Result { return self } diff --git a/Sources/SignalProtocol+Sequence.swift b/Sources/SignalProtocol+Sequence.swift index 2cc8d10..c32e64c 100644 --- a/Sources/SignalProtocol+Sequence.swift +++ b/Sources/SignalProtocol+Sequence.swift @@ -25,7 +25,6 @@ import Foundation extension SignalProtocol { - /// Map element into a collection, flattening the collection into next elements. /// Shorthand for `map(transform).flattenElements()`. public func flatMap(_ transform: @escaping (Element) -> [NewElement]) -> Signal { @@ -34,7 +33,6 @@ extension SignalProtocol { } extension SignalProtocol where Element: Sequence { - /// Map inner sequence. public func mapElement(_ transform: @escaping (Element.Iterator.Element) -> NewElement) -> Signal<[NewElement], Error> { return map { $0.map(transform) } @@ -43,13 +41,13 @@ extension SignalProtocol where Element: Sequence { /// Unwrap elements from each emitted sequence into the elements of the signal. public func flattenElements() -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in switch event { - case .next(let sequence): + case let .next(sequence): sequence.forEach(observer.receive(_:)) case .completed: observer.receive(completion: .finished) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) } } diff --git a/Sources/SignalProtocol+Threading.swift b/Sources/SignalProtocol+Threading.swift index 0510e6d..05e459a 100644 --- a/Sources/SignalProtocol+Threading.swift +++ b/Sources/SignalProtocol+Threading.swift @@ -25,7 +25,6 @@ import Foundation extension SignalProtocol { - /// Set the scheduler on which to execute the signal (i.e. to run the signal's producer). /// /// In contrast with `receive(on:)`, which affects downstream actions, `subscribe(on:)` changes the execution context of upstream actions. @@ -46,7 +45,7 @@ extension SignalProtocol { /// In contrast with `subscribe(on:)`, which affects upstream actions, `receive(on:)` changes the execution context of downstream actions. public func receive(on scheduler: S) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in scheduler.schedule { observer.on(event) } diff --git a/Sources/SignalProtocol+Transforming.swift b/Sources/SignalProtocol+Transforming.swift index 9ff3a1d..c2bbf46 100644 --- a/Sources/SignalProtocol+Transforming.swift +++ b/Sources/SignalProtocol+Transforming.swift @@ -25,7 +25,6 @@ import Foundation extension SignalProtocol { - /// Batch signal elements into arrays of the given size. /// /// Check out interactive example at [https://rxmarbles.com/#bufferCount](https://rxmarbles.com/#bufferCount) @@ -35,14 +34,14 @@ extension SignalProtocol { var _buffer: [Element] = [] return self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } _buffer.append(element) if _buffer.count == size { observer.receive(_buffer) _buffer.removeAll() } - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: observer.receive(completion: .finished) @@ -53,7 +52,7 @@ extension SignalProtocol { /// Collect all elements into an array and emit the array as a single element. public func collect() -> Signal<[Element], Error> { - return reduce([], { memo, new in memo + [new] }) + return reduce([]) { memo, new in memo + [new] } } /// Emit default element if the signal completes without emitting any element. @@ -65,11 +64,11 @@ extension SignalProtocol { var _didEmitNonTerminal = false return self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } _didEmitNonTerminal = true observer.receive(element) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: lock.lock(); defer { lock.unlock() } @@ -118,11 +117,11 @@ extension SignalProtocol { observer.receive(_accumulator) return self.observe { event in switch event { - case .next(let element): + case let .next(element): lock.lock(); defer { lock.unlock() } _accumulator = combine(_accumulator, element) observer.receive(_accumulator) - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) case .completed: observer.receive(completion: .finished) @@ -135,7 +134,7 @@ extension SignalProtocol { /// /// Check out interactive example at [https://rxmarbles.com/#startWith](https://rxmarbles.com/#startWith) public func prepend(_ element: Element) -> Signal { - return scan(element, { _, next in next }) + return scan(element) { _, next in next } } /// Append the given element to the signal element sequence. @@ -151,6 +150,6 @@ extension SignalProtocol { /// Par each element with its predecessor. /// Similar to `parwise`, but starts from the first element which is paird with `nil`. public func zipPrevious() -> Signal<(Element?, Element), Error> { - return scan(nil) { (pair, next) in (pair?.1, next) }.ignoreNils() + return scan(nil) { pair, next in (pair?.1, next) }.ignoreNils() } } diff --git a/Sources/SignalProtocol+Utilities.swift b/Sources/SignalProtocol+Utilities.swift index c53d07e..d862389 100644 --- a/Sources/SignalProtocol+Utilities.swift +++ b/Sources/SignalProtocol+Utilities.swift @@ -25,7 +25,6 @@ import Foundation extension SignalProtocol { - /// Raises a debugger signal when a provided closure needs to stop the process in the debugger. /// /// When any of the provided closures returns `true`, this signal raises the `SIGTRAP` signal to stop the process in the debugger. @@ -39,19 +38,20 @@ extension SignalProtocol { @inlinable public func breakpoint(receiveSubscription: (() -> Bool)? = nil, receiveOutput: ((Element) -> Bool)? = nil, receiveCompletion: ((Subscribers.Completion) -> Bool)? = nil) -> Signal { return handleEvents( - receiveSubscription: { + receiveSubscription: { if receiveSubscription?() ?? false { raise(SIGTRAP) } - }, receiveOutput: { (element) in - if receiveOutput?(element) ?? false { - raise(SIGTRAP) - } - }, receiveCompletion: { (completion) in - if receiveCompletion?(completion) ?? false { - raise(SIGTRAP) + }, receiveOutput: { element in + if receiveOutput?(element) ?? false { + raise(SIGTRAP) + } + }, receiveCompletion: { completion in + if receiveCompletion?(completion) ?? false { + raise(SIGTRAP) + } } - }) + ) } /// Raises a debugger signal upon receiving a failure. @@ -81,28 +81,29 @@ extension SignalProtocol { prefix = "[\(filename):\(function):\(line)]" } return handleEvents( - receiveSubscription: { + receiveSubscription: { print("\(prefix) started") - }, receiveOutput: { (element) in - print("\(prefix) next(\(element))") - }, receiveCompletion: { (completion) in - switch completion { - case .failure(let error): - print("\(prefix) failed: \(error)") - case .finished: - print("\(prefix) finished") + }, receiveOutput: { element in + print("\(prefix) next(\(element))") + }, receiveCompletion: { completion in + switch completion { + case let .failure(error): + print("\(prefix) failed: \(error)") + case .finished: + print("\(prefix) finished") + } + }, receiveCancel: { + print("\(prefix) disposed") } - }, receiveCancel: { - print("\(prefix) disposed") - }) + ) } - + /// Delay signal elements for `interval` time. /// /// Check out interactive example at [https://rxmarbles.com/#delay](https://rxmarbles.com/#delay) public func delay(interval: Double, on queue: DispatchQueue = DispatchQueue(label: "reactive_kit.delay")) -> Signal { return Signal { observer in - return self.observe { event in + self.observe { event in queue.asyncAfter(deadline: .now() + interval) { observer.on(event) } @@ -119,7 +120,7 @@ extension SignalProtocol { let innerDisposable = SerialDisposable(otherDisposable: nil) var _completions: (me: Bool, other: Bool) = (false, false) func _completeIfPossible() { - if _completions.me && _completions.other { + if _completions.me, _completions.other { observer.receive(completion: .finished) _attempt = nil } @@ -129,7 +130,7 @@ extension SignalProtocol { outerDisposable.otherDisposable = self.observe { event in lock.lock(); defer { lock.unlock() } switch event { - case .next(let element): + case let .next(element): observer.receive(element) _completions.other = false innerDisposable.otherDisposable?.dispose() @@ -147,7 +148,7 @@ extension SignalProtocol { case .completed: _completions.me = true _completeIfPossible() - case .failed(let error): + case let .failed(error): observer.receive(completion: .failure(error)) } } @@ -172,9 +173,9 @@ extension SignalProtocol { receiveSubscription?() let disposable = self.observe { event in switch event { - case .next(let value): + case let .next(value): receiveOutput?(value) - case .failed(let error): + case let .failed(error): receiveCompletion?(.failure(error)) case .completed: receiveCompletion?(.finished) @@ -207,7 +208,7 @@ extension SignalProtocol { public func feedError(into listener: S) -> Signal where S.Element == Error { return handleEvents(receiveCompletion: { completion in switch completion { - case .failure(let error): + case let .failure(error): listener.send(error) case .finished: break @@ -235,7 +236,7 @@ extension SignalProtocol { public func waitAndCollectElements() -> [Element] { return waitAndCollectEvents().compactMap { event in switch event { - case .next(let element): + case let .next(element): return element default: return nil diff --git a/Sources/SignalProtocol.swift b/Sources/SignalProtocol.swift index 42e738b..e7571e5 100644 --- a/Sources/SignalProtocol.swift +++ b/Sources/SignalProtocol.swift @@ -27,7 +27,6 @@ import Foundation /// Represents a sequence of events. public protocol SignalProtocol { - /// The type of elements generated by the signal. associatedtype Element @@ -41,17 +40,16 @@ public protocol SignalProtocol { } extension SignalProtocol { - /// Register an observer that will receive events from a signal. public func observe(with observer: O) -> Disposable where O.Element == Element, O.Error == Error { - return observe(with: observer.on) + return observe(with: observer.on) } /// Register an observer that will receive elements from `.next` events of the signal. public func observeNext(with observer: @escaping (Element) -> Void) -> Disposable { return observe { event in - if case .next(let element) = event { + if case let .next(element) = event { observer(element) } } @@ -60,7 +58,7 @@ extension SignalProtocol { /// Register an observer that will receive elements from `.failed` events of the signal. public func observeFailed(with observer: @escaping (Error) -> Void) -> Disposable { return observe { event in - if case .failed(let error) = event { + if case let .failed(error) = event { observer(error) } } @@ -77,12 +75,11 @@ extension SignalProtocol { /// Convert the receiver to a concrete signal. public func toSignal() -> Signal { - return (self as? Signal) ?? Signal(self.observe) + return (self as? Signal) ?? Signal(observe) } } extension SignalProtocol { - /// Attaches a subscriber with closure-based behavior. /// /// This method creates the subscriber and immediately requests an unlimited number of values, prior to returning the subscriber. @@ -92,9 +89,9 @@ extension SignalProtocol { public func sink(receiveCompletion: @escaping ((Subscribers.Completion) -> Void), receiveValue: @escaping ((Element) -> Void)) -> AnyCancellable { let disposable = observe { event in switch event { - case .next(let element): + case let .next(element): receiveValue(element) - case .failed(let error): + case let .failed(error): receiveCompletion(.failure(error)) case .completed: receiveCompletion(.finished) @@ -105,7 +102,6 @@ extension SignalProtocol { } extension SignalProtocol where Error == Never { - /// Attaches a subscriber with closure-based behavior. /// /// This method creates the subscriber and immediately requests an unlimited number of values, prior to returning the subscriber. @@ -117,7 +113,6 @@ extension SignalProtocol where Error == Never { } extension SignalProtocol where Error == Never { - /// Assigns each element from a signal to a property on an object. /// /// - note: The object will be retained as long as the returned cancellable is retained. @@ -127,16 +122,15 @@ extension SignalProtocol where Error == Never { } extension SignalProtocol { - public func subscribe(_ subscriber: Downstream) where Downstream.Input == Element, Downstream.Failure == Error { let disposable = CompositeDisposable() let subscription = DisposableSubscription(disposable: disposable) subscriber.receive(subscription: subscription) disposable += observe { event in switch event { - case .next(let element): + case let .next(element): _ = subscriber.receive(element) - case .failed(let error): + case let .failed(error): subscriber.receive(completion: .failure(error)) case .completed: subscriber.receive(completion: .finished) @@ -146,15 +140,13 @@ extension SignalProtocol { } private class DisposableSubscription: Subscription { - let disposable: Disposable init(disposable: Disposable) { self.disposable = disposable } - func request(_ demand: Subscribers.Demand) { - } + func request(_: Subscribers.Demand) {} func cancel() { disposable.dispose() diff --git a/Sources/Subjects.swift b/Sources/Subjects.swift index 101b7e7..f2042c7 100644 --- a/Sources/Subjects.swift +++ b/Sources/Subjects.swift @@ -25,11 +25,9 @@ import Foundation /// A type that is both a signal and an observer. -public protocol SubjectProtocol: SignalProtocol, ObserverProtocol { -} +public protocol SubjectProtocol: SignalProtocol, ObserverProtocol {} extension SubjectProtocol { - /// Convenience method to send `.next` event. public func send(_ element: Element) { on(.next(element)) @@ -40,7 +38,7 @@ extension SubjectProtocol { switch completion { case .finished: on(.completed) - case .failure(let error): + case let .failure(error): on(.failed(error)) } } @@ -53,7 +51,6 @@ extension SubjectProtocol { } extension SubjectProtocol where Element == Void { - /// Convenience method to send `.next` event. public func send() { send(()) @@ -63,18 +60,17 @@ extension SubjectProtocol where Element == Void { /// A type that is both a signal and an observer. /// Subject is a base subject class, please use one of the subclassesin your code. open class Subject: SubjectProtocol { - internal let lock = NSRecursiveLock(name: "com.reactive_kit.subject.lock") private typealias Token = Int64 private var nextToken: Token = 0 - + private var observers: Atomic<[(Token, Observer)]> = Atomic([]) public private(set) var isTerminated: Bool = false - + public let disposeBag = DisposeBag() - + public init() {} open func on(_ event: Signal.Event) { @@ -84,7 +80,7 @@ open class Subject: SubjectProtocol { observer(event) } } - + open func observe(with observer: @escaping Observer) -> Disposable { let token = nextToken nextToken += 1 @@ -93,14 +89,13 @@ open class Subject: SubjectProtocol { } return BlockDisposable { [weak self] in self?.observers.mutate { - $0.removeAll(where: { (t, _) in t == token }) + $0.removeAll(where: { t, _ in t == token }) } } } } extension Subject: BindableProtocol { - public func bind(signal: Signal) -> Disposable { return signal .prefix(untilOutputFrom: disposeBag.deallocated) @@ -114,7 +109,6 @@ extension Subject: BindableProtocol { /// A subject that propagates received events to the registered observes. public final class PassthroughSubject: Subject { - public override init() { super.init() } @@ -132,11 +126,10 @@ public final class PassthroughSubject: Subject: Subject { - private var _buffer: ArraySlice.Event> = [] public let bufferSize: Int - + public init(bufferSize: Int = Int.max) { if bufferSize < Int.max { self.bufferSize = bufferSize + 1 // plus terminal event @@ -144,7 +137,7 @@ public final class ReplaySubject: Subject.Event) { lock.lock(); defer { lock.unlock() } guard !isTerminated else { return } @@ -166,7 +159,6 @@ public typealias SafeReplaySubject = ReplaySubject /// A subject that replies latest event to each observer. public final class ReplayOneSubject: Subject { - private var _lastEvent: Signal.Event? private var _terminalEvent: Signal.Event? @@ -203,7 +195,6 @@ public typealias SafeReplayOneSubject = ReplayOneSubject: Subject, Error> { - private enum State { case notStarted case loading @@ -215,16 +206,16 @@ public final class ReplayLoadingValueSubject, Error>.Event? public let bufferSize: Int - + public init(bufferSize: Int = Int.max) { self.bufferSize = bufferSize } - + public override func on(_ event: Signal, Error>.Event) { lock.lock(); defer { lock.unlock() } guard !isTerminated else { return } switch event { - case .next(let loadingState): + case let .next(loadingState): switch loadingState { case .loading: if _state == .notStarted { diff --git a/Sources/Subscriber.swift b/Sources/Subscriber.swift index fe73900..e0fd708 100644 --- a/Sources/Subscriber.swift +++ b/Sources/Subscriber.swift @@ -25,7 +25,6 @@ import Foundation public protocol Subscriber { - associatedtype Input associatedtype Failure: Error @@ -37,7 +36,6 @@ public protocol Subscriber { } extension Subscriber where Self.Input == Void { - public func receive() -> Subscribers.Demand { return receive(()) } diff --git a/Sources/Subscribers/Accumulator.swift b/Sources/Subscribers/Accumulator.swift index d4ed7bc..4e8005f 100644 --- a/Sources/Subscribers/Accumulator.swift +++ b/Sources/Subscribers/Accumulator.swift @@ -25,11 +25,9 @@ import Foundation extension Subscribers { - /// A subscriber that accumulates received values into an array. This subscriber can be useful in unit testing by /// asserting the state of various properties of the subscriber. - final public class Accumulator: Subscriber, Cancellable { - + public final class Accumulator: Subscriber, Cancellable { private enum State { case initialized case subscribed(Cancellable) @@ -39,10 +37,10 @@ extension Subscribers { private var state = State.initialized /// An array of values received by the subscriber. - final public private(set) var values: [Input] = [] + public private(set) final var values: [Input] = [] /// True if the subscriber has received a finished event. - final public var isFinished: Bool { + public final var isFinished: Bool { switch state { case .terminated(.some(.finished)): return true @@ -52,7 +50,7 @@ extension Subscribers { } /// True if the subscriber has received a failure event. - final public var isFailure: Bool { + public final var isFailure: Bool { switch state { case .terminated(.some(.failure)): return true @@ -62,20 +60,18 @@ extension Subscribers { } /// Non-nil if the subscriber has received a failure event. - final public var error: Failure? { + public final var error: Failure? { switch state { - case .terminated(.some(.failure(let error))): + case let .terminated(.some(.failure(error))): return error default: return nil } } - - - public init() { - } - - final public func receive(subscription: Subscription) { + + public init() {} + + public final func receive(subscription: Subscription) { switch state { case .initialized: state = .subscribed(subscription) @@ -85,12 +81,12 @@ extension Subscribers { } } - final public func receive(_ value: Input) -> Subscribers.Demand { + public final func receive(_ value: Input) -> Subscribers.Demand { values.append(value) return .unlimited } - final public func receive(completion: Subscribers.Completion) { + public final func receive(completion: Subscribers.Completion) { switch state { case .terminated: break @@ -99,9 +95,9 @@ extension Subscribers { } } - final public func cancel() { + public final func cancel() { switch state { - case .subscribed(let subscription): + case let .subscribed(subscription): subscription.cancel() state = .terminated(nil) default: diff --git a/Sources/Subscribers/Completion.swift b/Sources/Subscribers/Completion.swift index 51a2cf0..ef79877 100644 --- a/Sources/Subscribers/Completion.swift +++ b/Sources/Subscribers/Completion.swift @@ -25,7 +25,6 @@ import Foundation public enum Subscribers { - public enum Completion where Failure: Error { case finished case failure(Failure) diff --git a/Sources/Subscribers/Demand.swift b/Sources/Subscribers/Demand.swift index 04fc92c..823f646 100644 --- a/Sources/Subscribers/Demand.swift +++ b/Sources/Subscribers/Demand.swift @@ -25,15 +25,13 @@ import Foundation extension Subscribers { - public struct Demand: Equatable, Hashable { - public let value: Int private init(value: Int) { self.value = value } - + public static let unlimited: Subscribers.Demand = .init(value: Int.max) @available(*, unavailable, message: "Not supported yet.") diff --git a/Sources/Subscribers/Sink.swift b/Sources/Subscribers/Sink.swift index 6a0b677..199311a 100644 --- a/Sources/Subscribers/Sink.swift +++ b/Sources/Subscribers/Sink.swift @@ -25,26 +25,24 @@ import Foundation extension Subscribers { - - final public class Sink: Subscriber, Cancellable where Failure: Error { - + public final class Sink: Subscriber, Cancellable where Failure: Error { private enum State { case initialized case subscribed(Cancellable) case terminated } - + private var state = State.initialized - - final public let receiveValue: (Input) -> Void - final public let receiveCompletion: (Subscribers.Completion) -> Void + + public final let receiveValue: (Input) -> Void + public final let receiveCompletion: (Subscribers.Completion) -> Void public init(receiveCompletion: @escaping ((Subscribers.Completion) -> Void), receiveValue: @escaping ((Input) -> Void)) { self.receiveValue = receiveValue self.receiveCompletion = receiveCompletion } - final public func receive(subscription: Subscription) { + public final func receive(subscription: Subscription) { switch state { case .initialized: state = .subscribed(subscription) @@ -54,19 +52,19 @@ extension Subscribers { } } - final public func receive(_ value: Input) -> Subscribers.Demand { + public final func receive(_ value: Input) -> Subscribers.Demand { receiveValue(value) return .unlimited } - final public func receive(completion: Subscribers.Completion) { + public final func receive(completion: Subscribers.Completion) { receiveCompletion(completion) state = .terminated } - final public func cancel() { + public final func cancel() { switch state { - case .subscribed(let subscription): + case let .subscribed(subscription): subscription.cancel() state = .terminated default: diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift index 8a21396..5046f44 100644 --- a/Tests/LinuxMain.swift +++ b/Tests/LinuxMain.swift @@ -1,7 +1,7 @@ -import XCTest @testable import ReactiveKitTests +import XCTest XCTMain([ testCase(SignalTests.allTests), - testCase(PropertyTests.allTests), + testCase(PropertyTests.allTests) ]) diff --git a/Tests/ReactiveKitTests/PropertyTests.swift b/Tests/ReactiveKitTests/PropertyTests.swift index 1df82d8..08f0a41 100644 --- a/Tests/ReactiveKitTests/PropertyTests.swift +++ b/Tests/ReactiveKitTests/PropertyTests.swift @@ -6,23 +6,22 @@ // Copyright © 2016 Srdan Rasic. All rights reserved. // -import XCTest import ReactiveKit +import XCTest class PropertyTests: XCTestCase { - var property: Property! - + override func setUp() { property = Property(0) } - + func testValue() { XCTAssert(property.value == 0) property.value = 1 XCTAssert(property.value == 1) } - + func testEvents() { let subscriber = Subscribers.Accumulator() property.subscribe(subscriber) @@ -64,7 +63,7 @@ class PropertyTests: XCTestCase { XCTAssertEqual(subscriber.values, [0, 5, 10, 20, 30, 40]) XCTAssertTrue(subscriber.isFinished) } - + func testBidirectionalBind() { let target = Property(100) let s1 = Subscribers.Accumulator() @@ -72,39 +71,39 @@ class PropertyTests: XCTestCase { target.ignoreTerminal().subscribe(s1) property.ignoreTerminal().subscribe(s2) - + property.bidirectionalBind(to: target) property.value = 50 target.value = 60 - + XCTAssertEqual(s1.values, [100, 0, 50, 60]) XCTAssertEqual(s2.values, [0, 0, 50, 60]) } - + func testPropertyForThreadSafety_oneEventDispatchedOnALotOfProperties() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 10000 - - for _ in 0.. () -> Void)] { + static var allTests: [(String, (PropertyTests) -> () -> Void)] { return [ ("testValue", testValue), ("testEvents", testEvents), diff --git a/Tests/ReactiveKitTests/Scheduler.swift b/Tests/ReactiveKitTests/Scheduler.swift index 8b66b8b..c7adc81 100644 --- a/Tests/ReactiveKitTests/Scheduler.swift +++ b/Tests/ReactiveKitTests/Scheduler.swift @@ -11,7 +11,6 @@ import ReactiveKit /// A scheduler that buffers actions and enables their manual execution through `run` methods. class Scheduler: ReactiveKit.Scheduler { - private var availableRuns = 0 private var scheduledBlocks: [() -> Void] = [] private(set) var numberOfRuns = 0 @@ -33,7 +32,7 @@ class Scheduler: ReactiveKit.Scheduler { } private func tryRun() { - while availableRuns > 0 && scheduledBlocks.count > 0 { + while availableRuns > 0, scheduledBlocks.count > 0 { let block = scheduledBlocks.removeFirst() block() numberOfRuns += 1 diff --git a/Tests/ReactiveKitTests/SignalTests.swift b/Tests/ReactiveKitTests/SignalTests.swift index fd6af02..fd0469c 100644 --- a/Tests/ReactiveKitTests/SignalTests.swift +++ b/Tests/ReactiveKitTests/SignalTests.swift @@ -6,16 +6,15 @@ // Copyright © 2016 Srdan Rasic. All rights reserved. // -import XCTest -import ReactiveKit import Dispatch +import ReactiveKit +import XCTest enum TestError: Swift.Error { case error } class SignalTests: XCTestCase { - func testProductionAndObservation() { let bob = Scheduler() bob.runRemaining() @@ -27,7 +26,7 @@ class SignalTests: XCTestCase { publisher.subscribe(a) publisher.subscribe(b) - + XCTAssertEqual(a.values, [1, 2, 3]) XCTAssertTrue(a.isFinished) @@ -44,7 +43,7 @@ class SignalTests: XCTestCase { } let operation = Signal { _ in - return disposable + disposable } operation.observe { _ in }.dispose() @@ -110,7 +109,7 @@ class SignalTests: XCTestCase { p1.subscribe(s1) XCTAssertEqual(s1.values, [[1], [2], [3]]) XCTAssertTrue(s1.isFinished) - + let s2 = Subscribers.Accumulator<[Int], Never>() let p2 = SafeSignal(sequence: [1, 2, 3, 4]).buffer(size: 2) p2.subscribe(s2) @@ -123,7 +122,7 @@ class SignalTests: XCTestCase { XCTAssertEqual(s3.values, [[1, 2], [3, 4]]) XCTAssertTrue(s3.isFinished) } - + func testMap() { let subscriber = Subscribers.Accumulator() let publisher = Signal(sequence: [1, 2, 3]).map { $0 * 2 } @@ -139,7 +138,7 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, [0, 1, 3, 6]) XCTAssertTrue(subscriber.isFinished) } - + func testScanForThreadSafety() { let subject = PassthroughSubject() let scanned = subject.scan(0, +) @@ -297,13 +296,13 @@ class SignalTests: XCTestCase { .receive(on: bob) .prefix(untilOutputFrom: Signal(sequence: ["A", "B"]).receive(on: eve)) .subscribe(subscriber) - - bob.runOne() // Sends 1. - bob.runOne() // Sends 2. - eve.runOne() // Sends A, effectively stopping the receiver. - bob.runOne() // Ignored. - eve.runRemaining() // Ignored. Sends B, with termination. - bob.runRemaining() // Ignored. + + bob.runOne() // Sends 1. + bob.runOne() // Sends 2. + eve.runOne() // Sends A, effectively stopping the receiver. + bob.runOne() // Ignored. + eve.runRemaining() // Ignored. Sends B, with termination. + bob.runRemaining() // Ignored. XCTAssertEqual(subscriber.values, [1, 2]) XCTAssertTrue(subscriber.isFinished) @@ -311,7 +310,7 @@ class SignalTests: XCTestCase { func testIgnoreNils() { let subscriber = Subscribers.Accumulator() - let publisher = Signal(sequence: Array([1, nil, 3])).ignoreNils() + let publisher = Signal(sequence: [Int?]([1, nil, 3])).ignoreNils() publisher.subscribe(subscriber) XCTAssertEqual(subscriber.values, [1, 3]) XCTAssertTrue(subscriber.isFinished) @@ -319,7 +318,7 @@ class SignalTests: XCTestCase { func testReplaceNils() { let subscriber = Subscribers.Accumulator() - let publisher = Signal(sequence: Array([1, nil, 3, nil])).replaceNils(with: 7) + let publisher = Signal(sequence: [Int?]([1, nil, 3, nil])).replaceNils(with: 7) publisher.subscribe(subscriber) XCTAssertEqual(subscriber.values, [1, 7, 3, 7]) XCTAssertTrue(subscriber.isFinished) @@ -345,23 +344,23 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, ["1A", "1B", "2B", "3B", "3C"]) XCTAssertTrue(subscriber.isFinished) } - + func testCombineLatestWithForThreadSafety() { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let combined = subjectOne.combineLatest(with: subjectTwo) - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") combined.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } func testMergeWith() { let bob = Scheduler() let eve = Scheduler() - + let subscriber = Subscribers.Accumulator() let a = Signal(sequence: [1, 2, 3]).receive(on: bob) let b = Signal(sequence: [4, 5, 6]).receive(on: eve) @@ -379,7 +378,7 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, [1, 4, 5, 2, 6, 3]) XCTAssertTrue(subscriber.isFinished) } - + func testStartWith() { let subscriber = Subscribers.Accumulator() let publisher = Signal(sequence: [1, 2, 3]).prepend(4) @@ -397,16 +396,16 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, ["1A", "2B"]) XCTAssertTrue(subscriber.isFinished) } - + func testZipWithForThreadSafety() { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let combined = subjectOne.zip(with: subjectTwo) - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") combined.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } @@ -431,8 +430,8 @@ class SignalTests: XCTestCase { } func testZipWithAsyncSignal() { - let a = Signal(sequence: 0..<4, interval: 0.5) - let b = Signal(sequence: 0..<10, interval: 1.0) + let a = Signal(sequence: 0 ..< 4, interval: 0.5) + let b = Signal(sequence: 0 ..< 10, interval: 1.0) let combined = a.zip(with: b).map { $0 + $1 } // Completes after 4 nexts due to 'a' and takes 4 secs due to 'b' let events = combined.waitAndCollectEvents() XCTAssertEqual(events, [.next(0), .next(2), .next(4), .next(6), .completed]) @@ -440,7 +439,7 @@ class SignalTests: XCTestCase { func testFlatMapError() { let subscriber = Subscribers.Accumulator() - let publisher = Signal.failed(.error).flatMapError { error in Signal(just: 1) } + let publisher = Signal.failed(.error).flatMapError { _ in Signal(just: 1) } publisher.subscribe(subscriber) XCTAssertEqual(subscriber.values, [1]) XCTAssertFalse(subscriber.isFailure) @@ -449,7 +448,7 @@ class SignalTests: XCTestCase { func testFlatMapError2() { let subscriber = Subscribers.Accumulator() - let publisher = Signal.failed(.error).flatMapError { error in Signal(just: 1) } + let publisher = Signal.failed(.error).flatMapError { _ in Signal(just: 1) } publisher.subscribe(subscriber) XCTAssertEqual(subscriber.values, [1]) XCTAssertFalse(subscriber.isFailure) @@ -469,25 +468,24 @@ class SignalTests: XCTestCase { XCTAssertTrue(subscriber.isFailure) XCTAssertEqual(bob.numberOfRuns, 4) } - + func testRetryForThreadSafety() { let subjectOne = PassthroughSubject() let retry = subjectOne.retry(3) - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") retry.stress(with: [subjectOne], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } func testRetryWhen() { - let queue = DispatchQueue(label: "test", qos: .userInitiated) let e = expectation(description: "Failed to retry") e.expectedFulfillmentCount = 1000 - for _ in 0.. Result in count += 1 @@ -596,11 +594,11 @@ class SignalTests: XCTestCase { .waitAndCollectEvents() XCTAssertEqual(events, [.failed(.error)]) } - + func testTimeoutForThreadSafety() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 10000 - for _ in 0..() let timeout = subject.timeout(after: 1, with: .error) let disposeBag = DisposeBag() @@ -631,14 +629,14 @@ class SignalTests: XCTestCase { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let combined = subjectOne.amb(with: subjectTwo) - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") combined.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } - + func testCollect() { let events = Signal(sequence: [1, 2, 3]) .collect() @@ -664,7 +662,7 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, [1, 2, 3, 4]) XCTAssertTrue(subscriber.isFinished) } - + func testWithLatestFrom() { let bob = Scheduler() let eve = Scheduler() @@ -681,23 +679,23 @@ class SignalTests: XCTestCase { eve.runOne() bob.runRemaining() eve.runRemaining() - + XCTAssertEqual(subscriber.values[0].0, 2) XCTAssertEqual(subscriber.values[0].1, 3) XCTAssertEqual(subscriber.values[1].0, 5) XCTAssertEqual(subscriber.values[1].1, 4) XCTAssertTrue(subscriber.isFinished) } - + func testWithLatestFromForThreadSafety() { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let merged = subjectOne.with(latestFrom: subjectTwo) - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") merged.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } @@ -731,7 +729,7 @@ class SignalTests: XCTestCase { let publisher = Signal(sequence: [1, 2]) .receive(on: bob) .flatMapMerge { num in - Signal(sequence: [5, 6].map { $0 * num }).receive(on: eves[num-1]) + Signal(sequence: [5, 6].map { $0 * num }).receive(on: eves[num - 1]) } publisher.subscribe(subscriber) @@ -744,16 +742,16 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, [5, 10, 12, 6]) XCTAssertTrue(subscriber.isFinished) } - + func testFlatMapMergeForThreadSafety() { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let merged = subjectOne.flatMapMerge { _ in subjectTwo } - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") merged.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } @@ -765,7 +763,7 @@ class SignalTests: XCTestCase { let publisher = Signal(sequence: [1, 2]) .receive(on: bob) .flatMapLatest { num in - Signal(sequence: [5, 6].map { $0 * num }).receive(on: eves[num-1]) + Signal(sequence: [5, 6].map { $0 * num }).receive(on: eves[num - 1]) } publisher.subscribe(subscriber) @@ -778,16 +776,16 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, [5, 10, 12]) XCTAssertTrue(subscriber.isFinished) } - + func testFlatMapLatestForThreadSafety() { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let merged = subjectOne.flatMapLatest { _ in subjectTwo } - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") merged.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } @@ -799,7 +797,7 @@ class SignalTests: XCTestCase { let publisher = Signal(sequence: [1, 2]) .receive(on: bob) .flatMapConcat { num in - Signal(sequence: [5, 6].map { $0 * num }).receive(on: eves[num-1]) + Signal(sequence: [5, 6].map { $0 * num }).receive(on: eves[num - 1]) } publisher.subscribe(subscriber) @@ -811,16 +809,16 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, [5, 6, 10, 12]) XCTAssertTrue(subscriber.isFinished) } - + func testFlatMapConcatForThreadSafety() { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let merged = subjectOne.flatMapConcat { _ in subjectTwo } - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") merged.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } @@ -832,7 +830,7 @@ class SignalTests: XCTestCase { let replayed = publisher.replay(limit: 2) XCTAssertEqual(publisher.waitAndCollectEvents(), [.next(1), .next(2), .next(3), .completed]) - let _ = replayed.connect() + _ = replayed.connect() XCTAssertEqual(replayed.waitAndCollectEvents(), [.next(2), .next(3), .completed]) XCTAssertEqual(bob.numberOfRuns, 2) } @@ -860,16 +858,16 @@ class SignalTests: XCTestCase { XCTAssertEqual(subscriber.values, [1, 2, 2, 2, 3, 3]) XCTAssertTrue(subscriber.isFinished) } - + func testReplayLatestWithForThreadSafety() { let subjectOne = PassthroughSubject() let subjectTwo = PassthroughSubject() let combined = subjectOne.replayLatest(when: subjectTwo) - + let disposeBag = DisposeBag() let exp = expectation(description: "race_condition?") combined.stress(with: [subjectOne, subjectTwo], expectation: exp).dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } @@ -881,7 +879,7 @@ class SignalTests: XCTestCase { let published = publisher.publish() XCTAssertEqual(publisher.waitAndCollectEvents(), [.next(1), .next(2), .next(3), .completed]) - let _ = published.connect() + _ = published.connect() XCTAssertEqual( published.timeout(after: 1, with: .error).waitAndCollectEvents(), @@ -892,7 +890,7 @@ class SignalTests: XCTestCase { } func testAnyCancallableHashable() { - let emptyClosure: () -> Void = { } + let emptyClosure: () -> Void = {} let cancellable1 = AnyCancellable(emptyClosure) let cancellable2 = AnyCancellable(emptyClosure) @@ -902,35 +900,31 @@ class SignalTests: XCTestCase { XCTAssertNotEqual(cancellable1, cancellable2) XCTAssertNotEqual(cancellable1, cancellable3) XCTAssertEqual(cancellable3, cancellable4) - } - #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) - func testBindTo() { - - class User: NSObject, BindingExecutionContextProvider { + #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS) + func testBindTo() { + class User: NSObject, BindingExecutionContextProvider { + var age: Int = 0 - var age: Int = 0 - - var bindingExecutionContext: ExecutionContext { - return .immediate + var bindingExecutionContext: ExecutionContext { + return .immediate + } } - } - let user = User() + let user = User() - SafeSignal(just: 20).bind(to: user) { (object, value) in object.age = value } - XCTAssertEqual(user.age, 20) + SafeSignal(just: 20).bind(to: user) { object, value in object.age = value } + XCTAssertEqual(user.age, 20) - SafeSignal(just: 30).bind(to: user, keyPath: \.age) - XCTAssertEqual(user.age, 30) - } + SafeSignal(just: 30).bind(to: user, keyPath: \.age) + XCTAssertEqual(user.age, 30) + } #endif } extension SignalTests { - - static var allTests : [(String, (SignalTests) -> () -> Void)] { + static var allTests: [(String, (SignalTests) -> () -> Void)] { return [ ("testProductionAndObservation", testProductionAndObservation), ("testDisposing", testDisposing), diff --git a/Tests/ReactiveKitTests/Stress.swift b/Tests/ReactiveKitTests/Stress.swift index 33a34ed..b76df07 100644 --- a/Tests/ReactiveKitTests/Stress.swift +++ b/Tests/ReactiveKitTests/Stress.swift @@ -6,41 +6,39 @@ // Copyright © 2016 Srdan Rasic. All rights reserved. // -import XCTest import ReactiveKit +import XCTest extension SignalProtocol { - func stress( with sendElements: [(Int) -> Void], queuesCount: Int = 3, eventsCount: Int = 3000, - timeout: Double = 2, + timeout _: Double = 2, expectation: XCTestExpectation ) -> Disposable { - - let dispatchQueues = Array((0..( with subjects: [S], queuesCount: Int = 3, @@ -57,5 +55,3 @@ extension SignalProtocol { ) } } - - diff --git a/Tests/ReactiveKitTests/SubjectTests.swift b/Tests/ReactiveKitTests/SubjectTests.swift index 851f68b..e3f4c1b 100644 --- a/Tests/ReactiveKitTests/SubjectTests.swift +++ b/Tests/ReactiveKitTests/SubjectTests.swift @@ -6,18 +6,17 @@ // Copyright © 2019 DeclarativeHub. All rights reserved. // -import XCTest import ReactiveKit +import XCTest final class SubjectTests: XCTestCase { - // MARK: - Subject - + func testSubjectForThreadSafety_oneEventDispatchedOnALotOfSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 10000 - - for _ in 0..() subject.stress(with: [subject], eventsCount: 1, expectation: exp).dispose(in: disposeBag) @@ -28,27 +27,27 @@ final class SubjectTests: XCTestCase { waitForExpectations(timeout: 3) } - + func testSubjectForThreadSafety_lotsOfEventsDispatchedOnOneSubject() { let exp = expectation(description: "race_condition?") let disposeBag = DisposeBag() let subject = PassthroughSubject() - + subject.stress(with: [subject], queuesCount: 10, eventsCount: 3000, expectation: exp) .dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } - + func testSubjectForThreadSafety_someEventsDispatchedOnSomeSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 100 - - for _ in 0..() subject.stress(with: [subject], expectation: exp).dispose(in: disposeBag) @@ -56,17 +55,17 @@ final class SubjectTests: XCTestCase { disposeBag.dispose() } } - + waitForExpectations(timeout: 3) } - + // MARK: - ReplaySubject - + func testReplaySubjectForThreadSafety_oneEventDispatchedOnALotOfSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 10000 - - for _ in 0..() subject.stress(with: [subject], eventsCount: 1, expectation: exp).dispose(in: disposeBag) @@ -74,30 +73,30 @@ final class SubjectTests: XCTestCase { disposeBag.dispose() } } - + waitForExpectations(timeout: 3) } - + func testReplaySubjectForThreadSafety_lotsOfEventsDispatchedOnOneSubject() { let exp = expectation(description: "race_condition?") - + let disposeBag = DisposeBag() let subject = ReplaySubject() - + subject.stress(with: [subject], queuesCount: 10, eventsCount: 3000, expectation: exp) .dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } - + func testReplaySubjectForThreadSafety_someEventsDispatchedOnSomeSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 100 - - for _ in 0..() subject.stress(with: [subject], expectation: exp).dispose(in: disposeBag) @@ -105,24 +104,23 @@ final class SubjectTests: XCTestCase { disposeBag.dispose() } } - + waitForExpectations(timeout: 3) } - + func testReplaySubjectForThreadSafetySendLast() { - let eventsCount = 10000 - + let eventsExpectation = expectation(description: "events") eventsExpectation.expectedFulfillmentCount = eventsCount - + let countDispatchQueue = DispatchQueue(label: "count") var actualEventsCount = 0 - - for _ in 0..() - + let dispatchQueueOne = DispatchQueue(label: "one") dispatchQueueOne.async { subject.observeNext { _ in @@ -132,14 +130,14 @@ final class SubjectTests: XCTestCase { eventsExpectation.fulfill() }.dispose(in: bag) } - + let dispatchQueueTwo = DispatchQueue(label: "two") dispatchQueueTwo.async { subject.send(1) bag.dispose() } } - + waitForExpectations(timeout: 2) { _ in countDispatchQueue.sync { guard actualEventsCount != eventsCount else { return } @@ -147,27 +145,26 @@ final class SubjectTests: XCTestCase { } } } - + func testReplaySubjectForThreadSafetySendFirst() { - let eventsCount = 10000 - + let eventsExpectation = expectation(description: "events") eventsExpectation.expectedFulfillmentCount = eventsCount - + let countDispatchQueue = DispatchQueue(label: "count") var actualEventsCount = 0 - - for _ in 0..() - + let dispatchQueueTwo = DispatchQueue(label: "two") dispatchQueueTwo.async { subject.send(1) bag.dispose() } - + let dispatchQueueOne = DispatchQueue(label: "one") dispatchQueueOne.async { subject.observeNext { _ in @@ -178,7 +175,7 @@ final class SubjectTests: XCTestCase { }.dispose(in: bag) } } - + waitForExpectations(timeout: 2) { _ in countDispatchQueue.sync { guard actualEventsCount != eventsCount else { return } @@ -186,14 +183,14 @@ final class SubjectTests: XCTestCase { } } } - + // MARK: - ReplayOneSubject - + func testReplayOneSubjectForThreadSafety_oneEventDispatchedOnALotOfSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 10000 - - for _ in 0..() subject.stress(with: [subject], eventsCount: 1, expectation: exp).dispose(in: disposeBag) @@ -201,30 +198,30 @@ final class SubjectTests: XCTestCase { disposeBag.dispose() } } - + waitForExpectations(timeout: 3) } - + func testReplayOneSubjectForThreadSafety_lotsOfEventsDispatchedOnOneSubject() { let exp = expectation(description: "race_condition?") - + let disposeBag = DisposeBag() let subject = ReplayOneSubject() - + subject.stress(with: [subject], queuesCount: 10, eventsCount: 3000, expectation: exp) .dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } - + func testReplayOneSubjectForThreadSafety_someEventsDispatchedOnSomeSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 100 - - for _ in 0..() subject.stress(with: [subject], expectation: exp).dispose(in: disposeBag) @@ -232,12 +229,11 @@ final class SubjectTests: XCTestCase { disposeBag.dispose() } } - + waitForExpectations(timeout: 3) } - + func testReplayOneSubjectForThreadSafetySendLast() { - let eventsCount = 10000 let eventsExpectation = expectation(description: "events") @@ -245,8 +241,8 @@ final class SubjectTests: XCTestCase { let countDispatchQueue = DispatchQueue(label: "count") var actualEventsCount = 0 - - for _ in 0..() @@ -259,14 +255,14 @@ final class SubjectTests: XCTestCase { eventsExpectation.fulfill() }.dispose(in: bag) } - + let dispatchQueueTwo = DispatchQueue(label: "two") dispatchQueueTwo.async { subject.send(1) bag.dispose() } } - + waitForExpectations(timeout: 2) { _ in countDispatchQueue.sync { guard actualEventsCount != eventsCount else { return } @@ -276,25 +272,24 @@ final class SubjectTests: XCTestCase { } func testReplayOneSubjectForThreadSafetySendFirst() { - let eventsCount = 10000 - + let eventsExpectation = expectation(description: "events") eventsExpectation.expectedFulfillmentCount = eventsCount - + let countDispatchQueue = DispatchQueue(label: "count") var actualEventsCount = 0 - - for _ in 0..() - + let dispatchQueueTwo = DispatchQueue(label: "two") dispatchQueueTwo.async { subject.send(1) bag.dispose() } - + let dispatchQueueOne = DispatchQueue(label: "one") dispatchQueueOne.async { subject.observeNext { _ in @@ -305,7 +300,7 @@ final class SubjectTests: XCTestCase { }.dispose(in: bag) } } - + waitForExpectations(timeout: 2) { _ in countDispatchQueue.sync { guard actualEventsCount != eventsCount else { return } @@ -313,14 +308,14 @@ final class SubjectTests: XCTestCase { } } } - + // MARK: - ReplayLoadingValueSubject - + func testReplayLoadingValueSubjectForThreadSafety_oneEventDispatchedOnALotOfSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 10000 - - for _ in 0..() @@ -333,30 +328,30 @@ final class SubjectTests: XCTestCase { disposeBag.dispose() } } - + waitForExpectations(timeout: 3) } - + func testReplayLoadingValueSubjectForThreadSafety_lotsOfEventsDispatchedOnOneSubject() { let exp = expectation(description: "race_condition?") - + let disposeBag = DisposeBag() let subject = ReplayLoadingValueSubject() - + subject.stress(with: [{ subject.send(.loaded($0)) }], queuesCount: 10, eventsCount: 3000, expectation: exp) .dispose(in: disposeBag) - + waitForExpectations(timeout: 3) } - + func testReplayLoadingValueSubjectForThreadSafety_someEventsDispatchedOnSomeSubjects() { let exp = expectation(description: "race_condition?") exp.expectedFulfillmentCount = 100 - - for _ in 0..() @@ -368,24 +363,23 @@ final class SubjectTests: XCTestCase { disposeBag.dispose() } } - + waitForExpectations(timeout: 3) } - + func testReplayLoadingValueSubjectForThreadSafetySendLast() { - let eventsCount = 10000 - + let eventsExpectation = expectation(description: "events") eventsExpectation.expectedFulfillmentCount = eventsCount - + let countDispatchQueue = DispatchQueue(label: "count") var actualEventsCount = 0 - - for _ in 0..() - + let dispatchQueueOne = DispatchQueue(label: "one") dispatchQueueOne.async { subject.observeNext { _ in @@ -395,14 +389,14 @@ final class SubjectTests: XCTestCase { eventsExpectation.fulfill() }.dispose(in: bag) } - + let dispatchQueueTwo = DispatchQueue(label: "two") dispatchQueueTwo.async { subject.send(.loaded(1)) bag.dispose() } } - + waitForExpectations(timeout: 2) { _ in countDispatchQueue.sync { guard actualEventsCount != eventsCount else { return } @@ -410,27 +404,26 @@ final class SubjectTests: XCTestCase { } } } - + func testReplayLoadingValueSubjectForThreadSafetySendFirst() { - let eventsCount = 10000 - + let eventsExpectation = expectation(description: "events") eventsExpectation.expectedFulfillmentCount = eventsCount - + let countDispatchQueue = DispatchQueue(label: "count") var actualEventsCount = 0 - - for _ in 0..() - + let dispatchQueueTwo = DispatchQueue(label: "two") dispatchQueueTwo.async { subject.send(.loaded(1)) bag.dispose() } - + let dispatchQueueOne = DispatchQueue(label: "one") dispatchQueueOne.async { subject.observeNext { _ in @@ -441,7 +434,7 @@ final class SubjectTests: XCTestCase { }.dispose(in: bag) } } - + waitForExpectations(timeout: 2) { _ in countDispatchQueue.sync { guard actualEventsCount != eventsCount else { return }