import Foundation private final class MulticastInstance<T> { let disposable: Disposable var subscribers = Bag<(T) -> Void>() var lock = Lock() init(disposable: Disposable) { self.disposable = disposable } } public final class Multicast<T> { private let lock = Lock() private var instances: [String: MulticastInstance<T>] = [:] public init() { } public func get(key: String, signal: Signal<T, NoError>) -> Signal<T, NoError> { return Signal { subscriber in var instance: MulticastInstance<T>! var beginDisposable: MetaDisposable? self.lock.locked { if let existing = self.instances[key] { instance = existing } else { let disposable = MetaDisposable() instance = MulticastInstance(disposable: disposable) beginDisposable = disposable } } var index: Bag<(T) -> Void>.Index! instance.lock.locked { index = instance.subscribers.add({ next in subscriber.putNext(next) }) } if let beginDisposable = beginDisposable { beginDisposable.set(signal.start(next: { next in var subscribers: [(T) -> Void]! instance.lock.locked { subscribers = instance.subscribers.copyItems() } for subscriber in subscribers { subscriber(next) } }, error: { _ in }, completed: { self.lock.locked { self.instances.removeValue(forKey: key) } })) } return ActionDisposable { var remove = false instance.lock.locked { instance.subscribers.remove(index) if instance.subscribers.isEmpty { remove = true } } if remove { self.lock.locked { let _ = self.instances.removeValue(forKey: key) } } } } } } public final class MulticastPromise<T> { public let subscribers = Bag<(T) -> Void>() public let lock = Lock() public var value: T? public init() { } }