// // Sample.swift // RxSwift // // Created by Krunoslav Zaher on 5/1/15. // Copyright © 2015 Krunoslav Zaher. All rights reserved. // extension ObservableType { /** Samples the source observable sequence using a sampler observable sequence producing sampling ticks. Upon each sampling tick, the latest element (if any) in the source sequence during the last sampling interval is sent to the resulting sequence. **In case there were no new elements between sampler ticks, no element is sent to the resulting sequence.** - seealso: [sample operator on reactivex.io](http://reactivex.io/documentation/operators/sample.html) - parameter sampler: Sampling tick sequence. - returns: Sampled observable sequence. */ public func sample(_ sampler: O) -> Observable { return Sample(source: self.asObservable(), sampler: sampler.asObservable()) } } final fileprivate class SamplerSink : ObserverType , LockOwnerType , SynchronizedOnType { typealias E = SampleType typealias Parent = SampleSequenceSink fileprivate let _parent: Parent var _lock: RecursiveLock { return _parent._lock } init(parent: Parent) { _parent = parent } func on(_ event: Event) { synchronizedOn(event) } func _synchronized_on(_ event: Event) { switch event { case .next: if let element = _parent._element { _parent._element = nil _parent.forwardOn(.next(element)) } if _parent._atEnd { _parent.forwardOn(.completed) _parent.dispose() } case .error(let e): _parent.forwardOn(.error(e)) _parent.dispose() case .completed: if let element = _parent._element { _parent._element = nil _parent.forwardOn(.next(element)) } if _parent._atEnd { _parent.forwardOn(.completed) _parent.dispose() } } } } final fileprivate class SampleSequenceSink : Sink , ObserverType , LockOwnerType , SynchronizedOnType { typealias Element = O.E typealias Parent = Sample fileprivate let _parent: Parent let _lock = RecursiveLock() // state fileprivate var _element = nil as Element? fileprivate var _atEnd = false fileprivate let _sourceSubscription = SingleAssignmentDisposable() init(parent: Parent, observer: O, cancel: Cancelable) { _parent = parent super.init(observer: observer, cancel: cancel) } func run() -> Disposable { _sourceSubscription.setDisposable(_parent._source.subscribe(self)) let samplerSubscription = _parent._sampler.subscribe(SamplerSink(parent: self)) return Disposables.create(_sourceSubscription, samplerSubscription) } func on(_ event: Event) { synchronizedOn(event) } func _synchronized_on(_ event: Event) { switch event { case .next(let element): _element = element case .error: forwardOn(event) dispose() case .completed: _atEnd = true _sourceSubscription.dispose() } } } final fileprivate class Sample : Producer { fileprivate let _source: Observable fileprivate let _sampler: Observable init(source: Observable, sampler: Observable) { _source = source _sampler = sampler } override func run(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element { let sink = SampleSequenceSink(parent: self, observer: observer, cancel: cancel) let subscription = sink.run() return (sink: sink, subscription: subscription) } }