execution_deferred_settings.bend

bendvy-ecs-core@0.1.0.3 · 162 lines · 43 definitions

1import Base
2import bendvy-ecs-core@0.1.0.3/dependency_plan.bend as Plan
3import bendvy-ecs-core@0.1.0.3/execution_deferred_plan.bend as Deferred
4
5type Explicit is Data:
6  Explicit{before:U32,condition:Maybe<&2,U32>}
7type Settings is Data:
8  Settings{automatic:Bool,finalApply:Bool,ignored:List<&2,Plan.Edge>,explicit:List<&2,Explicit>}
9type Automatic is Data:
10  Automatic{distance:Nat,id:U32}
11type Graph is Data:
12  Graph{nodes:List<&2,Plan.Node<String>>,edges:List<&2,Plan.Edge>,syncs:List<&2,U32>,automatic:List<&2,Automatic>}
13type Built is Data:
14  Built{plan:Plan.Build<String>,syncs:List<&2,U32>}
15type GraphResult is Data:
16  GraphReady{graph:Graph}
17  GraphRejected{reason:Plan.Invalid<String>}
18def defaults() -> Settings:Settings{True{},True{},[],[]}
19def member(+id:U32,ids:List<&2,U32>) -> Bool:
20  match ids:
21    case []:False{}
22    case other <> rest:Bool.or(U32.is_eq(id,other),member(id,rest))
23def edge_member(+before:U32,+after:U32,edges:List<&2,Plan.Edge>) -> Bool:
24  match edges:
25    case []:False{}
26    case Plan.Edge{a,b} <> rest:Bool.or(Bool.and(U32.is_eq(a,before),U32.is_eq(b,after)),edge_member(before,after,rest))
27def fresh_choice(used:Bool,candidate:U32,next:Maybe<&2,U32>) -> Maybe<&2,U32>:
28  match used:
29    case False{}:Some{candidate}
30    case True{}:next
31def fresh(fuel:Nat,+nodes:List<&2,Plan.Node<String>>,+candidate:U32) -> Maybe<&2,U32>:
32  match fuel:
33    case 0n:None{}
34    case 1n++rest:fresh_choice(Plan.has(~String,nodes,candidate),candidate,fresh(rest,nodes,U32.add(candidate,1)))
35def available(+nodes:List<&2,Plan.Node<String>>) -> Maybe<&2,U32>:
36  fresh(1n+List.length(&2,Plan.Node<String>,nodes),nodes,0)
37def explicit_target(explicit:Explicit) -> U32:
38  match explicit:
39    case Explicit{before,_}:before
40def targets(explicit:List<&2,Explicit>) -> List<&2,U32>:
41  match explicit:
42    case []:[]
43    case Explicit{before,_} <> rest:before <> targets(rest)
44def check_explicit_entry(known:Bool,duplicate:Bool,id:U32,condition:Maybe<&2,U32>,next:Maybe<&2,Plan.Invalid<String>>) -> Maybe<&2,Plan.Invalid<String>>:
45  match known duplicate condition:
46    case False{} _ _:Some{Plan.UnknownDependency{id}}
47    case True{} True{} _:Some{Plan.Duplicate{id}}
48    case True{} False{} Some{_}:Some{Plan.InvalidCondition{id}}
49    case True{} False{} None{}:next
50def check_explicit(explicit:List<&2,Explicit>,+nodes:List<&2,Plan.Node<String>>) -> Maybe<&2,Plan.Invalid<String>>:
51  match explicit:
52    case []:None{}
53    case Explicit{+before,condition} <> +rest:check_explicit_entry(Plan.has(~String,nodes,before),member(before,targets(rest)),before,condition,check_explicit(rest,nodes))
54def check_ignored_entry(present:Bool,id:U32,next:Maybe<&2,Plan.Invalid<String>>) -> Maybe<&2,Plan.Invalid<String>>:
55  match present:
56    case True{}:next
57    case False{}:Some{Plan.UnknownDependency{id}}
58def check_ignored(ignored:List<&2,Plan.Edge>,+edges:List<&2,Plan.Edge>) -> Maybe<&2,Plan.Invalid<String>>:
59  match ignored:
60    case []:None{}
61    case Plan.Edge{before,+after} <> rest:check_ignored_entry(edge_member(before,after,edges),after,check_ignored(rest,edges))
62def redirect_edge(+target:U32,sync:U32,edge:Plan.Edge) -> Plan.Edge:
63  match edge:
64    case Plan.Edge{before,+after}:Plan.Edge{before,Bool.pick(U32,U32.is_eq(after,target),sync,after)}
65def redirect(edges:List<&2,Plan.Edge>,+target:U32,+sync:U32) -> List<&2,Plan.Edge>:
66  match edges:
67    case []:[Plan.Edge{sync,target}]
68    case edge <> rest:redirect_edge(target,sync,edge) <> redirect(rest,target,sync)
69def add_sync(+id:U32,+target:U32,graph:Graph) -> Graph:
70  match graph:
71    case Graph{nodes,edges,syncs,automatic}:Graph{Plan.Node{id,[]} <> nodes,redirect(edges,target,id),id <> syncs,automatic}
72def add_explicit_choice(choice:Maybe<&2,U32>,target:U32,graph:Graph) -> GraphResult:
73  match choice:
74    case None{}:GraphRejected{Plan.Cycle{}}
75    case Some{id}:GraphReady{add_sync(id,target,graph)}
76def add_explicit(target:U32,+graph:Graph) -> GraphResult:
77  match graph:
78    case Graph{+nodes,edges,syncs,automatic}:add_explicit_choice(available(nodes),target,Graph{nodes,edges,syncs,automatic})
79def explicit_step(target:U32,result:GraphResult) -> GraphResult:
80  match result:
81    case GraphRejected{reason}:GraphRejected{reason}
82    case GraphReady{graph}:add_explicit(target,graph)
83def explicit_graph(explicit:List<&2,Explicit>,graph:Graph) -> GraphResult:
84  match explicit:
85    case []:GraphReady{graph}
86    case Explicit{before,_} <> rest:explicit_step(before,explicit_graph(rest,graph))
87def metadata_node(+syncs:List<&2,U32>,deferred:List<&2,U32>,node:Plan.Node<String>) -> Deferred.Node:
88  match node:
89    case Plan.Node{+id,_}:Deferred.Node{id,member(id,deferred),member(id,syncs),False{},member(id,syncs)}
90def metadata(nodes:List<&2,Plan.Node<String>>,+syncs:List<&2,U32>,+deferred:List<&2,U32>) -> List<&2,Deferred.Node>:
91  match nodes:
92    case []:[]
93    case node <> rest:metadata_node(syncs,deferred,node) <> metadata(rest,syncs,deferred)
94def deferred_edges(edges:List<&2,Plan.Edge>,+ignored:List<&2,Plan.Edge>) -> List<&2,Deferred.Edge>:
95  match edges:
96    case []:[]
97    case Plan.Edge{+before,+after} <> rest:Deferred.Edge{before,after,edge_member(before,after,ignored)} <> deferred_edges(rest,ignored)
98def automatic_choice(same:Bool,id:U32,rest:Maybe<&2,U32>) -> Maybe<&2,U32>:
99  match same:
100    case True{}:Some{id}
101    case False{}:rest
102def automatic_id(automatic:List<&2,Automatic>,+distance:Nat) -> Maybe<&2,U32>:
103  match automatic:
104    case []:None{}
105    case Automatic{other,id} <> rest:automatic_choice(Nat.is_eq(other,distance),id,automatic_id(rest,distance))
106def keep_edge(same:Bool,edge:Plan.Edge,rest:List<&2,Plan.Edge>) -> List<&2,Plan.Edge>:
107  match same:
108    case True{}:rest
109    case False{}:edge <> rest
110def remove_edge(edges:List<&2,Plan.Edge>,+before:U32,+after:U32) -> List<&2,Plan.Edge>:
111  match edges:
112    case []:[]
113    case Plan.Edge{+a,+b} <> rest:keep_edge(Bool.and(U32.is_eq(a,before),U32.is_eq(b,after)),Plan.Edge{a,b},remove_edge(rest,before,after))
114def connect(+before:U32,+after:U32,+sync:U32,graph:Graph) -> Graph:
115  match graph:
116    case Graph{nodes,edges,syncs,automatic}:Graph{nodes,Plan.Edge{before,sync} <> Plan.Edge{sync,after} <> remove_edge(edges,before,after),syncs,automatic}
117def allocated(before:U32,after:U32,distance:Nat,choice:Maybe<&2,U32>,graph:Graph) -> GraphResult:
118  match choice graph:
119    case None{} _:GraphRejected{Plan.Cycle{}}
120    case Some{+id} Graph{nodes,edges,syncs,automatic}:GraphReady{connect(before,after,id,Graph{Plan.Node{id,[]} <> nodes,edges,id <> syncs,Automatic{distance,id} <> automatic})}
121def reuse_automatic(before:U32,after:U32,distance:Nat,choice:Maybe<&2,U32>,+graph:Graph) -> GraphResult:
122  match choice graph:
123    case Some{id} graph:GraphReady{connect(before,after,id,graph)}
124    case None{} Graph{+nodes,edges,syncs,automatic}:allocated(before,after,distance,available(nodes),Graph{nodes,edges,syncs,automatic})
125def boundary_step(boundary:Deferred.Boundary,+graph:Graph) -> GraphResult:
126  match boundary graph:
127    case Deferred.Boundary{before,after,_,Some{id}} graph:GraphReady{connect(before,after,id,graph)}
128    case Deferred.Boundary{before,after,+distance,None{}} Graph{nodes,edges,syncs,+automatic}:reuse_automatic(before,after,distance,automatic_id(automatic,distance),Graph{nodes,edges,syncs,automatic})
129def boundary_result(boundary:Deferred.Boundary,result:GraphResult) -> GraphResult:
130  match result:
131    case GraphRejected{reason}:GraphRejected{reason}
132    case GraphReady{graph}:boundary_step(boundary,graph)
133def materialize(boundaries:List<&2,Deferred.Boundary>,graph:Graph) -> GraphResult:
134  match boundaries:
135    case []:GraphReady{graph}
136    case boundary <> rest:boundary_result(boundary,materialize(rest,graph))
137def synchronized(automatic:Bool,ignored:List<&2,Plan.Edge>,deferred:List<&2,U32>,+syncs:List<&2,U32>,automaticIds:List<&2,Automatic>,plan:Plan.Build<String>) -> GraphResult:
138  match plan:
139    case Plan.Rejected{reason}:GraphRejected{reason}
140    case Plan.Planned{+nodes,+edges}:materialize(Deferred.plan(automatic,metadata(nodes,syncs,deferred),deferred_edges(edges,ignored)),Graph{nodes,edges,syncs,automaticIds})
141def explicit_ready(automatic:Bool,ignored:List<&2,Plan.Edge>,deferred:List<&2,U32>,result:GraphResult) -> GraphResult:
142  match result:
143    case GraphRejected{reason}:GraphRejected{reason}
144    case GraphReady{Graph{+nodes,+edges,syncs,automaticIds}}:synchronized(automatic,ignored,deferred,syncs,automaticIds,Plan.sort(~String,List.length(&2,Plan.Node<String>,nodes),nodes,edges))
145def compiled(result:GraphResult) -> Built:
146  match result:
147    case GraphRejected{reason}:Built{Plan.Rejected{reason},[]}
148    case GraphReady{Graph{+nodes,edges,syncs,_}}:Built{Plan.sort(~String,List.length(&2,Plan.Node<String>,nodes),nodes,edges),syncs}
149def validated(invalid:Maybe<&2,Plan.Invalid<String>>,automatic:Bool,ignored:List<&2,Plan.Edge>,explicit:List<&2,Explicit>,deferred:List<&2,U32>,nodes:List<&2,Plan.Node<String>>,edges:List<&2,Plan.Edge>) -> Built:
150  match invalid:
151    case Some{reason}:Built{Plan.Rejected{reason},[]}
152    case None{}:compiled(explicit_ready(automatic,ignored,deferred,explicit_graph(explicit,Graph{nodes,edges,[],[]})))
153
154# Pinned Bevy ad678262 auto_insert_apply_deferred.rs: synchronize the graph,
155# before dependent systems' conditions run. Synthetic nodes are library-only;
156# their fresh IDs are checked against every actual and generated graph node.
157# Conditioned explicit barriers are rejected rather than treated as guaranteed
158# synchronization; this API exposes unconditional explicit-before placements.
159def compile(settings:Settings,deferred:List<&2,U32>,plan:Plan.Build<String>) -> Built:
160  match settings plan:
161    case _ Plan.Rejected{reason}:Built{Plan.Rejected{reason},[]}
162    case Settings{automatic,_,+ignored,+explicit} Plan.Planned{+nodes,+edges}:validated(Plan.first_error(~String,check_explicit(explicit,nodes),check_ignored(ignored,edges)),automatic,ignored,explicit,deferred,nodes,edges)