From 880c777a8026670935846dcff58bb300ae64c32e Mon Sep 17 00:00:00 2001 From: Krunoslav Zaher Date: Sun, 13 Sep 2015 15:35:48 +0200 Subject: [PATCH] Adds `repeatElement` operator. --- CHANGELOG.md | 1 + Rx.xcodeproj/project.pbxproj | 6 +++ RxExample/RxExample.xcodeproj/project.pbxproj | 4 ++ .../Observables/Implementations/Repeat.swift | 43 +++++++++++++++++++ RxSwift/Observables/Observable+Creation.swift | 14 +++++- .../Tests/Observable+CreationTest.swift | 21 +++++++++ 6 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 RxSwift/Observables/Implementations/Repeat.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index e996643f..d686d7e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file. * Removes `SpinLock`s in disposables in favor of more performant `OSAtomicCompareAndSwap32`. * Adds `buffer` operator (version with time and count). * Adds `range` operator. +* Adds `repeat` operator. ## [2.0.0-alpha.2](https://github.com/ReactiveX/RxSwift/releases/tag/2.0.0-alpha.2) diff --git a/Rx.xcodeproj/project.pbxproj b/Rx.xcodeproj/project.pbxproj index a680fccc..9aa564fc 100644 --- a/Rx.xcodeproj/project.pbxproj +++ b/Rx.xcodeproj/project.pbxproj @@ -264,6 +264,8 @@ C84B38EF1BA433CD001B7D88 /* Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84B38ED1BA433CD001B7D88 /* Generate.swift */; }; C86409FC1BA593F500D3C4E8 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86409FB1BA593F500D3C4E8 /* Range.swift */; }; C86409FD1BA593F500D3C4E8 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86409FB1BA593F500D3C4E8 /* Range.swift */; }; + C8640A031BA5B12A00D3C4E8 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8640A021BA5B12A00D3C4E8 /* Repeat.swift */; }; + C8640A041BA5B12A00D3C4E8 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8640A021BA5B12A00D3C4E8 /* Repeat.swift */; }; C88254161B8A752B00B02D69 /* RxCollectionViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88253F11B8A752B00B02D69 /* RxCollectionViewReactiveArrayDataSource.swift */; }; C88254171B8A752B00B02D69 /* RxTableViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88253F21B8A752B00B02D69 /* RxTableViewReactiveArrayDataSource.swift */; }; C88254181B8A752B00B02D69 /* ItemEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C88253F41B8A752B00B02D69 /* ItemEvents.swift */; }; @@ -459,6 +461,7 @@ C84B38E71BA43380001B7D88 /* ScheduledItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScheduledItem.swift; sourceTree = ""; }; C84B38ED1BA433CD001B7D88 /* Generate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Generate.swift; sourceTree = ""; }; C86409FB1BA593F500D3C4E8 /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = ""; }; + C8640A021BA5B12A00D3C4E8 /* Repeat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Repeat.swift; sourceTree = ""; }; C88253F11B8A752B00B02D69 /* RxCollectionViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxCollectionViewReactiveArrayDataSource.swift; sourceTree = ""; }; C88253F21B8A752B00B02D69 /* RxTableViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RxTableViewReactiveArrayDataSource.swift; sourceTree = ""; }; C88253F41B8A752B00B02D69 /* ItemEvents.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemEvents.swift; sourceTree = ""; }; @@ -673,6 +676,7 @@ C86409FB1BA593F500D3C4E8 /* Range.swift */, C8093C841B8A72BE0088E94D /* Reduce.swift */, C8093C851B8A72BE0088E94D /* RefCount.swift */, + C8640A021BA5B12A00D3C4E8 /* Repeat.swift */, C8093C861B8A72BE0088E94D /* Sample.swift */, C8093C871B8A72BE0088E94D /* Scan.swift */, C8093C881B8A72BE0088E94D /* Sink.swift */, @@ -1376,6 +1380,7 @@ C8093D441B8A72BE0088E94D /* Take.swift in Sources */, C8093D321B8A72BE0088E94D /* Reduce.swift in Sources */, C84B38EA1BA43380001B7D88 /* ScheduledItem.swift in Sources */, + C8640A041BA5B12A00D3C4E8 /* Repeat.swift in Sources */, C8093CF41B8A72BE0088E94D /* Error.swift in Sources */, C8093D141B8A72BE0088E94D /* Debug.swift in Sources */, C8093CCE1B8A72BE0088E94D /* Bag.swift in Sources */, @@ -1487,6 +1492,7 @@ C8093D431B8A72BE0088E94D /* Take.swift in Sources */, C8093D311B8A72BE0088E94D /* Reduce.swift in Sources */, C84B38E91BA43380001B7D88 /* ScheduledItem.swift in Sources */, + C8640A031BA5B12A00D3C4E8 /* Repeat.swift in Sources */, C8093CF31B8A72BE0088E94D /* Error.swift in Sources */, C8093D131B8A72BE0088E94D /* Debug.swift in Sources */, C8093CCD1B8A72BE0088E94D /* Bag.swift in Sources */, diff --git a/RxExample/RxExample.xcodeproj/project.pbxproj b/RxExample/RxExample.xcodeproj/project.pbxproj index 0cbe8afd..b24cae01 100644 --- a/RxExample/RxExample.xcodeproj/project.pbxproj +++ b/RxExample/RxExample.xcodeproj/project.pbxproj @@ -241,6 +241,7 @@ C86409F91BA5909000D3C4E8 /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C864098E1BA5909000D3C4E8 /* SubjectType.swift */; }; C86409FA1BA5909000D3C4E8 /* Variable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C864098F1BA5909000D3C4E8 /* Variable.swift */; }; C86409FF1BA5A87200D3C4E8 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86409FE1BA5A87200D3C4E8 /* Range.swift */; }; + C8640A011BA5AB5A00D3C4E8 /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8640A001BA5AB5A00D3C4E8 /* Repeat.swift */; }; C86E2F3E1AE5A0CA00C31024 /* SearchResultViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86E2F321AE5A0CA00C31024 /* SearchResultViewModel.swift */; }; C86E2F3F1AE5A0CA00C31024 /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86E2F331AE5A0CA00C31024 /* SearchViewModel.swift */; }; C86E2F451AE5A0CA00C31024 /* WikipediaAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = C86E2F3B1AE5A0CA00C31024 /* WikipediaAPI.swift */; }; @@ -522,6 +523,7 @@ C864098E1BA5909000D3C4E8 /* SubjectType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubjectType.swift; sourceTree = ""; }; C864098F1BA5909000D3C4E8 /* Variable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Variable.swift; sourceTree = ""; }; C86409FE1BA5A87200D3C4E8 /* Range.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Range.swift; sourceTree = ""; }; + C8640A001BA5AB5A00D3C4E8 /* Repeat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Repeat.swift; sourceTree = ""; }; C86E2F321AE5A0CA00C31024 /* SearchResultViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SearchResultViewModel.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; C86E2F331AE5A0CA00C31024 /* SearchViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = SearchViewModel.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; C86E2F3B1AE5A0CA00C31024 /* WikipediaAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WikipediaAPI.swift; sourceTree = ""; }; @@ -1002,6 +1004,7 @@ C86409FE1BA5A87200D3C4E8 /* Range.swift */, C864095A1BA5909000D3C4E8 /* Reduce.swift */, C864095B1BA5909000D3C4E8 /* RefCount.swift */, + C8640A001BA5AB5A00D3C4E8 /* Repeat.swift */, C864095C1BA5909000D3C4E8 /* Sample.swift */, C864095D1BA5909000D3C4E8 /* Scan.swift */, C864095E1BA5909000D3C4E8 /* Sink.swift */, @@ -1516,6 +1519,7 @@ C8297E561B6CF905000589EA /* WikipediaPage.swift in Sources */, C86409921BA5909000D3C4E8 /* Lock.swift in Sources */, C86409901BA5909000D3C4E8 /* Cancelable.swift in Sources */, + C8640A011BA5AB5A00D3C4E8 /* Repeat.swift in Sources */, C84B3A2F1BA4345A001B7D88 /* _RXKVOObserver.m in Sources */, C8297E571B6CF905000589EA /* Randomizer.swift in Sources */, C86409981BA5909000D3C4E8 /* AnonymousDisposable.swift in Sources */, diff --git a/RxSwift/Observables/Implementations/Repeat.swift b/RxSwift/Observables/Implementations/Repeat.swift new file mode 100644 index 00000000..e7030497 --- /dev/null +++ b/RxSwift/Observables/Implementations/Repeat.swift @@ -0,0 +1,43 @@ +// +// Repeat.swift +// RxExample +// +// Created by Krunoslav Zaher on 9/13/15. +// Copyright © 2015 Krunoslav Zaher. All rights reserved. +// + +import Foundation + +class RepeatElement : Producer { + let element: Element + let scheduler: ImmediateSchedulerType + + init(element: Element, scheduler: ImmediateSchedulerType) { + self.element = element + self.scheduler = scheduler + } + + override func run(observer: O, cancel: Disposable, setSink: (Disposable) -> Void) -> Disposable { + let sink = RepeatElementSink(parent: self, observer: observer, cancel: cancel) + setSink(sink) + return sink.run() + } +} + +class RepeatElementSink : Sink { + typealias Parent = RepeatElement + + let parent: Parent + + init(parent: Parent, observer: O, cancel: Disposable) { + self.parent = parent + super.init(observer: observer, cancel: cancel) + } + + func run() -> Disposable { + return self.parent.scheduler.scheduleRecursive(self.parent.element) { e, recurse in + self.observer?.on(.Next(e)) + recurse(e) + } + } +} \ No newline at end of file diff --git a/RxSwift/Observables/Observable+Creation.swift b/RxSwift/Observables/Observable+Creation.swift index 61d20cd4..9fcb906b 100644 --- a/RxSwift/Observables/Observable+Creation.swift +++ b/RxSwift/Observables/Observable+Creation.swift @@ -115,7 +115,6 @@ public func deferred(observableFactory: () throws -> Observable) return Deferred(observableFactory: observableFactory) } - /** Generates an observable sequence by running a state-driven loop producing the sequence's elements, using the specified scheduler to run the loop send out observer messages. @@ -148,4 +147,15 @@ public func range(start: Int, _ count: Int, _ scheduler: ImmediateSchedulerType } return RangeProducer(start: start, count: count, scheduler: scheduler) -} \ No newline at end of file +} + +/** +Generates an observable sequence that repeats the given element infinitely, using the specified scheduler to send out observer messages. + +- parameter element: Element to repeat. +- parameter scheduler: Scheduler to run the producer loop on. +- returns: An observable sequence that repeats the given element infinitely. +*/ +public func repeatElement(element: E, _ scheduler: ImmediateSchedulerType) -> Observable { + return RepeatElement(element: element, scheduler: scheduler) +} diff --git a/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift b/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift index 3fa3468f..8677b858 100644 --- a/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift +++ b/RxTests/RxSwiftTests/Tests/Observable+CreationTest.swift @@ -100,6 +100,7 @@ extension ObservableCreationTests { } } +// range extension ObservableCreationTests { func testRange_Boundaries() { let scheduler = TestScheduler(initialClock: 0) @@ -127,4 +128,24 @@ extension ObservableCreationTests { next(203, -8) ]) } +} + +// repeatElement +extension ObservableCreationTests { + func testRepeat_Element() { + let scheduler = TestScheduler(initialClock: 0) + + let res = scheduler.start(207) { + repeatElement(42, scheduler) + } + + XCTAssertEqual(res.messages, [ + next(201, 42), + next(202, 42), + next(203, 42), + next(204, 42), + next(205, 42), + next(206, 42) + ]) + } } \ No newline at end of file