execution_save_world.bend

bendvy-ecs-core@0.1.0.3 · 58 lines · 12 definitions

1import Base
2import bendvy-ecs-core@0.1.0.3/execution_save_plan.bend as Plan
3import bendvy-ecs-core@0.1.0.3/execution_save_traversal.bend as Traverse
4import bendvy-ecs-core@0.1.0.3/execution_save_rows.bend as Rows
5import bendvy-ecs-core@0.1.0.3/execution_save_data.bend as Saved
6import bendvy-ecs-core@0.1.0.3/execution_save_recipe.bend as Recipe
7import bendvy-ecs-core@0.1.0.3/execution_save_metadata.bend as Metadata
8import bendvy-ecs-core@0.1.0.3/execution_save_gate.bend as Gate
9import bendvy-ecs-core@0.1.0.3/execution_composer_layout.bend as Layout
10import bendvy-ecs-core@0.1.0.3/snapshot_data.bend as Legacy
11import bendvy-ecs-core@0.1.0.3/world.bend as W
12import bendvy-ecs-core@0.1.0.3/entity_allocator.bend as Alloc
13import bendvy-ecs-core@0.1.0.3/clock_state.bend as Clock
14import bendvy-ecs-core@0.1.0.3/execution_lifecycle_notices.bend as Notice
15import bendvy-ecs-core@0.1.0.3/deferred_command.bend as Deferred
16
17type Remainder<-S:Data,-C:Type,-R:Type,-E:Data> is Type:
18  Remainder{namespace:U32,allocator:Alloc.Allocator,events:List<&2,E>,pending:List<Deferred.Command<W.World<S,C,R,E>>>,registrations:List<&2,W.RegistrationMeta>,nextSystemId:U32,clock:Clock.State,journal:Notice.Journal<S>}
19def assembled(~S:Data,~C:Type,~R:Type,~E:Data,rest:Remainder<S,C,R,E>,columns:C,resources:R) -> W.World<S,C,R,E>:
20  match rest:
21    case Remainder{namespace,allocator,events,pending,registrations,nextSystemId,clock,journal}:W.World{namespace,allocator,columns,resources,events,pending,registrations,nextSystemId,clock,journal}
22def exported(~S:Data,~cp:Plan.Plan,~rp:Plan.Plan,~E:Data,componentRecipes:Plan.Recipes(~S,cp),columns:Layout.columns(~S,Plan.layout(cp)),rest:Remainder<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E>,metadata:Metadata.Metadata<S>,rows:List<&2,Saved.Entity>,result:Plan.Recipes(~S,rp) & (Layout.resources(~S,Plan.layout(rp)) & Saved.Fields)) -> Plan.Schema<S,cp,rp> & (W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Gate.Outcome<Saved.Snapshot<S>,Recipe.Refusal>):
23  match result:
24    case (resourceRecipes,(resources,Saved.Fields{_,Some{error}})):(Plan.Schema{componentRecipes,resourceRecipes},(assembled(~S,~Layout.columns(~S,Plan.layout(cp)),~Layout.resources(~S,Plan.layout(rp)),~E,rest,columns,resources),Gate.Refused{error}))
25    case (resourceRecipes,(resources,Saved.Fields{fields,None{}})):(Plan.Schema{componentRecipes,resourceRecipes},(assembled(~S,~Layout.columns(~S,Plan.layout(cp)),~Layout.resources(~S,Plan.layout(rp)),~E,rest,columns,resources),Gate.Saved{Saved.Snapshot{2,metadata,rows,fields}}))
26def rows_returned(~S:Data,~cp:Plan.Plan,~rp:Plan.Plan,~E:Data,resourceRecipes:Plan.Recipes(~S,rp),resources:Layout.resources(~S,Plan.layout(rp)),rest:Remainder<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E>,metadata:Metadata.Metadata<S>,result:Plan.Recipes(~S,cp) & (Layout.columns(~S,Plan.layout(cp)) & (List<&2,Saved.Entity> & Maybe<&2,Recipe.Refusal>))) -> Plan.Schema<S,cp,rp> & (W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Gate.Outcome<Saved.Snapshot<S>,Recipe.Refusal>):
27  match result:
28    case (componentRecipes,(columns,(_,Some{error}))):(Plan.Schema{componentRecipes,resourceRecipes},(assembled(~S,~Layout.columns(~S,Plan.layout(cp)),~Layout.resources(~S,Plan.layout(rp)),~E,rest,columns,resources),Gate.Refused{error}))
29    case (componentRecipes,(columns,(rows,None{}))):exported(~S,~cp,~rp,~E,componentRecipes,columns,rest,metadata,rows,Traverse.resources(~S,rp)(resourceRecipes,resources))
30def handles_returned(~S:Data,~cp:Plan.Plan,~rp:Plan.Plan,~E:Data,schema:Plan.Schema<S,cp,rp>,metadata:Metadata.Metadata<S>,result:W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & List<&2,W.Handle<S>>) -> Plan.Schema<S,cp,rp> & (W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Gate.Outcome<Saved.Snapshot<S>,Recipe.Refusal>):
31  match schema result:
32    case Plan.Schema{componentRecipes,resourceRecipes}, (W.World{namespace,allocator,columns,resources,events,pending,registrations,nextSystemId,clock,journal},handles):rows_returned(~S,~cp,~rp,~E,resourceRecipes,resources,Remainder{namespace,allocator,events,pending,registrations,nextSystemId,clock,journal},metadata,Rows.rows(~S,~cp,handles,componentRecipes,columns))
33def metadata_returned(~S:Data,~cp:Plan.Plan,~rp:Plan.Plan,~E:Data,schema:Plan.Schema<S,cp,rp>,result:W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Metadata.Metadata<S>) -> Plan.Schema<S,cp,rp> & (W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Gate.Outcome<Saved.Snapshot<S>,Recipe.Refusal>):
34  match result:
35    case (world,metadata):handles_returned(~S,~cp,~rp,~E,schema,metadata,W.handles(~S,~Layout.columns(~S,Plan.layout(cp)),~Layout.resources(~S,Plan.layout(rp)),~E,world))
36def unique(valid:Bool) -> Maybe<&2,Recipe.Refusal>:
37  match valid:
38    case True{}:None{}
39    case False{}:Some{Recipe.DescriptorMismatch{"unique layout keys","duplicate key"}}
40def eligibility_result(result:Maybe<&2,String>,valid:Bool) -> Maybe<&2,Recipe.Refusal>:
41  match result:
42    case Some{key}:Some{Recipe.PlainUnserializable{key}}
43    case None{}:unique(valid)
44def eligibility(~cp:Plan.Plan,~rp:Plan.Plan) -> Maybe<&2,Recipe.Refusal>:
45  eligibility_result(Plan.first(Plan.ineligible(cp),Plan.ineligible(rp)),Bool.and(Layout.unique(Plan.layout(cp)),Layout.unique(Plan.layout(rp))))
46def eligible(~S:Data,~cp:Plan.Plan,~rp:Plan.Plan,~E:Data,schema:Plan.Schema<S,cp,rp>,world:W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E>,error:Maybe<&2,Recipe.Refusal>) -> Plan.Schema<S,cp,rp> & (W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Gate.Outcome<Saved.Snapshot<S>,Recipe.Refusal>):
47  match error:
48    case Some{error}:(schema,(world,Gate.Refused{error}))
49    case None{}:metadata_returned(~S,~cp,~rp,~E,schema,Metadata.capture(~S,~Layout.columns(~S,Plan.layout(cp)),~Layout.resources(~S,Plan.layout(rp)),~E,world))
50def ready(~S:Data,~cp:Plan.Plan,~rp:Plan.Plan,~E:Data,schema:Plan.Schema<S,cp,rp>,result:W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Bool) -> Plan.Schema<S,cp,rp> & (W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Gate.Outcome<Saved.Snapshot<S>,Recipe.Refusal>):
51  match result:
52    case (world,False{}):(schema,(world,Gate.RefusedPending{}))
53    case (world,True{}):eligible(~S,~cp,~rp,~E,schema,world,eligibility(~cp,~rp))
54# Internal World phase. Ordinary applications must first inventory their actual
55# command owners with execution-save-gate; legacy World.pending is additional.
56# Eligibility of the entire closed schema precedes metadata and field projection.
57def save(~S:Data,~cp:Plan.Plan,~rp:Plan.Plan,~E:Data,schema:Plan.Schema<S,cp,rp>,world:W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E>) -> Plan.Schema<S,cp,rp> & (W.World<S,Layout.columns(~S,Plan.layout(cp)),Layout.resources(~S,Plan.layout(rp)),E> & Gate.Outcome<Saved.Snapshot<S>,Recipe.Refusal>):
58  ready(~S,~cp,~rp,~E,schema,Legacy.ready(~S,~Layout.columns(~S,Plan.layout(cp)),~Layout.resources(~S,Plan.layout(rp)),~E,world))