Skip to content

Instantly share code, notes, and snippets.

@ordazgustavo
Created November 25, 2019 05:26
Show Gist options
  • Save ordazgustavo/54f9d67f037a966bf7fe2f8715906a76 to your computer and use it in GitHub Desktop.
Save ordazgustavo/54f9d67f037a966bf7fe2f8715906a76 to your computer and use it in GitHub Desktop.
MUI
// MARK: - Implementation Example
struct LightMachine: StateMachine {
typealias States = LightStates
typealias Events = LightEvents
typealias Context = (Int)
enum LightStates {
case green
case yellow
case red
}
enum LightEvents {
case timer
}
var context: Context {
get { (count) }
}
@ExtendedState private var count = 0
var chart: some Machine {
Chart(id: "light") {
Initial(state: LightStates.green)
StateNodes {
From(state: LightStates.green) {
On {
Event(LightEvents.timer) {
Entry(action: increment)
Target(state: LightStates.yellow)
Action(increment, increment)
Exit(action: decrement)
Guard(cond: nonNegative)
}
}
}
From(state: LightStates.yellow) {
On {
Event(LightEvents.timer) {
Entry(action: increment)
Target(state: LightStates.red)
Action(increment)
Exit(action: decrement)
Guard(cond: nonNegative)
}
}
}
From(state: LightStates.red) {
On {
Event(LightEvents.timer) {
Entry(action: increment)
Target(state: LightStates.green)
Action(increment)
Exit(action: decrement)
Guard(cond: nonNegative)
}
}
}
}
}
}
func increment() -> Void {
count += 1
}
func decrement() -> Void {
count -= 1
}
func nonNegative() -> Bool {
count >= 0
}
}
// MARK: - Builders
@_functionBuilder struct ChartBuilder {
static func buildBlock<C0, C1>(
_ c0: C0,
_ c1: C1
) -> TupleDescriptor<(C0, C1)> where C0: Machine, C1: Machine {
TupleDescriptor((c0, c1))
}
}
@_functionBuilder struct StateBuilder {
static func buildBlock<C0>(
_ c0: C0
) -> TupleDescriptor<(C0)> where C0: Machine {
TupleDescriptor((c0))
}
static func buildBlock<C0, C1>(
_ c0: C0,
_ c1: C1
) -> TupleDescriptor<(C0, C1)> where C0: Machine, C1: Machine {
TupleDescriptor((c0, c1))
}
static func buildBlock<C0, C1, C2>(
_ c0: C0,
_ c1: C1,
_ c2: C2
) -> TupleDescriptor<(C0, C1, C2)> where C0: Machine, C1: Machine, C2: Machine {
TupleDescriptor((c0, c1, c2))
}
static func buildBlock<C0, C1, C2, C3>(
_ c0: C0,
_ c1: C1,
_ c2: C2,
_ c3: C3
) -> TupleDescriptor<(C0, C1, C2, C3)> where C0: Machine, C1: Machine, C2: Machine, C3: Machine {
TupleDescriptor((c0, c1, c2, c3))
}
static func buildBlock<C0, C1, C2, C3, C4>(
_ c0: C0,
_ c1: C1,
_ c2: C2,
_ c3: C3,
_ c4: C4
) -> TupleDescriptor<(C0, C1, C2, C3, C4)> where C0: Machine, C1: Machine, C2: Machine, C3: Machine, C4: Machine {
TupleDescriptor((c0, c1, c2, c3, c4))
}
}
@_functionBuilder struct TransitionBuilder {
static func buildBlock<Component>(
_ component: Component
) -> Component where Component: Machine {
component
}
}
@_functionBuilder struct OnBuilder {
static func buildBlock<Component>(
_ component: Component
) -> Component where Component: Machine {
component
}
}
@_functionBuilder struct EventBuilder {
static func buildBlock<C0>(
_ c0: C0
) -> TupleDescriptor<(C0)> where C0: Machine {
TupleDescriptor((c0))
}
static func buildBlock<C0, C1>(
_ c0: C0,
_ c1: C1
) -> TupleDescriptor<(C0, C1)> where C0: Machine, C1: Machine {
TupleDescriptor((c0, c1))
}
static func buildBlock<C0, C1, C2>(
_ c0: C0,
_ c1: C1,
_ c2: C2
) -> TupleDescriptor<(C0, C1, C2)> where C0: Machine, C1: Machine, C2: Machine {
TupleDescriptor((c0, c1, c2))
}
static func buildBlock<C0, C1, C2, C3>(
_ c0: C0,
_ c1: C1,
_ c2: C2,
_ c3: C3
) -> TupleDescriptor<(C0, C1, C2, C3)> where C0: Machine, C1: Machine, C2: Machine, C3: Machine {
TupleDescriptor((c0, c1, c2, c3))
}
static func buildBlock<C0, C1, C2, C3, C4>(
_ c0: C0,
_ c1: C1,
_ c2: C2,
_ c3: C3,
_ c4: C4
) -> TupleDescriptor<(C0, C1, C2, C3, C4)> where C0: Machine, C1: Machine, C2: Machine, C3: Machine, C4: Machine {
TupleDescriptor((c0, c1, c2, c3, c4))
}
}
// MARK: - Components
struct Chart<Content>: Machine where Content: Machine {
var id: String
var chart: Content
init(id: String, @ChartBuilder content: () -> Content) {
self.id = id
self.chart = content()
}
}
struct TupleDescriptor<T>: Machine {
var value: T
var chart: Never { fatalError() }
init(_ value: T) {
self.value = value
}
}
struct ArrayDescriptor<T>: Machine {
var value: T
var chart: Never { fatalError() }
init(_ value: T) {
self.value = value
}
}
struct PossibleStates<S>: Machine {
var states: S
var chart: Never { fatalError() }
init(_ states: S) {
self.states = states
}
}
struct PossibleEvents<E>: Machine {
var events: E
var chart: Never { fatalError() }
init(_ events: E) {
self.events = events
}
}
struct Initial<State>: Machine {
var state: State
var chart: Never { fatalError() }
init(state: State) {
self.state = state
}
}
struct StateNodes<Content>: Machine where Content: Machine {
var chart: Content
init(@StateBuilder makeStateTransition: () -> Content) {
self.chart = makeStateTransition()
}
}
struct From<State, Content>: Machine where Content: Machine {
var state: State
var chart: Content
init(
state: State,
@TransitionBuilder makeTransition: () -> Content
) {
self.state = state
self.chart = makeTransition()
}
}
struct On<Content>: Machine where Content: Machine {
var chart: Content
init(@OnBuilder makeTarget: () -> Content) {
self.chart = makeTarget()
}
}
struct Event<E, Content>: Machine where Content: Machine {
var event: E
var chart: Content
init(_ event: E, @EventBuilder makeEvent: () -> Content) {
self.event = event
self.chart = makeEvent()
}
}
//struct Type<Content>: Machine where Content: Machine {
// var type: String
// var chart: Content
//
// init(_ type: String) {
// self.type = type
// }
//}
struct Target<State>: Machine {
var state: State
var chart: Never { fatalError() }
init(state: State) {
self.state = state
}
}
struct Action: Machine {
var perform: (() -> Void)? = nil
var handlers: [() -> Void]? = nil
var chart: Never { fatalError() }
init(perform: @escaping () -> Void) {
self.perform = perform
}
init(_ handlers: (() -> Void)...) {
self.handlers = handlers
}
}
struct Entry: Machine {
var action: () -> Void
var chart: Never { fatalError() }
init(action: @escaping () -> Void) {
self.action = action
}
}
struct Exit: Machine {
var action: () -> Void
var chart: Never { fatalError() }
init(action: @escaping () -> Void) {
self.action = action
}
func keyForWrapping(propertyNamed propertyName: String) -> String? {
nil
}
}
struct Guard: Machine {
var cond: () -> Bool
var chart: Never { fatalError() }
init(cond: @escaping () -> Bool) {
self.cond = cond
}
}
// MARK: - @ExtendedState property wrapper
@propertyWrapper struct ExtendedState<Value> {
class Storage {
var value: Value
init(initialValue: Value) { self.value = initialValue }
}
private var storage: Storage
var wrappedValue: Value {
get { self.storage.value }
nonmutating set { self.storage.value = newValue }
}
init(wrappedValue value: Value) {
self.storage = Storage(initialValue: value)
}
public var projectedValue: Self {
get { self }
set { self = newValue }
}
}
// MARK: - Protocols
protocol Machine {
associatedtype Body: Machine
var chart: Self.Body { get }
}
protocol StateMachine: Machine {
associatedtype States
associatedtype Events
associatedtype Context
}
extension Never: Machine {
typealias Body = Never
var chart: Never { fatalError() }
}
// MARK: - Machine Interpreter
//struct Interpreter<M> where M: StateMachine {
// enum InterpreterStatus {
// case notStarted
// case running
// case stopped
// }
//
// enum Errors: Error {
// case notInitialized
// }
//
// var machine: M
//
// /// Weather the service is initialized
// var initialized = false
// private var status = InterpreterStatus.notStarted
//
// var id: String
// var initialState: M.States
// var state: M.States
//
//// init(machine: M) {
//// self.machine = machine
////
////// let chart = machine.chart
////// self.id = chart.id
//////
////// self.initialState = chart.initialState as! M.States
////// self.state = chart.initialState as! M.States
//// }
//
//// func unwrap(machine: M) {
//// guard !(machine is Never) else { return }
////
//// if let chart = machine.chart as! Chart {
//// unwrap(machine: machine)
//// }
//// }
//
// mutating func start(initialState: M.States? = nil) {
// /// Do not restart the service
// guard status == .running else { return }
//
// self.initialized = true
// self.status = .running
// }
//
// mutating func stop() {
// self.initialized = false
// self.status = .stopped
// }
//
//// func onTransition() -> (_ state: M.State) -> Void {
////
//// }
//
// func send(_ events: M.Events...) throws -> M.States {
// guard status == .stopped else { return self.state }
//
// do {
// try self.batch(events)
// } catch {
// throw error
// }
//
// return self.state
// }
//
// private func batch(_ events: [M.Events]) throws {
// guard self.status == .running else {
// throw Errors.notInitialized
// }
// print(events)
// }
//}
//
////var machine = Interpreter(machine: LightMachine())
////machine.start()
//
////let state = try! machine.send(.timer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment