|
- import Combine
- import Foundation
-
- public protocol MPAKControllerProtocol: AnyObject {
- associatedtype Model
-
- func pipe<T>(
- dbg: String?,
- sub: UnsafeMutablePointer<[AnyCancellable]>?,
- _ node: AnyPublisher<T, Never>,
- _ reaction: @escaping (inout Model) -> Void,
- _ reversion: ((inout Model) -> Void)?
- )
-
- func pipeValue<T>(
- dbg: String?,
- sub: UnsafeMutablePointer<[AnyCancellable]>?,
- _ node: AnyPublisher<T, Never>,
- _ reaction: @escaping (inout Model, T) -> Void,
- _ reversion: ((inout Model, T) -> Void)?
- )
- }
-
- extension MPAK {
- open class Controller<Model>: MPAKControllerProtocol {
- public let m: CurrentValueSubject<Model, Never>
- public var subscriptions = [AnyCancellable]()
-
- private var debugClassName: String?
- private var debugLog: ((String) -> Void)?
- private var model: Model
-
- public init(
- _ model: Model,
- debugClassName: String? = nil,
- debugLog: ((String) -> Void)? = nil
- ) {
- m = .init(model)
- self.model = model
- self.debugClassName = debugClassName
- self.debugLog = debugLog
- }
-
- public func pipe<T>(
- dbg: String? = nil,
- sub: UnsafeMutablePointer<[AnyCancellable]>? = nil,
- _ node: AnyPublisher<T, Never>,
- _ reaction: @escaping (inout Model) -> Void,
- _ reversion: ((inout Model) -> Void)? = nil
- ) {
- let subscription = node
- .sink { [weak self] _ in
- assert(Thread.isMainThread)
- guard let self = self else { return }
- self.dbgLog(dbg)
- reaction(&self.model)
- let modelCopy = self.model
- if let rev = reversion {
- rev(&self.model)
- }
- self.m.send(modelCopy)
- }
- if let sub = sub {
- sub.pointee.append(subscription)
- } else {
- subscriptions.append(subscription)
- }
- }
-
- public func pipeOptional<T>(
- dbg: String? = nil,
- _ node: AnyPublisher<T?, Never>,
- _ reaction: @escaping (inout Model, T?) -> Void,
- _ reversion: ((inout Model, T?) -> Void)? = nil
- ) {
- node
- .sink { [weak self] value in
- assert(Thread.isMainThread)
- guard let self = self else { return }
- self.dbgLog(dbg)
- reaction(&self.model, value)
- let modelCopy = self.model
- if let rev = reversion {
- rev(&self.model, value)
- }
- self.m.send(modelCopy)
- }
- .store(in: &subscriptions)
- }
-
- public func pipeValue<T>(
- dbg: String? = nil,
- sub: UnsafeMutablePointer<[AnyCancellable]>? = nil,
- _ node: AnyPublisher<T, Never>,
- _ reaction: @escaping (inout Model, T) -> Void,
- _ reversion: ((inout Model, T) -> Void)? = nil
- ) {
- let subscription = node
- .sink { [weak self] value in
- assert(Thread.isMainThread)
- guard let self = self else { return }
- self.dbgLog(dbg)
- reaction(&self.model, value)
- let modelCopy = self.model
- if let rev = reversion {
- rev(&self.model, value)
- }
- self.m.send(modelCopy)
- }
- if let sub = sub {
- sub.pointee.append(subscription)
- } else {
- subscriptions.append(subscription)
- }
- }
-
- private func dbgLog(_ text: String?) {
- guard
- let className = debugClassName,
- let log = debugLog,
- let text = text
- else {
- return
- }
- log("\(className).\(text)")
- }
- }
- }
|