-
-
Save BryanJBryce/fd99d64a613f5b290b9c10737075ba8c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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