1 import Base 2 import ./world.bend as W 3 import ./entity_allocator.bend as A 4 import ./entity_key.bend as Key 5 import ./clock_state.bend as Clock 6 import ./execution_lifecycle_notices.bend as Notice 7 import ./deferred_command.bend as Deferred 8 9 type Allocator is Data: 10 Allocator{next:U32,high:U32,capacity:U32,depth:Nat,slots:List<&2,A.Slot>,free:List<&2,U32>,order:List<&2,Key.Key>} 11 type Lifecycle<-S:Data> is Data: 12 Lifecycle{namespace:U32,channels:List<&2,Notice.Channel>,nextReader:U32,active:List<&2,Notice.Active>} 13 type Metadata<-S:Data> is Data: 14 Metadata{namespace:U32,allocator:Allocator,clock:Clock.State,lifecycle:Lifecycle} 15 16 def right_slots(left:Array,leftValues:List<&2,A.Slot>,result:Array & List<&2,A.Slot>) -> Array & List<&2,A.Slot>: 17 match result: 18 case (right,rightValues):(ANode{left,right},List.append(&2,A.Slot,leftValues,rightValues)) 19 def joined_slots(leftResult:Array & List<&2,A.Slot>,rightResult:Array & List<&2,A.Slot>) -> Array & List<&2,A.Slot>: 20 match leftResult: 21 case (left,leftValues):right_slots(left,leftValues,rightResult) 22 def slots(values:Array) -> Array & List<&2,A.Slot>: 23 match values: 24 case ALeaf{+value}:(ALeaf{value},[value]) 25 case ANode{left,right}:joined_slots(slots(left),slots(right)) 26 def allocator_slots(+next:U32,+high:U32,+capacity:U32,+depth:Nat,+free:List<&2,U32>,+order:List<&2,Key.Key>,result:Array & List<&2,A.Slot>) -> A.Allocator & Allocator: 27 match result: 28 case (actual,values):(A.Allocator{next,high,actual,capacity,depth,free,order},Allocator{next,high,capacity,depth,values,free,order}) 29 def allocator(actual:A.Allocator) -> A.Allocator & Allocator: 30 match actual: 31 case A.Allocator{next,high,actual,capacity,depth,free,order}:allocator_slots(next,high,capacity,depth,free,order,slots(actual)) 32 def lifecycle(~S:Data,actual:Notice.Journal) -> Notice.Journal & Lifecycle: 33 match actual: 34 case Notice.Journal{+namespace,+channels,+nextReader,+active}:(Notice.Journal{namespace,channels,nextReader,active},Lifecycle{namespace,channels,nextReader,active}) 35 def captured_lifecycle(~S:Data,~C:Type,~R:Type,~E:Data,+namespace:U32,actual:A.Allocator,metadata:Allocator,store:C,resource:R,events:List<&2,E>,pending:List>>,registrations:List<&2,W.RegistrationMeta>,nextSystemId:U32,+clock:Clock.State,result:Notice.Journal & Lifecycle) -> W.World & Metadata: 36 match result: 37 case (journal,lifecycle):(W.World{namespace,actual,store,resource,events,pending,registrations,nextSystemId,clock,journal},Metadata{namespace,metadata,clock,lifecycle}) 38 def captured_allocator(~S:Data,~C:Type,~R:Type,~E:Data,namespace:U32,store:C,resource:R,events:List<&2,E>,pending:List>>,registrations:List<&2,W.RegistrationMeta>,nextSystemId:U32,clock:Clock.State,journal:Notice.Journal,result:A.Allocator & Allocator) -> W.World & Metadata: 39 match result: 40 case (actual,metadata):captured_lifecycle(~S,~C,~R,~E,namespace,actual,metadata,store,resource,events,pending,registrations,nextSystemId,clock,lifecycle(~S,journal)) 41 # Detached metadata accompanies field export. It is not a restored namespace or 42 # a checkpoint of live reader/system owners; restore must remap those identities. 43 def capture(~S:Data,~C:Type,~R:Type,~E:Data,world:W.World) -> W.World & Metadata: 44 match world: 45 case W.World{namespace,actual,store,resource,events,pending,registrations,nextSystemId,clock,journal}:captured_allocator(~S,~C,~R,~E,namespace,store,resource,events,pending,registrations,nextSystemId,clock,journal,allocator(actual))