1 import Base 2 import ./clock_state.bend as Clock 3 import entity_key.bend as Key 4 import entity_allocator.bend as Alloc 5 import ./world.bend as W 6 import ./decode_data.bend as D 7 import ./deferred_command.bend as Deferred 8 9 # Basic detached Data only; runtime checkpoint state is intentionally not encoded. 10 type Entity is Data: 11 Entity{key:Key.Key,components:List<&2,D.Field>} 12 type Snapshot is Data: 13 Snapshot{version:U32,nextEntity:U32,entities:List<&2,Entity>,resources:List<&2,D.Field>} 14 15 # Ordinary save either exports detached Data or refuses pending structural work. 16 # Refusal returns the same World separately; it does not execute or discard work. 17 type Outcome is Data: 18 Saved{snapshot:A} 19 RefusedPending{} 20 21 def pending_ready(~World:Type,pending:List>) -> List> & Bool: 22 match pending: 23 case []:([],True{}) 24 case command <> rest:(command <> rest,False{}) 25 def ready_joined(~S:Data,~C:Type,~R:Type,~E:Data,namespace:U32,allocator:Alloc.Allocator,store:C,resource:R,events:List<&2,E>,registrations:List<&2,W.RegistrationMeta>,nextSystemId:U32,clock:Clock.State,result:List>> & Bool) -> W.World & Bool: 26 match result: 27 case (pending,ready):(W.World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},ready) 28 # Internal constant-time structural admission, before any trusted projection. 29 def ready(~S:Data,~C:Type,~R:Type,~E:Data,world:W.World) -> W.World & Bool: 30 match world: 31 case W.World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:ready_joined(~S,~C,~R,~E,namespace,allocator,store,resource,events,registrations,nextSystemId,clock,pending_ready(~W.World,pending)) 32 33 # Internal experimental accessor: exact actual allocator, no inferred live count. 34 # Rebuild the SAME owner with every field returned unchanged. 35 def allocator(~S:Data,~C:Type,~R:Type,~E:Data,world:W.World) -> W.World & U32: 36 match world: 37 case W.World{+namespace,Alloc.Allocator{+nextId,+high,slots,+capacity,+depth,+free,+order},store,resource,+events,pending,+registrations,+nextSystemId,+clock}: 38 (W.World{namespace,Alloc.Allocator{nextId,high,slots,capacity,depth,free,order},store,resource,events,pending,registrations,nextSystemId,clock},nextId) 39 40 # Closed schema providers must return the actual store/resource owners. Their 41 # projections, transient omission and name bindings are trusted author inputs. 42 # This is NOT the still-missing public constructed-descriptor validation gate. 43 def finish(~S:Data,~C:Type,~R:Type,~E:Data,nextEntity:U32,entities:List<&2,Entity>,observed:W.World & List<&2,D.Field>) -> W.World & Snapshot: 44 match observed: 45 case (world,fields):(world,Snapshot{1,nextEntity,entities,fields}) 46 def with_entities(~S:Data,~C:Type,~R:Type,~E:Data,~resources:R -> R & List<&2,D.Field>,nextEntity:U32,observed:W.World & List<&2,Entity>) -> W.World & Snapshot: 47 match observed: 48 case (world,entities):finish(~S,~C,~R,~E,nextEntity,entities,W.observe_resource(~S,~C,~R,~E,~List<&2,D.Field>,~resources,world)) 49 def with_handles(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,nextEntity:U32,observed:W.World & List<&2,W.Handle>) -> W.World & Snapshot: 50 match observed: 51 case (world,handles):with_entities(~S,~C,~R,~E,~resources,nextEntity,W.with_store(~S,~C,~R,~E,~List<&2,Entity>,rows(handles),world)) 52 def with_allocator(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,observed:W.World & U32) -> W.World & Snapshot: 53 match observed: 54 case (world,nextEntity):with_handles(~S,~C,~R,~E,~rows,~resources,nextEntity,W.handles(~S,~C,~R,~E,world)) 55 def saved(~S:Data,~C:Type,~R:Type,~E:Data,result:W.World & Snapshot) -> W.World & Outcome: 56 match result: 57 case (world,snapshot):(world,Saved{snapshot}) 58 def basic_ready(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,result:W.World & Bool) -> W.World & Outcome: 59 match result: 60 case (world,False{}):(world,RefusedPending{}) 61 case (world,True{}):saved(~S,~C,~R,~E,with_allocator(~S,~C,~R,~E,~rows,~resources,allocator(~S,~C,~R,~E,world))) 62 def basic(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,world:W.World) -> W.World & Outcome: 63 basic_ready(~S,~C,~R,~E,~rows,~resources,ready(~S,~C,~R,~E,world))