machine_handler_engine.bend

bendvy-ecs-core@0.1.0.0 · 90 lines · 0 definitions

1import Base
2import bendvy-ecs-core@0.1.0.0/system.bend as Sys
3import bendvy-ecs-core@0.1.0.0/machine.bend as M
4# One transition engine, independent of the operational state carrier.
5type PhaseResult<State:Type,Entry:Type> is Type:
6  Complete{entries:List<Entry>,world:State}
7  Failed{entries:List<Entry>,world:State,error:String}
8type Owners<Entry:Type> is Type:
9  Owners{exit:List<Entry>,transition:List<Entry>,enter:List<Entry>}
10type HandlerResult<State:Type,Entry:Type,Phase:Data> is Type:
11  Completed{owners:Owners<Entry>,world:State}
12  Stopped{owners:Owners<Entry>,world:State,phase:Phase,error:String}
13type Prepared<S:Data,K:Data,V:Data> is Data:
14  Idle{slot:M.Slot<S,K,V>}
15  Ready{slot:M.Slot<S,K,V>,transition:M.Transition<V>,skipSame:Bool}
16def prepend(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,head:Entry,tail:PhaseResult<State,Entry>) -> PhaseResult<State,Entry>:
17  match tail:
18    case Complete{entries,world}: Complete{head <> entries,world}
19    case Failed{entries,world,error}: Failed{head <> entries,world,error}
20
21def entry_outcome(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,entry:Entry,outcome:Sys.Outcome<State,String,Unit>,next:State -> Maybe<&2,String> -> PhaseResult<State,Entry>) -> PhaseResult<State,Entry>:
22  match outcome:
23    case Sys.Failed{world,error}:prepend(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,entry,next(world,Some{error}))
24    case Sys.Succeeded{world,_}:prepend(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,entry,next(world,None{}))
25def entry_result(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,observed:Entry & Sys.Outcome<State,String,Unit>,next:State -> Maybe<&2,String> -> PhaseResult<State,Entry>) -> PhaseResult<State,Entry>:
26  match observed:
27    case (entry,outcome):entry_outcome(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,entry,outcome,next)
28def run_phase(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,entries:List<&1,Entry>,world:State,+phase:Phase,+from:V,+to:V,error:Maybe<&2,String>) -> PhaseResult<State,Entry>:
29  match entries error:
30    case entries Some{error}: Failed{entries,world,error}
31    case [] None{}: Complete{[],world}
32    case entry <> rest None{}: entry_result(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,invoke(entry,world,phase,from,to),world => error => run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,rest,world,phase,from,to,error))
33
34def run_initial(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,entries:List<&1,Entry>,world:State,+to:V,error:Maybe<&2,String>) -> PhaseResult<State,Entry>:
35  match entries error:
36    case entries Some{error}: Failed{entries,world,error}
37    case [] None{}: Complete{[],world}
38    case entry <> rest None{}: entry_result(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,initial(entry,world,to),world => error => run_initial(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,rest,world,to,error))
39
40def choose(~S:Data,~K:Data,~V:Data,skip:Bool,+current:V,+value:V,previous:Maybe<&2,V>,+skipSame:Bool) -> Prepared<S,K,V>:
41  match skip:
42    case True{}: Idle{M.Present{current,M.NoPending{},previous,False{}}}
43    case False{}: Ready{M.Present{current,M.NoPending{},Some{current},False{}},M.Transition{current,value},skipSame}
44
45def prepare(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,slot:M.Slot<S,K,V>,captured:M.Snapshot<V>) -> Prepared<S,K,V>:
46  match slot captured:
47    case slot M.Unscheduled{}: Idle{M.clear_changed(~S,~K,~V,slot)}
48    case M.Missing{} M.Scheduled{_,_}: Idle{M.Missing{}}
49    case M.Present{+current,_,previous,_} M.Scheduled{+value,+skipSame}: choose(~S,~K,~V,Bool.and(skipSame,same(current,value)),current,value,previous,skipSame)
50
51def committed(~S:Data,~K:Data,~V:Data,slot:M.Slot<S,K,V>,from:V,to:V) -> M.Slot<S,K,V>:
52  match slot:
53    case M.Missing{}: M.Missing{}
54    case M.Present{_,pending,_,_}: M.Present{to,pending,Some{from},True{}}
55
56def requeued(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot<S,K,V>,~put:State -> M.Slot<S,K,V> -> State,~publish:State -> M.Transition<V> -> State,observed:State & M.Slot<S,K,V>,to:V,skipSame:Bool) -> State:
57  (world,slot)=observed
58  put(world,M.queue(~S,~K,~V,slot,to,skipSame))
59
60def published(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot<S,K,V>,~put:State -> M.Slot<S,K,V> -> State,~publish:State -> M.Transition<V> -> State,observed:State & M.Slot<S,K,V>,+from:V,+to:V) -> State:
61  (world,slot)=observed
62  publish(put(world,committed(~S,~K,~V,slot,from,to)),M.Transition{from,to})
63
64def after_enter(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,exit:List<&1,Entry>,transition:List<&1,Entry>,observed:PhaseResult<State,Entry>) -> HandlerResult<State,Entry,Phase>:
65  match observed:
66    case Complete{enter,world}: Completed{Owners{exit,transition,enter},world}
67    case Failed{enter,world,error}: Stopped{Owners{exit,transition,enter},world,enterPhase,error}
68
69def after_transition(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot<S,K,V>,~put:State -> M.Slot<S,K,V> -> State,~publish:State -> M.Transition<V> -> State,exit:List<&1,Entry>,enter:List<&1,Entry>,observed:PhaseResult<State,Entry>,+from:V,+to:V,skipSame:Bool) -> HandlerResult<State,Entry,Phase>:
70  match observed:
71    case Failed{transition,world,error}: Stopped{Owners{exit,transition,enter},requeued(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,take(world),to,skipSame),transitionPhase,error}
72    case Complete{transition,world}: after_enter(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,exit,transition,run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,enter,published(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,take(world),from,to),enterPhase,from,to,None{}))
73
74def after_exit(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot<S,K,V>,~put:State -> M.Slot<S,K,V> -> State,~publish:State -> M.Transition<V> -> State,transition:List<&1,Entry>,enter:List<&1,Entry>,observed:PhaseResult<State,Entry>,+from:V,+to:V,skipSame:Bool) -> HandlerResult<State,Entry,Phase>:
75  match observed:
76    case Failed{exit,world,error}: Stopped{Owners{exit,transition,enter},requeued(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,take(world),to,skipSame),exitPhase,error}
77    case Complete{exit,world}: after_transition(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,exit,enter,run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,transition,world,transitionPhase,from,to,None{}),from,to,skipSame)
78
79def prepared(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot<S,K,V>,~put:State -> M.Slot<S,K,V> -> State,~publish:State -> M.Transition<V> -> State,owners:Owners<Entry>,world:State,prepared:Prepared<S,K,V>) -> HandlerResult<State,Entry,Phase>:
80  match owners prepared:
81    case owners Idle{slot}: Completed{owners,put(world,slot)}
82    case Owners{exit,transition,enter} Ready{slot,M.Initial{to},_}:after_enter(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,exit,transition,run_initial(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,enter,put(world,slot),to,None{}))
83    case Owners{exit,transition,enter} Ready{slot,M.Transition{+from,+to},skipSame}: after_exit(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,transition,enter,run_phase(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,exit,put(world,slot),exitPhase,from,to,None{}),from,to,skipSame)
84
85def taken(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot<S,K,V>,~put:State -> M.Slot<S,K,V> -> State,~publish:State -> M.Transition<V> -> State,~same:V -> V -> Bool,owners:Owners<Entry>,observed:State & M.Slot<S,K,V>,captured:M.Snapshot<V>) -> HandlerResult<State,Entry,Phase>:
86  (world,slot)=observed
87  prepared(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,owners,world,prepare(~S,~K,~V,~same,slot,captured))
88
89def run(~S:Data,~State:Type,~Entry:Type,~Phase:Data,~V:Data,~invoke:Entry -> State -> Phase -> V -> V -> Entry & Sys.Outcome<State,String,Unit>,~initial:Entry -> State -> V -> Entry & Sys.Outcome<State,String,Unit>,~exitPhase:Phase,~transitionPhase:Phase,~enterPhase:Phase,~K:Data,~take:State -> State & M.Slot<S,K,V>,~put:State -> M.Slot<S,K,V> -> State,~publish:State -> M.Transition<V> -> State,~same:V -> V -> Bool,owners:Owners<Entry>,world:State,captured:M.Snapshot<V>) -> HandlerResult<State,Entry,Phase>:
90  taken(~S,~State,~Entry,~Phase,~V,~invoke,~initial,~exitPhase,~transitionPhase,~enterPhase,~K,~take,~put,~publish,~same,owners,take(world),captured)