import Foundation | |
import Actor | |
import MessageRouter | |
public final class Core<State, Event, Command> { | |
public typealias CommandProcessor = (Core<State, Event, Command>, Command) -> Void | |
public typealias EventHandler = (State, Event) -> CoreUpdate<State, Command> | |
public let stateChanged = MessageRouter<State>() | |
public var currentState: State { | |
return stateMachine.currentState | |
} | |
private let stateMachine: PureStateMachine<State, Event, CoreUpdate<State, Command>> | |
private let commandProcessors: [CommandProcessor] | |
public init(initialState: State, commandProcessors: [CommandProcessor] = [], handler: @escaping EventHandler) { | |
self.stateMachine = PureStateMachine<State, Event, CoreUpdate<State, Command>>(initialState: initialState, label: "pro.tricksofthetrade.Core") { state, event in | |
let update = handler(state, event) | |
return (update.state ?? state, update) | |
} | |
self.commandProcessors = commandProcessors | |
} | |
public func fire(event: Event) { | |
DispatchQueue.global(qos: .default).async { | |
let update = self.stateMachine.handleEvent(event) | |
if let state = update.state { | |
self.stateChanged.send(state) | |
} | |
for command in update.commands { | |
for processor in self.commandProcessors { | |
processor(self, command) | |
} | |
} | |
} | |
} | |
public func perform(command: Command) { | |
DispatchQueue.global(qos: .default).async { | |
self.commandProcessors.forEach { $0(self, command) } | |
} | |
} | |
} | |
public enum CoreUpdate<State, Command> { | |
case NoUpdate | |
case State(State) | |
case Commands([Command]) | |
case StateAndCommands(State, [Command]) | |
public var state: State? { | |
switch self { | |
case .NoUpdate, .Commands: return nil | |
case .State(let state): return state | |
case .StateAndCommands(let state, _): return state | |
} | |
} | |
public var commands: [Command] { | |
switch self { | |
case .NoUpdate, .State: return [] | |
case .Commands(let commands): return commands | |
case .StateAndCommands(_, let commands): return commands | |
} | |
} | |
public func mapState<T>(_ closure: (State) -> T) -> CoreUpdate<T, Command> { | |
switch self { | |
case .NoUpdate: | |
return .NoUpdate | |
case .Commands(let commands): | |
return .Commands(commands) | |
case .State(let state): | |
return .State(closure(state)) | |
case .StateAndCommands(let state, let commands): | |
return .StateAndCommands(closure(state), commands) | |
} | |
} | |
public func mapCommand<T>(_ closure: (Command) -> T) -> CoreUpdate<State, T> { | |
switch self { | |
case .NoUpdate: | |
return .NoUpdate | |
case .Commands(let commands): | |
return .Commands(commands.map(closure)) | |
case .State(let state): | |
return .State(state) | |
case .StateAndCommands(let state, let commands): | |
return .StateAndCommands(state, commands.map(closure)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment