schedule.bend
bendvy-ecs-core@0.1.0.4 · 173 lines · 32 definitions
1import Base
2import bendvy-ecs-core@0.1.0.4/world.bend as W
3import bendvy-ecs-core@0.1.0.4/system.bend as Sys
4
5
6
7
8
9
10type Step is Data:
11 System{id: U32,condition: U32}
12 Phase{name: String}
13 Barrier{}
14
15
16type Observation is Data:
17 Entered{name: String}
18 Ran{id: U32}
19 Skipped{id: U32}
20 Applied{}
21
22
23type Schedule<S: Data,C: Type,R: Type,E: Data,H: Type> is Type:
24 Schedule{namespace: U32,name: String,steps: List<&2,Step>,owners: H}
25
26
27type Build<S: Data,C: Type,R: Type,E: Data,H: Type> is Type:
28 Built{schedule: Schedule<S,C,R,E,H>}
29 Invalid{owners: H}
30
31
32
33
34type RunResult<S: Data,C: Type,R: Type,E: Data,H: Type,Error: Data> is Type:
35 Finished{schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>,observations: List<&2,Observation>}
36 Failed{schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>,error: Error,observations: List<&2,Observation>}
37 Rejected{schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>}
38
39def contains(ids: List<&2,U32>,+id: U32) -> Bool:
40 match ids:
41 case []: False{}
42 case +head <> rest: Bool.or(U32.is_eq(head,id),contains(rest,id))
43
44def valid(steps: List<&2,Step>,+catalog: List<&2,U32>,+seen: List<&2,U32>) -> Bool:
45 match steps:
46 case []: True{}
47 case Phase{_} <> rest: valid(rest,catalog,seen)
48 case Barrier{} <> rest: valid(rest,catalog,seen)
49 case System{+id,_} <> rest: Bool.and(contains(catalog,id),Bool.and(Bool.not(contains(seen,id)),valid(rest,catalog,id <> seen)))
50
51def build_checked(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,allowed: Bool,+namespace: U32,+name: String,+steps: List<&2,Step>,owners: H) -> Build<S,C,R,E,H>:
52 match allowed:
53 case False{}: Invalid{owners}
54 case True{}: Built{Schedule{namespace,name,steps,owners}}
55
56
57
58
59def build(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,+namespace: U32,+name: String,+steps: List<&2,Step>,catalog: List<&2,U32>,owners: H) -> Build<S,C,R,E,H>:
60 build_checked(~S,~C,~R,~E,~H,valid(steps,catalog,[]),namespace,name,steps,owners)
61
62
63
64def after_outcome(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,next: H -> W.World<S,C,R,E> -> List<&2,Observation> -> RunResult<S,C,R,E,H,Error>,outcome: Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,owners: H,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>,+id: U32) -> RunResult<S,C,R,E,H,Error>:
65 match outcome:
66 case Sys.Failed{world,error}: Failed{Schedule{namespace,name,all,owners},world,error,List.append(&2,Observation,observations,[Ran{id}])}
67 case Sys.Succeeded{world,_}: next(owners,world,List.append(&2,Observation,observations,[Ran{id}]))
68
69def after_dispatch(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,next: H -> W.World<S,C,R,E> -> List<&2,Observation> -> RunResult<S,C,R,E,H,Error>,result: H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>,+id: U32) -> RunResult<S,C,R,E,H,Error>:
70 (owners,outcome) = result
71 after_outcome(~S,~C,~R,~E,~H,~Error,next,outcome,owners,namespace,name,all,observations,id)
72
73def conditioned(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,next: H -> W.World<S,C,R,E> -> List<&2,Observation> -> RunResult<S,C,R,E,H,Error>,allowed: Bool,owners: H,world: W.World<S,C,R,E>,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>,+id: U32) -> RunResult<S,C,R,E,H,Error>:
74 match allowed:
75 case False{}: next(owners,world,List.append(&2,Observation,observations,[Skipped{id}]))
76 case True{}: after_dispatch(~S,~C,~R,~E,~H,~Error,next,dispatch(owners,world,id),namespace,name,all,observations,id)
77
78def after_condition(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,next: H -> W.World<S,C,R,E> -> List<&2,Observation> -> RunResult<S,C,R,E,H,Error>,checked: W.World<S,C,R,E> & Bool,owners: H,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>,+id: U32) -> RunResult<S,C,R,E,H,Error>:
79 (world,allowed) = checked
80 conditioned(~S,~C,~R,~E,~H,~Error,~dispatch,next,allowed,owners,world,namespace,name,all,observations,id)
81
82def after_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,next: H -> W.World<S,C,R,E> -> List<&2,Observation> -> RunResult<S,C,R,E,H,Error>,returned: H & W.World<S,C,R,E>,observations: List<&2,Observation>) -> RunResult<S,C,R,E,H,Error>:
83 (owners,world) = returned
84 next(owners,world,observations)
85
86def default_barrier(~S:Data,~C:Type,~R:Type,~E:Data,~H:Type,owners:H,world:W.World<S,C,R,E>) -> H & W.World<S,C,R,E>:
87 (owners,W.barrier(~S,~C,~R,~E,world))
88def execute_with_barrier(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,~barrier:H -> W.World<S,C,R,E> -> H & W.World<S,C,R,E>,steps: List<&2,Step>,owners: H,world: W.World<S,C,R,E>,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>) -> RunResult<S,C,R,E,H,Error>:
89 match steps:
90 case []: Finished{Schedule{namespace,name,all,owners},world,observations}
91 case Phase{phase} <> rest: execute_with_barrier(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~barrier,rest,owners,world,namespace,name,all,List.append(&2,Observation,observations,[Entered{phase}]))
92 case Barrier{} <> rest: after_skip(~S,~C,~R,~E,~H,~Error,h => w => obs => execute_with_barrier(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~barrier,rest,h,w,namespace,name,all,obs),barrier(owners,world),List.append(&2,Observation,observations,[Applied{}]))
93 case System{+id,slot} <> rest: after_condition(~S,~C,~R,~E,~H,~Error,~dispatch,h => w => obs => execute_with_barrier(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~barrier,rest,h,w,namespace,name,all,obs),condition(world,slot),owners,namespace,name,all,observations,id)
94
95def execute(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,steps: List<&2,Step>,owners: H,world: W.World<S,C,R,E>,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>) -> RunResult<S,C,R,E,H,Error>:
96 execute_with_barrier(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~default_barrier(~S,~C,~R,~E,~H),steps,owners,world,namespace,name,all,observations)
97
98def run_checked(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,allowed: Bool,schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>) -> RunResult<S,C,R,E,H,Error>:
99 match allowed schedule:
100 case False{} schedule: Rejected{schedule,world}
101 case True{} Schedule{+namespace,+name,+steps,owners}: execute(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,steps,owners,world,namespace,name,steps,[])
102
103
104def run_actual(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>,+actual: U32) -> RunResult<S,C,R,E,H,Error>:
105 match schedule:
106 case Schedule{+namespace,+name,+steps,owners}: run_checked(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,U32.is_eq(namespace,actual),Schedule{namespace,name,steps,owners},world)
107
108def run_namespace(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,schedule: Schedule<S,C,R,E,H>,named: W.World<S,C,R,E> & U32) -> RunResult<S,C,R,E,H,Error>:
109 (world,+actual) = named
110 run_actual(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,schedule,world,actual)
111
112
113
114
115
116
117
118def run(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>) -> RunResult<S,C,R,E,H,Error>:
119 run_namespace(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,schedule,W.namespace(~S,~C,~R,~E,world))
120
121
122def conditioned_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~skip: H -> W.World<S,C,R,E> -> U32 -> H & W.World<S,C,R,E>,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,next: H -> W.World<S,C,R,E> -> List<&2,Observation> -> RunResult<S,C,R,E,H,Error>,allowed: Bool,owners: H,world: W.World<S,C,R,E>,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>,+id: U32) -> RunResult<S,C,R,E,H,Error>:
123 match allowed:
124 case False{}: after_skip(~S,~C,~R,~E,~H,~Error,next,skip(owners,world,id),List.append(&2,Observation,observations,[Skipped{id}]))
125 case True{}: after_dispatch(~S,~C,~R,~E,~H,~Error,next,dispatch(owners,world,id),namespace,name,all,observations,id)
126
127def after_condition_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~skip: H -> W.World<S,C,R,E> -> U32 -> H & W.World<S,C,R,E>,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,next: H -> W.World<S,C,R,E> -> List<&2,Observation> -> RunResult<S,C,R,E,H,Error>,checked: W.World<S,C,R,E> & Bool,owners: H,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>,+id: U32) -> RunResult<S,C,R,E,H,Error>:
128 (world,allowed) = checked
129 conditioned_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,next,allowed,owners,world,namespace,name,all,observations,id)
130
131def execute_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~skip: H -> W.World<S,C,R,E> -> U32 -> H & W.World<S,C,R,E>,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,steps: List<&2,Step>,owners: H,world: W.World<S,C,R,E>,+namespace: U32,+name: String,+all: List<&2,Step>,+observations: List<&2,Observation>) -> RunResult<S,C,R,E,H,Error>:
132 match steps:
133 case []: Finished{Schedule{namespace,name,all,owners},world,observations}
134 case Phase{phase} <> rest: execute_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,~condition,rest,owners,world,namespace,name,all,List.append(&2,Observation,observations,[Entered{phase}]))
135 case Barrier{} <> rest: execute_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,~condition,rest,owners,W.barrier(~S,~C,~R,~E,world),namespace,name,all,List.append(&2,Observation,observations,[Applied{}]))
136 case System{+id,slot} <> rest: after_condition_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,h => w => obs => execute_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,~condition,rest,h,w,namespace,name,all,obs),condition(world,slot),owners,namespace,name,all,observations,id)
137
138def run_checked_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~skip: H -> W.World<S,C,R,E> -> U32 -> H & W.World<S,C,R,E>,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,allowed: Bool,schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>) -> RunResult<S,C,R,E,H,Error>:
139 match allowed schedule:
140 case False{} schedule: Rejected{schedule,world}
141 case True{} Schedule{+namespace,+name,+steps,owners}: execute_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,~condition,steps,owners,world,namespace,name,steps,[])
142
143
144def run_actual_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~skip: H -> W.World<S,C,R,E> -> U32 -> H & W.World<S,C,R,E>,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>,+actual: U32) -> RunResult<S,C,R,E,H,Error>:
145 match schedule:
146 case Schedule{+namespace,+name,+steps,owners}: run_checked_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,~condition,U32.is_eq(namespace,actual),Schedule{namespace,name,steps,owners},world)
147
148def run_namespace_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~skip: H -> W.World<S,C,R,E> -> U32 -> H & W.World<S,C,R,E>,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,schedule: Schedule<S,C,R,E,H>,named: W.World<S,C,R,E> & U32) -> RunResult<S,C,R,E,H,Error>:
149 (world,+actual) = named
150 run_actual_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,~condition,schedule,world,actual)
151
152
153
154
155def run_with_skip(~S: Data,~C: Type,~R: Type,~E: Data,~H: Type,~Error: Data,~skip: H -> W.World<S,C,R,E> -> U32 -> H & W.World<S,C,R,E>,~dispatch: H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition: W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,schedule: Schedule<S,C,R,E,H>,world: W.World<S,C,R,E>) -> RunResult<S,C,R,E,H,Error>:
156 run_namespace_skip(~S,~C,~R,~E,~H,~Error,~skip,~dispatch,~condition,schedule,W.namespace(~S,~C,~R,~E,world))
157
158def run_barrier_checked(~S:Data,~C:Type,~R:Type,~E:Data,~H:Type,~Error:Data,~dispatch:H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition:W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,~barrier:H -> W.World<S,C,R,E> -> H & W.World<S,C,R,E>,allowed:Bool,schedule:Schedule<S,C,R,E,H>,world:W.World<S,C,R,E>) -> RunResult<S,C,R,E,H,Error>:
159 match allowed schedule:
160 case False{} schedule:Rejected{schedule,world}
161 case True{} Schedule{+namespace,+name,+steps,owners}:execute_with_barrier(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~barrier,steps,owners,world,namespace,name,steps,[])
162def run_barrier_actual(~S:Data,~C:Type,~R:Type,~E:Data,~H:Type,~Error:Data,~dispatch:H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition:W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,~barrier:H -> W.World<S,C,R,E> -> H & W.World<S,C,R,E>,schedule:Schedule<S,C,R,E,H>,world:W.World<S,C,R,E>,+actual:U32) -> RunResult<S,C,R,E,H,Error>:
163 match schedule:
164 case Schedule{+namespace,+name,+steps,owners}:run_barrier_checked(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~barrier,U32.is_eq(namespace,actual),Schedule{namespace,name,steps,owners},world)
165def run_barrier_named(~S:Data,~C:Type,~R:Type,~E:Data,~H:Type,~Error:Data,~dispatch:H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition:W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,~barrier:H -> W.World<S,C,R,E> -> H & W.World<S,C,R,E>,schedule:Schedule<S,C,R,E,H>,named:W.World<S,C,R,E> & U32) -> RunResult<S,C,R,E,H,Error>:
166 match named:
167 case (world,actual):run_barrier_actual(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~barrier,schedule,world,actual)
168
169
170
171
172def run_with_barrier(~S:Data,~C:Type,~R:Type,~E:Data,~H:Type,~Error:Data,~dispatch:H -> W.World<S,C,R,E> -> U32 -> H & Sys.Outcome<W.World<S,C,R,E>,Error,Unit>,~condition:W.World<S,C,R,E> -> U32 -> W.World<S,C,R,E> & Bool,~barrier:H -> W.World<S,C,R,E> -> H & W.World<S,C,R,E>,schedule:Schedule<S,C,R,E,H>,world:W.World<S,C,R,E>) -> RunResult<S,C,R,E,H,Error>:
173 run_barrier_named(~S,~C,~R,~E,~H,~Error,~dispatch,~condition,~barrier,schedule,W.namespace(~S,~C,~R,~E,world))