MobiusCore/Source/EffectHandlers/EffectHandler.swift (28 lines of code) (raw):
// Copyright Spotify AB.
// SPDX-License-Identifier: Apache-2.0
/// This protocol defines the contract for an Effect Handler which takes `EffectParameters` as input, and produces
/// `Event`s as output.
///
/// For each input to the `handle` function, zero or more `Event`s can be sent as output using `callback.send(Event)`.
/// Once the effect has been completely handled (i.e. when the handler will not produce any more events)
/// call `callback.end()`.
///
/// Note: `EffectHandler` should be used in conjunction with an `EffectRouter`.
public protocol EffectHandler {
associatedtype EffectParameters
associatedtype Event
/// Handle an effect with `EffectParameters` as its associated values.
///
/// To output events, call `callback.send`.
/// Call `callback.end()` once the input has been handled to prevent memory leaks.
///
/// This returns a `Disposable` which cancels the handling of this effect. This `Disposable` will
/// not be called if `callback.end()` has already been called.
///
/// Note: If it does not make sense to finish handling an effect, you should be using a `Connectable` instead of
/// this protocol.
/// Note: Mobius will not dispose the returned `Disposable` if `callback.end()` has already been called.
/// - Parameter effectParameters: The associated values of the loop `Effect` being handled.
/// - Parameter callback: The `EffectCallback` used to communicate with the associated Mobius loop.
func handle(
_ effectParameters: EffectParameters,
_ callback: EffectCallback<Event>
) -> Disposable
}
/// A type-erased wrapper of the `EffectHandler` protocol.
public struct AnyEffectHandler<EffectParameters, Event>: EffectHandler {
private let handleClosure: (EffectParameters, EffectCallback<Event>) -> Disposable
/// Creates an anonymous `EffectHandler` that implements `handle` with the provided closure.
///
/// - Parameter handle: An effect handler `handle` function; see the documentation for `EffectHandler.handle`.
public init(handle: @escaping (EffectParameters, EffectCallback<Event>) -> Disposable) {
self.handleClosure = handle
}
/// Creates a type-erased `EffectHandler` that wraps the given instance.
public init<Handler: EffectHandler>(
handler: Handler
) where Handler.EffectParameters == EffectParameters, Handler.Event == Event {
let handleClosure: (EffectParameters, EffectCallback<Event>) -> Disposable
if let anyHandler = handler as? AnyEffectHandler {
handleClosure = anyHandler.handleClosure
} else {
handleClosure = handler.handle
}
self.init(handle: handleClosure)
}
public func handle(_ parameters: EffectParameters, _ callback: EffectCallback<Event>) -> Disposable {
return self.handleClosure(parameters, callback)
}
}