import Combine import Foundation public enum Bus { } public extension Bus { enum Option { case async } } extension Bus { final class Service { static let singleton = Service() let events = PassthroughSubject<(key: String, value: Any), Never>() var subscriptions = [AnyCancellable]() func send(_ key: String, _ value: Any) { /**/print("ИГР BusS.send key/value: '\(key)'/'\(value)'") events.send((key, value)) } } } private extension Bus { static func subscribe( _ subscription: AnyCancellable?, _ sub: UnsafeMutablePointer<[AnyCancellable]>? ) { guard let subscription else { return } if let sub = sub { sub.pointee.append(subscription) } else { Service.singleton.subscriptions.append(subscription) } } } public extension Bus { static func receive( _ keys: Set, _ handler: @escaping ((String, T) -> Void), opt: [Option] = [], sub: UnsafeMutablePointer<[AnyCancellable]>? = nil ) { var subscription: AnyCancellable? let isAsync = opt.contains(.async) // Async. if isAsync { subscription = Service.singleton.events .compactMap { convertKeyValue(keys, $0) } .receive(on: DispatchQueue.main) .sink { v in handler(v.0, v.1) } } // Async. if !isAsync { subscription = Service.singleton.events .compactMap { convertKeyValue(keys, $0) } .sink { v in handler(v.0, v.1) } } subscribe(subscription, sub) } static func send( _ key: String, _ node: AnyPublisher, opt: [Option] = [], sub: UnsafeMutablePointer<[AnyCancellable]>? = nil ) { var subscription: AnyCancellable? let isAsync = opt.contains(.async) // Async. if isAsync { subscription = node .receive(on: DispatchQueue.main) .sink { v in Service.singleton.send(key, v) } } // Sync. if !isAsync { subscription = node .sink { v in Service.singleton.send(key, v) } } subscribe(subscription, sub) } static func send(_ key: String, _ value: Any) { Service.singleton.send(key, value) } } public extension Bus { static func process( _ keysIn: Set, _ keyOut: String, _ handler: @escaping ((Src) -> Dst?), opt: [Option] = [], sub: UnsafeMutablePointer<[AnyCancellable]>? = nil ) { var subscription: AnyCancellable? let isAsync = opt.contains(.async) // Async. if isAsync { subscription = Service.singleton.events .compactMap { processKeysValue($0, keysIn, handler) } .receive(on: DispatchQueue.main) .sink { vOut in Service.singleton.send(keyOut, vOut) } } // Sync. if !isAsync { subscription = Service.singleton.events .compactMap { processKeysValue($0, keysIn, handler) } .sink { vOut in Service.singleton.send(keyOut, vOut) } } subscribe(subscription, sub) } }