snapshot_data.bend
bendvy-ecs-core@0.1.0.0 · 63 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.0/clock_state.bend as Clock
3import entity_key.bend as Key
4import entity_allocator.bend as Alloc
5import bendvy-ecs-core@0.1.0.0/world.bend as W
6import bendvy-ecs-core@0.1.0.0/decode_data.bend as D
7import bendvy-ecs-core@0.1.0.0/deferred_command.bend as Deferred
8
9# Basic detached Data only; runtime checkpoint state is intentionally not encoded.
10type Entity is Data:
11 Entity{key:Key.Key,components:List<&2,D.Field>}
12type 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.
17type Outcome<A:Data> is Data:
18 Saved{snapshot:A}
19 RefusedPending{}
20
21def pending_ready(~World:Type,pending:List<Deferred.Command<World>>) -> List<Deferred.Command<World>> & Bool:
22 match pending:
23 case []:([],True{})
24 case command <> rest:(command <> rest,False{})
25def 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<Deferred.Command<W.World<S,C,R,E>>> & Bool) -> W.World<S,C,R,E> & 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.
29def ready(~S:Data,~C:Type,~R:Type,~E:Data,world:W.World<S,C,R,E>) -> W.World<S,C,R,E> & 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<S,C,R,E>,pending))
32
33# Internal experimental accessor: exact actual allocator, no inferred live count.
34# Rebuild the SAME owner with every field returned unchanged.
35def allocator(~S:Data,~C:Type,~R:Type,~E:Data,world:W.World<S,C,R,E>) -> W.World<S,C,R,E> & 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.
43def finish(~S:Data,~C:Type,~R:Type,~E:Data,nextEntity:U32,entities:List<&2,Entity>,observed:W.World<S,C,R,E> & List<&2,D.Field>) -> W.World<S,C,R,E> & Snapshot:
44 match observed:
45 case (world,fields):(world,Snapshot{1,nextEntity,entities,fields})
46def with_entities(~S:Data,~C:Type,~R:Type,~E:Data,~resources:R -> R & List<&2,D.Field>,nextEntity:U32,observed:W.World<S,C,R,E> & List<&2,Entity>) -> W.World<S,C,R,E> & 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))
49def with_handles(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle<S>> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,nextEntity:U32,observed:W.World<S,C,R,E> & List<&2,W.Handle<S>>) -> W.World<S,C,R,E> & 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))
52def with_allocator(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle<S>> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,observed:W.World<S,C,R,E> & U32) -> W.World<S,C,R,E> & Snapshot:
53 match observed:
54 case (world,nextEntity):with_handles(~S,~C,~R,~E,~rows,~resources,nextEntity,W.handles(~S,~C,~R,~E,world))
55def saved(~S:Data,~C:Type,~R:Type,~E:Data,result:W.World<S,C,R,E> & Snapshot) -> W.World<S,C,R,E> & Outcome<Snapshot>:
56 match result:
57 case (world,snapshot):(world,Saved{snapshot})
58def basic_ready(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle<S>> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,result:W.World<S,C,R,E> & Bool) -> W.World<S,C,R,E> & Outcome<Snapshot>:
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)))
62def basic(~S:Data,~C:Type,~R:Type,~E:Data,~rows:List<&2,W.Handle<S>> -> C -> C & List<&2,Entity>,~resources:R -> R & List<&2,D.Field>,world:W.World<S,C,R,E>) -> W.World<S,C,R,E> & Outcome<Snapshot>:
63 basic_ready(~S,~C,~R,~E,~rows,~resources,ready(~S,~C,~R,~E,world))