MobiusCore/Source/EffectHandlers/ThreadSafeConnectable.swift (51 lines of code) (raw):
// Copyright Spotify AB.
// SPDX-License-Identifier: Apache-2.0
final class ThreadSafeConnectable<Event, Effect>: Connectable {
private let connectable: AnyConnectable<Effect, Event>
private let lock = Lock()
private var output: Consumer<Event>?
private var connection: Connection<Effect>?
init<Conn: Connectable>(
connectable: Conn
) where Conn.Input == Effect, Conn.Output == Event {
self.connectable = AnyConnectable(connectable)
}
func connect(_ output: @escaping (Event) -> Void) -> Connection<Effect> {
return lock.synchronized {
guard self.output == nil, connection == nil else {
MobiusHooks.errorHandler(
"Connection limit exceeded: The Connectable \(type(of: self)) is already connected. " +
"Unable to connect more than once",
#file,
#line
)
}
self.output = output
connection = connectable.connect(self.dispatch)
return Connection(
acceptClosure: accept,
disposeClosure: dispose
)
}
}
private func accept(_ effect: Effect) {
if let connection = lock.synchronized(closure: { connection }) {
connection.accept(effect)
}
}
private func dispatch(event: Event) {
if let output = lock.synchronized(closure: { output }) {
output(event)
}
}
private func dispose() {
var disposeConnection: (() -> Void)?
lock.synchronized {
output = nil
disposeConnection = connection?.dispose
connection = nil
}
disposeConnection?()
}
deinit {
dispose()
}
}