1 import Base 2 import ./machine.bend as M 3 import ./machine_queue.bend as Queue 4 import ./execution_machine_stream.bend as Stream 5 import ./change_tick.bend as Tick 6 7 # The Cell is framework storage. Ordinary bodies receive declaration-derived ops. 8 type Cell<-S:Data,-K:Data,-V:Data> is Type: 9 Cell{slot:M.Slot,stream:Stream.Store,revision:Nat,stamp:Maybe<&2,Tick.Tick>,nextStamp:Maybe<&2,Tick.Tick>,sequence:Nat,initialPending:Bool,namespace:Maybe<&2,U32>,intent:Intent} 10 type Intent<-V:Data> is Data: 11 Idle{} 12 Initial{value:V} 13 Transition{from:V,to:V,runExitEnter:Bool} 14 type View<-S:Data,-K:Data,-V:Data> is Data: 15 View{current:M.CurrentView,next:M.NextView,revision:Nat,stamp:Maybe<&2,Tick.Tick>,nextStamp:Maybe<&2,Tick.Tick>,intent:Intent} 16 def empty(~S:Data,~K:Data,~V:Data) -> Cell: 17 Cell{M.Missing{},Stream.empty(~V),0n,None{},None{},0n,False{},None{},Idle{}} 18 def projected(-S:Data,-K:Data,-V:Data,cell:Cell) -> Cell & View: 19 match cell: 20 case Cell{+slot,stream,+revision,+stamp,+nextStamp,sequence,initialPending,namespace,+intent}:(Cell{slot,stream,revision,stamp,nextStamp,sequence,initialPending,namespace,intent},View{M.current_view_generic(S,K,V,slot),M.next_view_generic(S,K,V,slot),revision,stamp,nextStamp,intent}) 21 def queue_generic(-S:Data,-K:Data,-V:Data,same:V -> V -> Bool,cell:Cell,request:M.QueueInput) -> Cell: 22 match cell request: 23 case Cell{slot,stream,revision,stamp,nextStamp,sequence,initialPending,namespace,intent} M.Set{value,skipSame}:Cell{Queue.queue_generic(S,K,V,same,slot,value,skipSame),stream,revision,stamp,nextStamp,sequence,initialPending,namespace,intent} 24 case Cell{slot,stream,revision,stamp,nextStamp,sequence,initialPending,namespace,intent} M.Reset{}:Cell{M.reset_generic(S,K,V,slot),stream,revision,stamp,nextStamp,sequence,initialPending,namespace,intent} 25 # Next setters and pending consumption have their own actual write stamp: 26 # https://github.com/bevyengine/bevy/blob/ad678262ce53b5d142fe49ee5e08caff6f00ab60/crates/bevy_state/src/state/resources.rs#L197-L234 27 def queue(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,cell:Cell,request:M.QueueInput) -> Cell: 28 queue_generic(S,K,V,same,cell,request) 29 30 def request_stamped_generic(-S:Data,-K:Data,-V:Data,tick:Tick.Tick,cell:Cell) -> Cell & Unit: 31 match cell: 32 case Cell{M.Missing{},stream,revision,stamp,nextStamp,sequence,initialPending,namespace,intent}:(Cell{M.Missing{},stream,revision,stamp,nextStamp,sequence,initialPending,namespace,intent},Unit{}) 33 case Cell{slot,stream,revision,stamp,_,sequence,initialPending,namespace,intent}:(Cell{slot,stream,revision,stamp,Some{tick},sequence,initialPending,namespace,intent},Unit{}) 34 def request_stamped(~S:Data,~K:Data,~V:Data,tick:Tick.Tick,cell:Cell) -> Cell & Unit: 35 request_stamped_generic(S,K,V,tick,cell) 36 37 def queued_at_generic(-S:Data,-K:Data,-V:Data,same:V -> V -> Bool,request:M.QueueInput,tick:Tick.Tick,cell:Cell) -> Cell & Unit: 38 request_stamped_generic(S,K,V,tick,queue_generic(S,K,V,same,cell,request)) 39 def queued_at(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,request:M.QueueInput,tick:Tick.Tick,cell:Cell) -> Cell & Unit: 40 queued_at_generic(S,K,V,same,request,tick,cell) 41 42 def initialized(~S:Data,~K:Data,~V:Data,+value:V,+tick:Tick.Tick,stream:Stream.Store,+sequence:Nat,namespace:Maybe<&2,U32>) -> Cell: 43 Cell{M.Present{value,M.NoPending{},None{},True{}},Stream.publish(~V,stream,1n+sequence,M.Initial{value}),1n,Some{tick},Some{tick},1n+sequence,True{},namespace,Initial{value}} 44 def initialize(~S:Data,~K:Data,~V:Data,cell:Cell,value:V,tick:Tick.Tick) -> Cell: 45 match cell: 46 case Cell{M.Missing{},stream,_,_,_,sequence,_,namespace,_}:initialized(~S,~K,~V,value,tick,stream,sequence,namespace) 47 case cell:cell 48 def next_revision(same:Bool,revision:Nat) -> Nat: 49 match same: 50 case True{}:revision 51 case False{}:1n+revision 52 def next_stamp(same:Bool,stamp:Maybe<&2,Tick.Tick>,tick:Tick.Tick) -> Maybe<&2,Tick.Tick>: 53 match same: 54 case True{}:stamp 55 case False{}:Some{tick} 56 # Bevy commits State and emits StateTransitionEvent before phase schedules: 57 # https://github.com/bevyengine/bevy/blob/ad678262ce53b5d142fe49ee5e08caff6f00ab60/crates/bevy_state/src/state/transitions.rs#L138-L205 58 # Comparator equality retains actual Current; exited/Previous/event use the 59 # requested value, including when equal values have different representations. 60 def retained(~V:Data,equal:Bool,from:V,to:V) -> V: 61 match equal: 62 case True{}:from 63 case False{}:to 64 def exited(~V:Data,equal:Bool,from:V,to:V) -> V: 65 match equal: 66 case True{}:to 67 case False{}:from 68 def committed(~S:Data,~K:Data,~V:Data,+from:V,+to:V,skipSame:Bool,stream:Stream.Store,revision:Nat,stamp:Maybe<&2,Tick.Tick>,+sequence:Nat,+tick:Tick.Tick,+equal:Bool,namespace:Maybe<&2,U32>) -> Cell: 69 Cell{M.Present{retained(~V,equal,from,to),M.NoPending{},Some{exited(~V,equal,from,to)},Bool.not(equal)},Stream.publish(~V,stream,1n+sequence,M.Transition{exited(~V,equal,from,to),to}),next_revision(equal,revision),next_stamp(equal,stamp,tick),Some{tick},1n+sequence,False{},namespace,Transition{exited(~V,equal,from,to),to,Bool.or(Bool.not(skipSame),Bool.not(equal))}} 70 def apply(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,cell:Cell,tick:Tick.Tick) -> Cell: 71 match cell: 72 case Cell{M.Present{+current,M.Queued{+value,skipSame},_,_},stream,revision,stamp,nextStamp,sequence,_,namespace,_}:committed(~S,~K,~V,current,value,skipSame,stream,revision,stamp,sequence,tick,same(current,value),namespace) 73 case Cell{slot,stream,revision,stamp,nextStamp,sequence,True{},namespace,intent}:Cell{slot,stream,revision,stamp,nextStamp,sequence,False{},namespace,intent} 74 case Cell{slot,stream,revision,stamp,nextStamp,sequence,False{},namespace,_}:Cell{M.clear_changed(~S,~K,~V,slot),stream,revision,stamp,nextStamp,sequence,False{},namespace,Idle{}} 75 def run_exit(-V:Data,intent:Intent) -> Bool: 76 match intent: 77 case Transition{_,_,allowed}:allowed 78 case _:False{} 79 def run_transition(-V:Data,intent:Intent) -> Bool: 80 match intent: 81 case Transition{_,_,_}:True{} 82 case _:False{} 83 def run_enter(-V:Data,intent:Intent) -> Bool: 84 match intent: 85 case Initial{_}:True{} 86 case Transition{_,_,allowed}:allowed 87 case _:False{} 88 def matches(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,value:V,view:View) -> Bool: 89 match view: 90 case View{current,_,_,_,_,_}:M.is_current(~S,~K,~V,~same,current,value) 91 92 def bind(~S:Data,~K:Data,~V:Data,namespace:U32,cell:Cell) -> Cell: 93 match cell: 94 case Cell{slot,stream,revision,stamp,nextStamp,sequence,initialPending,None{},intent}:Cell{slot,stream,revision,stamp,nextStamp,sequence,initialPending,Some{namespace},intent} 95 case cell:cell 96 def maintain(~S:Data,~K:Data,~V:Data,tick:Tick.Tick,cell:Cell) -> Cell: 97 match cell: 98 case Cell{slot,stream,revision,stamp,nextStamp,+sequence,initialPending,namespace,intent}:Cell{slot,Stream.maintain(~V,sequence,tick,stream),revision,stamp,nextStamp,sequence,initialPending,namespace,intent}