Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended Sample operation to support a default value #1457

Merged
merged 10 commits into from
Jan 9, 2020
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ All notable changes to this project will be documented in this file.
* Add `UITextField.isSecureTextEntry` binder. #1968
* Remove "custom" `Result` in favor of `Foundation.Resault`. #2006
* Fix compilation error in `SharedSequence.createUnsafe`. #2014
* Added `defaultValue` to `sample` to be returned when no new events occur between sampler ticks. #1457

## [5.0.1](https://github.com/ReactiveX/RxSwift/releases/tag/5.0.1)

Expand Down
18 changes: 12 additions & 6 deletions RxSwift/Observables/Sample.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ extension ObservableType {

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.**
**In case there were no new elements between sampler ticks, if a default value has been set then it is sent
aspitz marked this conversation as resolved.
Show resolved Hide resolved
to the resulting sequence otherwise no element is sent.**

- seealso: [sample operator on reactivex.io](http://reactivex.io/documentation/operators/sample.html)

- parameter sampler: Sampling tick sequence.
defaultValue: a value to return if there are new new elements between sampler ticks
aspitz marked this conversation as resolved.
Show resolved Hide resolved
- returns: Sampled observable sequence.
*/
public func sample<Source: ObservableType>(_ sampler: Source)
public func sample<Source: ObservableType>(_ sampler: Source, defaultValue: Element? = nil)
-> Observable<Element> {
return Sample(source: self.asObservable(), sampler: sampler.asObservable())
return Sample(source: self.asObservable(), sampler: sampler.asObservable(), defaultValue: defaultValue)
}
}

Expand Down Expand Up @@ -54,6 +56,8 @@ final private class SamplerSink<Observer: ObserverType, SampleType>
if let element = parent.element {
aspitz marked this conversation as resolved.
Show resolved Hide resolved
self.parent.element = nil
self.parent.forwardOn(.next(element))
} else if let element = self.parent.parent.defaultValue {
aspitz marked this conversation as resolved.
Show resolved Hide resolved
self.parent.forwardOn(.next(element))
}

if self.parent.atEnd {
Expand All @@ -75,7 +79,7 @@ final private class SampleSequenceSink<Observer: ObserverType, SampleType>
typealias Element = Observer.Element
typealias Parent = Sample<Element, SampleType>

private let parent: Parent
fileprivate let parent: Parent

let lock = RecursiveLock()

Expand Down Expand Up @@ -119,10 +123,12 @@ final private class SampleSequenceSink<Observer: ObserverType, SampleType>
final private class Sample<Element, SampleType>: Producer<Element> {
fileprivate let source: Observable<Element>
fileprivate let sampler: Observable<SampleType>

init(source: Observable<Element>, sampler: Observable<SampleType>) {
fileprivate let defaultValue: Element?
aspitz marked this conversation as resolved.
Show resolved Hide resolved

init(source: Observable<Element>, sampler: Observable<SampleType>, defaultValue: Element? = nil) {
self.source = source
self.sampler = sampler
self.defaultValue = defaultValue
}

override func run<Observer: ObserverType>(_ observer: Observer, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where Observer.Element == Element {
Expand Down
1 change: 1 addition & 0 deletions Sources/AllTestz/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,7 @@ final class ObservableSampleTest_ : ObservableSampleTest, RxTestCase {
#endif

static var allTests: [(String, (ObservableSampleTest_) -> () -> Void)] { return [
("testSample_Sampler_DefaultValue", ObservableSampleTest.testSample_Sampler_DefaultValue),
("testSample_Sampler_SamplerThrows", ObservableSampleTest.testSample_Sampler_SamplerThrows),
("testSample_Sampler_Simple1", ObservableSampleTest.testSample_Sampler_Simple1),
("testSample_Sampler_Simple2", ObservableSampleTest.testSample_Sampler_Simple2),
Expand Down
46 changes: 46 additions & 0 deletions Tests/RxSwiftTests/Observable+SampleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,52 @@ class ObservableSampleTest : RxTest {
}

extension ObservableSampleTest {
func testSample_Sampler_DefaultValue() {
let scheduler = TestScheduler(initialClock: 0)

let xs = scheduler.createHotObservable([
.next(150, 1),
.next(220, 2),
.next(240, 3),
.next(290, 4),
.next(300, 5),
.next(310, 6),
.completed(400)
])

let ys = scheduler.createHotObservable([
.next(150, ""),
.next(210, "bar"),
.next(250, "foo"),
.next(260, "qux"),
.next(320, "baz"),
.completed(500)
])

let res = scheduler.start {
xs.sample(ys, defaultValue: 0)
}

let correct = Recorded.events(
.next(210, 0),
.next(250, 3),
.next(260, 0),
.next(320, 6),
.next(500, 0),
.completed(500)
)

XCTAssertEqual(res.events, correct)

XCTAssertEqual(xs.subscriptions, [
Subscription(200, 400)
])

XCTAssertEqual(ys.subscriptions, [
Subscription(200, 500)
])
}

func testSample_Sampler_SamplerThrows() {
let scheduler = TestScheduler(initialClock: 0)

Expand Down