1use crate::Simulation;
2use std::time::Duration;
3
4pub trait Execute {
6 fn execute(self, sim: &mut Simulation);
9}
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12enum EndCondition {
13 Time(Duration),
14 EmptyQueue,
15 Steps(usize),
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct Executor {
23 end_condition: EndCondition,
24}
25
26impl Executor {
27 #[must_use]
29 pub fn unbound() -> Self {
30 Self {
31 end_condition: EndCondition::EmptyQueue,
32 }
33 }
34
35 #[must_use]
38 pub fn timed(time: Duration) -> Self {
39 Self {
40 end_condition: EndCondition::Time(time),
41 }
42 }
43
44 #[must_use]
46 pub fn steps(steps: usize) -> Self {
47 Self {
48 end_condition: EndCondition::Steps(steps),
49 }
50 }
51
52 #[must_use]
54 pub fn side_effect<F>(self, func: F) -> ExecutorWithSideEffect<F>
55 where
56 F: Fn(&Simulation),
57 {
58 ExecutorWithSideEffect {
59 end_condition: self.end_condition,
60 side_effect: func,
61 }
62 }
63}
64
65impl Execute for Executor {
66 fn execute(self, sim: &mut Simulation) {
67 run_with(sim, self.end_condition, |_| {});
68 }
69}
70
71pub struct ExecutorWithSideEffect<F>
72where
73 F: Fn(&Simulation),
74{
75 end_condition: EndCondition,
76 side_effect: F,
77}
78
79impl<F> Execute for ExecutorWithSideEffect<F>
80where
81 F: Fn(&Simulation),
82{
83 fn execute(self, sim: &mut Simulation) {
84 run_with(sim, self.end_condition, self.side_effect);
85 }
86}
87
88fn run_with<F>(sim: &mut Simulation, end_condition: EndCondition, side_effect: F)
89where
90 F: Fn(&Simulation),
91{
92 let step_fn = |sim: &mut Simulation| {
93 let result = sim.step();
94 if result {
95 side_effect(sim);
96 }
97 result
98 };
99 match end_condition {
100 EndCondition::Time(time) => execute_until(sim, time, step_fn),
101 EndCondition::EmptyQueue => execute_until_empty(sim, step_fn),
102 EndCondition::Steps(steps) => execute_steps(sim, steps, step_fn),
103 }
104}
105
106fn execute_until_empty<F>(sim: &mut Simulation, step: F)
107where
108 F: Fn(&mut Simulation) -> bool,
109{
110 while step(sim) {}
111}
112
113fn execute_until<F>(sim: &mut Simulation, time: Duration, step: F)
114where
115 F: Fn(&mut Simulation) -> bool,
116{
117 while sim.scheduler.peek().map_or(false, |e| e.time() <= time) {
118 step(sim);
119 }
120}
121
122fn execute_steps<F>(sim: &mut Simulation, steps: usize, step: F)
123where
124 F: Fn(&mut Simulation) -> bool,
125{
126 for _ in 0..steps {
127 if !step(sim) {
128 break;
129 }
130 }
131}
132
133#[cfg(test)]
134mod test {
135 use super::*;
136 use crate::Component;
137
138 struct TestComponent {
139 counter: crate::Key<usize>,
140 }
141
142 #[derive(Debug)]
143 struct TestEvent;
144
145 impl Component for TestComponent {
146 type Event = TestEvent;
147
148 fn process_event(
149 &self,
150 self_id: crate::ComponentId<Self::Event>,
151 _event: &Self::Event,
152 scheduler: &mut crate::Scheduler,
153 state: &mut crate::State,
154 ) {
155 let counter = state.get_mut(self.counter).unwrap();
156 *counter += 1;
157 if *counter < 10 {
158 scheduler.schedule(Duration::from_secs(2), self_id, TestEvent);
159 }
160 }
161 }
162
163 #[test]
164 fn test_create_executor() {
165 assert_eq!(
166 Executor::unbound(),
167 Executor {
168 end_condition: EndCondition::EmptyQueue
169 }
170 );
171 assert_eq!(
172 Executor::timed(Duration::default()),
173 Executor {
174 end_condition: EndCondition::Time(Duration::default())
175 }
176 );
177 assert_eq!(
178 Executor::steps(7),
179 Executor {
180 end_condition: EndCondition::Steps(7)
181 }
182 );
183 assert_eq!(&format!("{:?}", TestEvent), "TestEvent");
185 }
186
187 #[test]
188 fn test_steps() {
189 let mut sim = Simulation::default();
190 let counter_key = sim.state.insert(0_usize);
191 let component = sim.add_component(TestComponent {
192 counter: counter_key,
193 });
194 sim.schedule(Duration::default(), component, TestEvent);
195 Executor::steps(10).execute(&mut sim);
196 assert_eq!(sim.state.get(counter_key), Some(&10));
197 }
198
199 #[test]
200 fn test_steps_stops_before() {
201 let mut sim = Simulation::default();
202 let counter_key = sim.state.insert(0_usize);
203 let component = sim.add_component(TestComponent {
204 counter: counter_key,
205 });
206 sim.schedule(Duration::default(), component, TestEvent);
207 Executor::steps(100).execute(&mut sim);
209 assert_eq!(sim.state.get(counter_key), Some(&10));
210 }
211
212 #[test]
213 fn test_timed() {
214 let mut sim = Simulation::default();
215 let counter_key = sim.state.insert(0_usize);
216 let component = sim.add_component(TestComponent {
217 counter: counter_key,
218 });
219 sim.schedule(Duration::default(), component, TestEvent);
220 Executor::timed(Duration::from_secs(6)).execute(&mut sim);
221 assert_eq!(sim.state.get(counter_key), Some(&4));
222 assert_eq!(sim.scheduler.clock().time(), Duration::from_secs(6));
223 }
224
225 #[test]
226 fn test_timed_clock_stops_early() {
227 let mut sim = Simulation::default();
228 let counter_key = sim.state.insert(0_usize);
229 let component = sim.add_component(TestComponent {
230 counter: counter_key,
231 });
232 sim.schedule(Duration::default(), component, TestEvent);
233 Executor::timed(Duration::from_secs(5)).execute(&mut sim);
234 assert_eq!(sim.state.get(counter_key), Some(&3));
235 assert_eq!(sim.scheduler.clock().time(), Duration::from_secs(4));
236 }
237}