From 9c324cd0a4755e4061f9e46a394185aec3ca2700 Mon Sep 17 00:00:00 2001 From: sergdort Date: Tue, 28 Sep 2021 13:19:32 +0100 Subject: [PATCH] Add firstValueAfterNil --- Sources/CombineFeedback/Feedback.swift | 58 +++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/Sources/CombineFeedback/Feedback.swift b/Sources/CombineFeedback/Feedback.swift index e16d0c6..6169d70 100644 --- a/Sources/CombineFeedback/Feedback.swift +++ b/Sources/CombineFeedback/Feedback.swift @@ -231,6 +231,55 @@ public struct Feedback { }) } + public static func firstValueAfterNil( + _ transform: @escaping (State) -> Value?, + effects: @escaping (Value, Dependency) -> Effect + ) -> Feedback where Effect.Output == Event, Effect.Failure == Never { + return .compacting( + state: { state -> AnyPublisher, Never> in + return state.scan((lastWasNil: true, output: NilEdgeTransition?.none)) { acum, state in + var temp = acum + let result = transform(state) + temp.output = nil + + switch (temp.lastWasNil, result) { + case (true, .none), (false, .some): + return temp + case let (true, .some(value)): + temp.lastWasNil = false + temp.output = .populated(value) + case (false, .none): + temp.lastWasNil = true + temp.output = .cleared + } + return temp + } + .compactMap(\.output) + .eraseToAnyPublisher() + }, + effects: { transition, dependency -> AnyPublisher in + switch transition { + case let .populated(value): + return effects(value, dependency).eraseToAnyPublisher() + case .cleared: + return Empty().eraseToAnyPublisher() + } + } + ) + } + + @available(iOS 15.0, *) + public static func firstValueAfterNil( + _ transform: @escaping (State) -> Value?, + effect: @escaping (Value, Dependency) async -> Event + ) -> Feedback { + .firstValueAfterNil(transform) { value, dependency in + TaskPublisher { + await effect(value, dependency) + } + } + } + /// Creates a Feedback which re-evaluates the given effect every time the /// state changes. /// @@ -390,7 +439,7 @@ struct TaskPublisher: Publisher { } final class TaskSubscription: Combine.Subscription where Downstream.Input == Output, Downstream.Failure == Never { - private var handle: Task.Handle? + private var handle: Task? private let work: () async -> Output private let subscriber: Downstream @@ -400,7 +449,7 @@ struct TaskPublisher: Publisher { } func start() { - self.handle = async { [subscriber, work] in + self.handle = Task.init { [subscriber, work] in let result = await work() _ = subscriber.receive(result) subscriber.receive(completion: .finished) @@ -415,3 +464,8 @@ struct TaskPublisher: Publisher { } } } + +private enum NilEdgeTransition { + case populated(Value) + case cleared +}