Skip to content

Instantly share code, notes, and snippets.

@MrSmart00
Created June 30, 2020 04:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MrSmart00/72741c6e73ceff8a0d261b3bf33aa6ba to your computer and use it in GitHub Desktop.
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.
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()
}
}
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