From 114bbece3b3359fa2e3e7237caba6d4f363a7a81 Mon Sep 17 00:00:00 2001 From: Chris Eidhof Date: Tue, 12 Mar 2019 09:02:14 +0100 Subject: [PATCH] Incremental fixes --- Sources/Incremental/Incremental.swift | 19 ++++---- Tests/IncrementalTests/IncrementalTests.swift | 45 +++++++++++++++++++ 2 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 Tests/IncrementalTests/IncrementalTests.swift diff --git a/Sources/Incremental/Incremental.swift b/Sources/Incremental/Incremental.swift index cdeceea..051654b 100644 --- a/Sources/Incremental/Incremental.swift +++ b/Sources/Incremental/Incremental.swift @@ -44,16 +44,16 @@ fileprivate struct Register { } final class Observer { - let _height: () -> Int + let _height: (_ seen: [AnyObject]) -> Int let fire: () -> () var cancelled = false - init(fire: @escaping () -> (), height: @escaping () -> Int) { + init(fire: @escaping () -> (), height: @escaping (_ seen: [AnyObject]) -> Int) { self.fire = fire self._height = height } - var height: Int { - return _height() + func height(_ seen: [AnyObject]) -> Int { + return _height(seen + [self]) } } @@ -64,7 +64,7 @@ final class Queue { func enqueue(_ newObservers: [Observer]) { observers.append(contentsOf: newObservers) - observers.sort { $0.height < $1.height } + observers.sort { $0.height([]) < $1.height([]) } process() } @@ -98,7 +98,7 @@ public class Observable { observer(value) return observers.add(Observer(fire: { observer(self.value) - }, height: { + }, height: { _ in return 0 })) } @@ -108,15 +108,16 @@ public class Observable { observers.remove(token) } - var height: Int { - let maxChildHeight = observers.values.map { $0.height }.max() + func height(_ seen: [AnyObject]) -> Int { + let newSeen = seen + [self] + let maxChildHeight = observers.values.filter { child in !newSeen.contains { $0 === child } }.map { $0.height(newSeen) }.max() return (maxChildHeight ?? 0) + 1 } @discardableResult func addChild(fire: @escaping () -> (), dependent: @escaping () -> Observable) -> Token { fire() return observers.add(Observer(fire: fire, height: { - dependent().height + dependent().height($0) })) } diff --git a/Tests/IncrementalTests/IncrementalTests.swift b/Tests/IncrementalTests/IncrementalTests.swift new file mode 100644 index 0000000..edb4f99 --- /dev/null +++ b/Tests/IncrementalTests/IncrementalTests.swift @@ -0,0 +1,45 @@ +import Foundation +import XCTest +import Incremental + +func &&(lhs: Observable, rhs: Observable) -> Observable { + return lhs.flatMap { x in rhs.map { $0 && x } } +} + +final class IncrementalTests: XCTestCase { + func testFlatMapNested() { + let o = Observable(0) + let o2 = o.flatMap { _ in o } + var results: [Int] = [] + o2.observe { results.append($0) } + o.send(1) // eventually crashes here + XCTAssert(results == [0, 1]) + } + + func testFlatMapMap() { + let x = Observable(1) + let double = x.flatMap { value in x.map { value + $0 }} + var result: [Int] = [] + let disposable = double.observe { result.append($0) } + x.send(2) + XCTAssertEqual(result, [2,4]) + } + + func test() { + let airplaneMode = Observable(false) + let cellular = Observable(true) + let wifi = Observable(true) + + let notAirplaneMode = airplaneMode.map { !$0 } + + let cellularEnabled = notAirplaneMode && cellular + let wifiEnabled = notAirplaneMode && wifi + let wifiAndCellular = wifiEnabled && cellularEnabled + + var results: [Bool] = [] + _ = wifiAndCellular.observe { results.append($0) } + airplaneMode.send(true) + airplaneMode.send(false) + XCTAssertEqual(results, [true,false,true]) + } +}