Created
November 25, 2019 05:26
-
-
Save ordazgustavo/54f9d67f037a966bf7fe2f8715906a76 to your computer and use it in GitHub Desktop.
MUI
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
// 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