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
155
156
157
158
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)