1 import Base 2 import ./change_tick.bend as Tick 3 import entity_key.bend as Key 4 import world.bend as W 5 import component.bend as C 6 import column.bend as Col 7 import lifecycle.bend as L 8 import bundle_install.bend as F 9 10 type Entry is Type: 11 Entry{handle:W.Handle,owner:Maybe<&1,Owner>} 12 type Recovery is Type: 13 Recovery{previous:Entry,stamp:L.Stamp} 14 def undone(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~C:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~project:C -> C & V,+handle:W.Handle,+stamp:L.Stamp,observed:W.World & C.Swap) -> F.Restore,Entry,Recovery>: 15 match observed: 16 case (world,C.Swapped{incoming}): F.Restored{C.restore_stamp(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,handle,stamp,world),Entry{handle,incoming}} 17 case (world,C.SwapRejected{old}): F.Pending{world,Recovery{Entry{handle,old},stamp},W.CapacityExceeded{}} 18 def undo_present(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~C:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~project:C -> C & V,+handle:W.Handle,+id:U32,stamp:L.Stamp,world:W.World,observed:Maybe<&1,C> & Bool) -> F.Restore,Entry,Recovery>: 19 (previous,present)=observed 20 undone(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,handle,stamp,C.swap_world(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,id,previous,present,Tick.zero(),world)) 21 def undo_checked(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~C:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~project:C -> C & V,+handle:W.Handle,+id:U32,stamp:L.Stamp,previous:Maybe<&1,C>,observed:W.World & Bool) -> F.Restore,Entry,Recovery>: 22 match observed: 23 case (world,False{}): F.Pending{world,Recovery{Entry{handle,previous},stamp},W.MissingEntity{}} 24 case (world,True{}): undo_present(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,handle,id,stamp,world,C.owner_present(~C,previous)) 25 def undo(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~C:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~project:C -> C & V,recovery:Recovery,world:W.World) -> F.Restore,Entry,Recovery>: 26 match recovery: 27 case Recovery{Entry{W.Handle{+ns,+id},previous},stamp}: undo_checked(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,W.Handle{ns,id},Key.index(id),stamp,previous,W.valid(~S,~Store,~R,~E,world,W.Handle{ns,id})) 28 def replaced(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~C:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~project:C -> C & V,+handle:W.Handle,+stamp:L.Stamp,result:C.Replacement,C>) -> F.Attempt,Entry,Recovery>: 29 match result: 30 case C.ReplaceRejected{world,incoming,error}: F.Refused{world,Entry{handle,incoming},error} 31 case C.Replaced{world,previous}: F.Installed{world,w => undo(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,Recovery{Entry{handle,previous},stamp},w)} 32 def stamped(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~C:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~project:C -> C & V,+family:C.Family,+handle:W.Handle,incoming:Maybe<&1,C>,observed:W.World & L.Stamp) -> F.Attempt,Entry,Recovery>: 33 (world,stamp)=observed 34 replaced(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,handle,stamp,C.replace(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,family,world,handle,incoming)) 35 def install(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~C:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column,~put:Rest -> Col.Column -> Store,~project:C -> C & V,+family:C.Family,world:W.World,entry:Entry) -> F.Attempt,Entry,Recovery>: 36 match entry: 37 case Entry{+handle,incoming}: stamped(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,family,handle,incoming,C.lifecycle(~S,~Store,~R,~E,~Rest,~C,~V,~Token,~take,~put,~project,family,world,handle))