1 import Base 2 import ./deferred_command.bend as Deferred 3 import ./trace_facts.bend as TraceFacts 4 import ./machine.bend as M 5 import ./transaction.bend as Tx 6 7 # Bevy NextState::set_if_different preserves an existing forced same target. 8 # Equality is the same closed erased V comparator used by apply/conditions. 9 def forced_pending(~V:Data,same:Bool,prior:V,value:V) -> M.Pending: 10 match same: 11 case True{}:M.Queued{prior,False{}} 12 case False{}:M.Queued{value,True{}} 13 def conditional_pending(~V:Data,~same:V -> V -> Bool,pending:M.Pending,+value:V) -> M.Pending: 14 match pending: 15 case M.Queued{+prior,False{}}:forced_pending(~V,same(prior,value),prior,value) 16 case _:M.Queued{value,True{}} 17 def conditional(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,slot:M.Slot,value:V) -> M.Slot: 18 match slot: 19 case M.Missing{}:M.Missing{} 20 case M.Present{current,pending,previous,changed}:M.Present{current,conditional_pending(~V,~same,pending,value),previous,changed} 21 def queue(~S:Data,~K:Data,~V:Data,~same:V -> V -> Bool,slot:M.Slot,value:V,skipSame:Bool) -> M.Slot: 22 match skipSame: 23 case False{}:M.queue(~S,~K,~V,slot,value,False{}) 24 case True{}:conditional(~S,~K,~V,~same,slot,value) 25 def write_taken(~S:Data,~K:Data,~V:Data,~W:Type,~E:Data,~put:W -> M.Slot -> W,~same:V -> V -> Bool,pair:W & M.Slot,undo:List<&1,(W -> W)>,commands:List<&1,Deferred.Command>,events:List<&2,E>,trace:TraceFacts.State,value:V,skipSame:Bool) -> Tx.Tx: 26 match pair: 27 case (world,+old):Tx.Tx{put(world,queue(~S,~K,~V,~same,old,value,skipSame)),(world => put(world,old)) <> undo,commands,events,trace} 28 def write(~S:Data,~K:Data,~V:Data,~W:Type,~E:Data,~take:W -> W & M.Slot,~put:W -> M.Slot -> W,~same:V -> V -> Bool,tx:Tx.Tx,value:V,skipSame:Bool) -> Tx.Tx: 29 match tx: 30 case Tx.Tx{world,undo,commands,events,trace}:write_taken(~S,~K,~V,~W,~E,~put,~same,take(world),undo,commands,events,trace,value,skipSame) 31 def next(~S:Data,~K:Data,~V:Data,~W:Type,~E:Data,~take:W -> W & M.Slot,~put:W -> M.Slot -> W,~same:V -> V -> Bool,tx:Tx.Tx,request:M.QueueInput) -> Tx.Tx: 32 match request: 33 case M.Set{value,skipSame}:write(~S,~K,~V,~W,~E,~take,~put,~same,tx,value,skipSame) 34 case M.Reset{}:M.reset_tx(~S,~K,~V,~W,~E,~take,~put,tx) 35 def declared_record(~W:Type,~E:Data,enabled:Bool,name:String,tx:Tx.Tx) -> Tx.Tx: 36 match enabled: 37 case False{}:tx 38 case True{}:Tx.record(~W,~E,tx,TraceFacts.Fact{TraceFacts.NextStateValue{},name,TraceFacts.StageOperation{},None{},TraceFacts.OpaqueValue{},TraceFacts.OpaqueValue{},TraceFacts.Attempted{}}) 39 def declared_named(~S:Data,~K:Data,~V:Data,~W:Type,~E:Data,~take:W -> W & M.Slot,~put:W -> M.Slot -> W,~same:V -> V -> Bool,name:String,request:M.QueueInput,checked:Tx.Tx & Bool) -> Tx.Tx: 40 match checked: 41 case (tx,enabled):declared_record(~W,~E,enabled,name,next(~S,~K,~V,~W,~E,~take,~put,~same,tx,request)) 42 def next_declared(~S:Data,~K:Data,~V:Data,~W:Type,~E:Data,~take:W -> W & M.Slot,~put:W -> M.Slot -> W,~same:V -> V -> Bool,family:M.Family,tx:Tx.Tx,request:M.QueueInput) -> Tx.Tx: 43 match family: 44 case M.Family{name}:declared_named(~S,~K,~V,~W,~E,~take,~put,~same,name,request,Tx.trace_enabled(~W,~E,tx))