Skip to content

Instantly share code, notes, and snippets.

@rob-brown
Last active November 18, 2018 04:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rob-brown/0725f6609accd6348f2dc5bc883b1cd1 to your computer and use it in GitHub Desktop.
Save rob-brown/0725f6609accd6348f2dc5bc883b1cd1 to your computer and use it in GitHub Desktop.
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))
}
}
}
@rob-brown
Copy link
Author

Dependencies

Actor
MessageRouter

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment