diff --git a/Flow/Signal+Combiners.swift b/Flow/Signal+Combiners.swift index a00e088..25735e1 100644 --- a/Flow/Signal+Combiners.swift +++ b/Flow/Signal+Combiners.swift @@ -51,6 +51,61 @@ public func merge(_ signals: Signals) -> CoreSignal(_ other: S) -> CoreSignal where Kind.DropWrite == S.Kind.DropWrite { + let signal = providedSignal + let otherSignal = other.providedSignal + return CoreSignal(onEventType: { callback in + let state = StateAndCallback(state: S.Value?.none, callback: callback) // previous + + state += otherSignal.onEventType { eventType in + switch eventType { + case .initial(nil): + break + case .initial(let val?): + state.protectedVal = val + case .event(.value(let val)): + state.protectedVal = val + case .event(.end(let error)): + return state.call(.event(.end(error))) + } + } + + state += signal.onEventType { eventType in + switch eventType { + case .initial(nil): + state.call(.initial(nil)) + case .initial(let val?): + if let otherValue = state.protectedVal { + state.call(.initial((val, otherValue))) + } + case .event(.value(let val)): + if let otherValue = state.protectedVal { + state.call(.event(.value((val, otherValue)))) + } + case .event(.end(let error)): + state.call(.event(.end(error))) + } + } + + return state + }) + } +} + /// Returns a new signal merging the values emitted from `signals` /// /// a)---b---c------d-| diff --git a/FlowTests/SignalProviderTests.swift b/FlowTests/SignalProviderTests.swift index 4b6ff02..86d10cf 100644 --- a/FlowTests/SignalProviderTests.swift +++ b/FlowTests/SignalProviderTests.swift @@ -441,6 +441,80 @@ class SignalProviderTests: XCTestCase { } } + func testWithLatestFrom() { + runTest(timeout: 10) { bag in + let a = ReadWriteSignal("") + let b = ReadWriteSignal(0) + + let expected = [("b", 1), ("c", 2), ("d", 2)] + + var buffer = [(String, Int)]() + + let signal = a.plain().withLatestFrom(b.plain()) + + let expectation = self.expectation(description: "Values should be combined in order") + bag += signal.onValue { v in + buffer.append(v) + + if buffer.count == expected.count { + var equal = true + for (index, element) in expected.enumerated() { + let t = buffer[index] + if t.0 != element.0 { + equal = false + } + } + + if equal { expectation.fulfill() } + } + } + + a.value = "a" + b.value = 1 + a.value = "b" + b.value = 2 + a.value = "c" + a.value = "d" + } + } + + func testWithLatestFromUsingSource() { + runTest(timeout: 10) { bag in + let a = ReadWriteSignal(".") + let b = ReadWriteSignal(0) + + let expected = [(".", 0), ("a", 0), ("b", 1), ("c", 2), ("d", 2)] + + var buffer = [(String, Int)]() + + let signal = a.withLatestFrom(b) + + let expectation = self.expectation(description: "Values should be combined in order") + bag += signal.atOnce().onValue { v in + buffer.append(v) + + if buffer.count == expected.count { + var equal = true + for (index, element) in expected.enumerated() { + let t = buffer[index] + if t.0 != element.0 { + equal = false + } + } + + if equal { expectation.fulfill() } + } + } + + a.value = "a" + b.value = 1 + a.value = "b" + b.value = 2 + a.value = "c" + a.value = "d" + } + } + func testCombineLatestWith() { runTest(timeout: 10) { bag in let a = ReadWriteSignal("")