snapshot_data.bend

bendvy-ecs-core@0.1.0.3 · 64 lines · 14 definitions

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