Skip to content

Instantly share code, notes, and snippets.

@myobie
Last active April 7, 2020 11:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save myobie/4813b9482ce4057910441ed996c15c0d to your computer and use it in GitHub Desktop.
Save myobie/4813b9482ce4057910441ed996c15c0d to your computer and use it in GitHub Desktop.
Make any class a super simple publisher with publish() and complete() functions
class Names: SimplePublisher {
typealias Output = Result<String, Error>
var subscriptions = [SimpleSubscription<Output, Failure>]()
let names = ["Alice", "Bob", "Claris", "Doug"]
shoutName() {
if let name = names.randomElement() {
publish(.success(name))
} else {
assertionFailure("There are def some names in there...")
}
}
}
let names = Names()
let _ = names.sink { result in
print("Sinked a name \(name)")
}
names.shoutName()
names.shoutName()
names.shoutName()
names.shoutName()
names.complete()
import Foundation
import Combine
import Synchronized
protocol SimplePublisher: Publisher, Synchronized {
var subscriptions: [SimpleSubscription<Output, Failure>] { get set }
}
extension SimplePublisher {
public func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
let subscription = SimpleSubscription(subscriber: AnySubscriber(subscriber))
subscriber.receive(subscription: subscription)
sync {
subscriptions.append(subscription)
}
}
func publish(_ output: Output) {
var subscriptions = [SimpleSubscription<Output, Failure>]()
sync {
subscriptions = self.subscriptions
}
for subscription in subscriptions {
guard let demand = subscription.demand else { continue }
guard demand > 0 else { continue }
let newDemand = subscription.subscriber.receive(output)
subscription.request(newDemand)
}
}
func complete() {
complete(.finished)
}
func complete(_ failure: Failure) {
complete(.failure(failure))
}
func complete(_ failure: Subscribers.Completion<Failure>) {
var subscriptions = [SimpleSubscription<Output, Failure>]()
sync {
subscriptions = self.subscriptions
self.subscriptions.removeAll()
}
for subscription in subscriptions {
subscription.subscriber.receive(completion: failure)
}
}
}
import Foundation
import Combine
class SimpleSubscription<Input, Failure: Error>: Subscription {
let subscriber: AnySubscriber<Input, Failure>
var demand: Subscribers.Demand? = nil
init(subscriber: AnySubscriber<Input, Failure>) {
self.subscriber = subscriber
}
func request(_ demand: Subscribers.Demand) {
self.demand = demand
}
func cancel() {
self.demand = nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment