Skip to content

Instantly share code, notes, and snippets.

@aduuub
Created November 1, 2023 22:47
Show Gist options
  • Save aduuub/468c2b7338ffe43da47e6662f3022db6 to your computer and use it in GitHub Desktop.
Save aduuub/468c2b7338ffe43da47e6662f3022db6 to your computer and use it in GitHub Desktop.
A Publisher that turns a completion with Result into a Combine Publisher
import Foundation
import Combine
public struct ResultPublisher<Success, Failure>: Publisher where Failure: Error {
public typealias Output = Success
public typealias Failure = Failure
public typealias ResultCallback = (Result<Success, Failure>) -> Void
let invocation: (@escaping ResultCallback) -> Void
public init(_ invocation: @escaping (@escaping ResultCallback) -> Void) {
self.invocation = invocation
}
public func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Success == S.Input {
let subscription = ResultSubscription(
invocation: invocation,
subscriber: subscriber
)
subscriber.receive(subscription: subscription)
}
}
private extension ResultPublisher {
class ResultSubscription<S: Subscriber>: Subscription where S.Input == Success, S.Failure == Failure {
private let invocation: (@escaping ResultCallback) -> Void
private var subscriber: S?
init(invocation: @escaping (@escaping ResultCallback) -> Void, subscriber: S) {
self.invocation = invocation
self.subscriber = subscriber
invokeCallback()
}
func request(_ demand: Subscribers.Demand) {
// Adjust the demand in case you need to
}
func cancel() {
subscriber = nil
}
private func invokeCallback() {
guard let subscriber = subscriber else {
return
}
invocation { result in
switch result {
case .success(let value):
_ = subscriber.receive(value)
case .failure(let error):
subscriber.receive(completion: .failure(error))
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment