Created
June 30, 2020 04:10
-
-
Save MrSmart00/72741c6e73ceff8a0d261b3bf33aa6ba to your computer and use it in GitHub Desktop.
Swift Combine: Add Materialize Publisher with separatable function on Publishers. And add ignore Nil operation on Publisher.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Combine | |
public protocol OptionalType { | |
associatedtype Wrapped | |
var optional: Wrapped? { get } | |
} | |
extension Optional: OptionalType { | |
public var optional: Wrapped? { self } | |
} | |
public extension Publisher where Output: OptionalType { | |
func ignoreNil() -> AnyPublisher<Output.Wrapped, Failure> { | |
flatMap { output -> AnyPublisher<Output.Wrapped, Failure> in | |
guard let output = output.optional else { | |
return Empty<Output.Wrapped, Failure>(completeImmediately: false) | |
.eraseToAnyPublisher() | |
} | |
return Just(output) | |
.setFailureType(to: Failure.self) | |
.eraseToAnyPublisher() | |
} | |
.eraseToAnyPublisher() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Combine | |
public extension Publishers { | |
enum Event<T, E: Error> { | |
case value(T) | |
case failure(E) | |
case finished | |
var value: T? { | |
if case .value(let value) = self { | |
return value | |
} | |
return nil | |
} | |
var failure: E? { | |
if case .failure(let error) = self { | |
return error | |
} | |
return nil | |
} | |
var isCompleted: Bool { | |
if case .finished = self { | |
return true | |
} | |
return false | |
} | |
} | |
class Materialized<Upstream: Publisher>: Publisher { | |
public typealias Output = Event<Upstream.Output, Upstream.Failure> | |
public typealias Failure = Never | |
private let upstream: Upstream | |
init(upstream: Upstream) { | |
self.upstream = upstream | |
} | |
public func receive<S>(subscriber: S) where S: Subscriber, Materialized.Failure == S.Failure, Materialized.Output == S.Input { | |
let cancellable = upstream | |
.sink( | |
receiveCompletion: { | |
switch $0 { | |
case .failure(let error): | |
_ = subscriber.receive(.failure(error)) | |
case .finished: | |
_ = subscriber.receive(.finished) | |
} | |
subscriber.receive(completion: .finished) | |
}, | |
receiveValue: { _ = subscriber.receive(.value($0)) } | |
) | |
let subscription = MaterializedSubscription(cancellable: cancellable) | |
subscriber.receive(subscription: subscription) | |
} | |
private class MaterializedSubscription: Subscription { | |
private let cancellable: AnyCancellable | |
init(cancellable: AnyCancellable) { | |
self.cancellable = cancellable | |
} | |
func request(_ demand: Subscribers.Demand) {} | |
func cancel() { | |
cancellable.cancel() | |
} | |
} | |
} | |
} | |
public extension Publishers.Materialized { | |
func separate() -> (value: AnyPublisher<Upstream.Output?, Never>, failure: AnyPublisher<Upstream.Failure?, Never>) { | |
( | |
value: self.map { $0.value }.eraseToAnyPublisher(), | |
failure: self.map { $0.failure }.eraseToAnyPublisher() | |
) | |
} | |
} | |
public extension Publisher { | |
func materialize() -> Publishers.Materialized<Self> { | |
Publishers.Materialized(upstream: self) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment