Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions Sources/Incremental/Incremental.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ fileprivate struct Register<A> {
}

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])
}
}

Expand All @@ -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()
}

Expand Down Expand Up @@ -98,7 +98,7 @@ public class Observable<A> {
observer(value)
return observers.add(Observer(fire: {
observer(self.value)
}, height: {
}, height: { _ in
return 0
}))
}
Expand All @@ -108,15 +108,16 @@ public class Observable<A> {
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<A>(fire: @escaping () -> (), dependent: @escaping () -> Observable<A>) -> Token {
fire()
return observers.add(Observer(fire: fire, height: {
dependent().height
dependent().height($0)
}))
}

Expand Down
45 changes: 45 additions & 0 deletions Tests/IncrementalTests/IncrementalTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Foundation
import XCTest
import Incremental

func &&(lhs: Observable<Bool>, rhs: Observable<Bool>) -> Observable<Bool> {
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<Bool>(false)
let cellular = Observable<Bool>(true)
let wifi = Observable<Bool>(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])
}
}