// // EventHub.swift // FirebladeECS // // Created by Christian Treffs on 09.10.17. // public protocol EventHub: class { func subscribe(classRef eventHandlerRefUnowned: EventHandler, eventHandler: @escaping (E) -> Void) func unsubscribe(classRef eventHandlerRefUnowned: EventHandler, eventHandler: @escaping (E) -> Void) weak var sniffer: EventSniffer? { get set } } public class DefaultEventHub: EventHub, EventDispatcher { public var sniffer: EventSniffer? public init() { } private var listeners: [UET: ContiguousArray] = [:] private func typeEvent(opaqueEvent: Event, eventHandler: @escaping (E) -> Void ) { guard let typedEvent: E = opaqueEvent as? E else { fatalError() // TODO: meaningful message } eventHandler(typedEvent) } private func push(listener newListener: EventHandlerRef, `for` uet: UET) { if listeners[uet] == nil { listeners[uet] = [] listeners.reserveCapacity(1) } listeners[uet]?.append(newListener) } } // MARK: - event center extension DefaultEventHub { final public func subscribe(classRef unownedListenerRef: EventHandler, eventHandler handler: @escaping (E) -> Void) { let eventListener: EventHandlerRef = EventHandlerRef(eventHandlerClassRefUnowned: unownedListenerRef, eventHandler: { self.typeEvent(opaqueEvent: $0, eventHandler: handler) }) push(listener: eventListener, for: E.uet) sniffer?.subscriber(subsribed: E.uet) } final public func unsubscribe(classRef listenerRef: EventHandler, eventHandler handler: @escaping (E) -> Void) { let uet: UET = E.uet if let removeIdx: Int = listeners[uet]?.index(is: listenerRef) { let removed = listeners[uet]?.remove(at: removeIdx) assert(removed != nil) sniffer?.subscriber(unsubsribed: uet) } } } // MARK: - event dispatcher delegate extension DefaultEventHub { final public func dispatch(_ event: E) { let uet: UET = E.uet listeners[uet]?.forEach { $0.eventHandler(event) } sniffer?.dispatched(event: event) } } // MARK: - event dumper public protocol EventSniffer: class { func subscriber(subsribed to: UET) func subscriber(unsubsribed from: UET) func dispatched(event: E) }