diff --git a/Sources/Verge/Store/Accumulator.swift b/Sources/Verge/Store/Accumulator.swift index 83b7cbe047..df6d4487e3 100644 --- a/Sources/Verge/Store/Accumulator.swift +++ b/Sources/Verge/Store/Accumulator.swift @@ -1,56 +1,58 @@ -public protocol Sink { +public protocol Sink { associatedtype Source func receive(source: Source) } public struct AccumulationBuilder: ~Copyable { - public func ifChanged(_ selector: @escaping (Source) -> U) -> IfChangedSink { + public func ifChanged(_ selector: @escaping (Source) -> U) -> SinkIfChanged { .init(selector: selector) } - public final class IfChangedSink: Sink { +} - private let selector: (Source) -> Target +public final class SinkIfChanged: Sink { - private var latestValue: Target? - private var handler: ((consuming Target) -> Void)? + private let selector: (Source) -> Target - public init(selector: @escaping (Source) -> Target) { - self.selector = selector - } + private var latestValue: Target? + private var handler: ((consuming Target) -> Void)? - public func `do`(_ perform: @escaping (consuming Target) -> Void) -> Self { - self.handler = perform - return self - } + public init(selector: @escaping (Source) -> Target) { + self.selector = selector + } - public func receive(source: Source) { + public func `do`(_ perform: @escaping (consuming Target) -> Void) -> Self { + self.handler = perform + return self + } - let selected = selector(source) + public func receive(source: Source) { - guard latestValue != selected else { - return - } + let selected = selector(source) - latestValue = selected + guard latestValue != selected else { + return + } - handler?(selected) + latestValue = selected - } - } + handler?(selected) + } } extension DispatcherType { - public func accumulate(@SinkComponentBuilder _ buildSubscription: (consuming AccumulationBuilder) -> SinkGroup) -> Cancellable { + public func accumulate( + queue: MainActorTargetQueue = .mainIsolated(), + @SinkComponentBuilder _ buildSubscription: (consuming AccumulationBuilder) -> SinkGroup) -> Cancellable { let builder = AccumulationBuilder() let group = buildSubscription(consume builder) - return sinkState { state in + return sinkState(dropsFirst: false, queue: queue) { state in group.receive(source: state.primitive) @@ -60,6 +62,19 @@ extension DispatcherType { } +public struct SinkBox: Sink { + + private let base: any Sink + + public init(base: some Sink) { + self.base = base + } + + public func receive(source: Source) { + base.receive(source: source) + } +} + public struct SinkGroup: Sink { private let _receive: (Source) -> Void @@ -79,16 +94,30 @@ public struct SinkComponentBuilder { public static func buildBlock() -> SinkGroup { return .init(receive: { _ in }) } +// +// public static func buildBlock(_ components: repeat AccumulationBuilder.IfChangedSink) -> SinkGroup { +// .init { source in +// +// func run(_ component: AccumulationBuilder.IfChangedSink) { +// component.receive(source: source) +// } +// +// repeat run(each components) +// +// } +// } + + public static func buildExpression(_ expression: any Sink) -> SinkBox { + .init(base: expression) + } - public static func buildBlock(_ components: repeat AccumulationBuilder.IfChangedSink) -> SinkGroup { + public static func buildBlock(_ sinks: (SinkBox)...) -> SinkGroup { .init { source in - func run(_ component: AccumulationBuilder.IfChangedSink) { - component.receive(source: source) + for sink in sinks { + sink.receive(source: source) } - repeat run(each components) - } } diff --git a/Tests/VergeTests/AccumulationTests.swift b/Tests/VergeTests/AccumulationTests.swift index 65f7a39ffe..291e0b696f 100644 --- a/Tests/VergeTests/AccumulationTests.swift +++ b/Tests/VergeTests/AccumulationTests.swift @@ -22,6 +22,10 @@ final class AccumulationTests: XCTestCase { } + SinkIfChanged(selector: \.count).do { value in + print(value) + } + } store.commit {