maplibre/schedule.rs
1use std::collections::HashMap;
2
3use downcast_rs::{impl_downcast, Downcast};
4use thiserror::Error;
5
6use crate::{
7 context::MapContext,
8 define_label,
9 tcs::system::{stage::SystemStage, IntoSystemContainer, SystemError},
10};
11
12pub struct NopStage;
13
14impl Stage for NopStage {
15 fn run(&mut self, _context: &mut MapContext) -> StageResult {
16 Ok(())
17 }
18}
19
20#[macro_export]
21macro_rules! multi_stage {
22 ($multi_stage:ident, $($stage:ident: $stage_ty:ty),*) => {
23 pub struct $multi_stage {
24 $($stage: $stage_ty),*
25 }
26
27 impl Stage for $multi_stage {
28 fn run(&mut self, context: &mut $crate::context::MapContext) {
29 $(self.$stage.run(context);)*
30 }
31 }
32
33 impl Default for $multi_stage {
34 fn default() -> Self {
35 $multi_stage {
36 $($stage: <$stage_ty>::default()),*
37 }
38 }
39 }
40 };
41}
42
43pub struct MultiStage<const I: usize, S>
44where
45 S: Stage,
46{
47 stages: [S; I],
48}
49
50impl<const I: usize, S> MultiStage<I, S>
51where
52 S: Stage,
53{
54 pub fn new(stages: [S; I]) -> Self {
55 Self { stages }
56 }
57}
58
59impl<const I: usize, S> Stage for MultiStage<I, S>
60where
61 S: Stage,
62{
63 fn run(&mut self, context: &mut MapContext) -> StageResult {
64 for stage in self.stages.iter_mut() {
65 stage.run(context)?
66 }
67
68 Ok(())
69 }
70}
71
72define_label!(StageLabel);
73pub(crate) type BoxedStageLabel = Box<dyn StageLabel>;
74
75#[derive(Error, Debug)]
76pub enum StageError {
77 #[error("system errored")]
78 System(#[from] SystemError),
79}
80
81pub type StageResult = Result<(), StageError>;
82
83pub trait Stage: Downcast {
84 /// Runs the stage; this happens once per update.
85 /// Implementors must initialize all of their state before running the first time.
86 fn run(&mut self, context: &mut MapContext) -> StageResult;
87}
88
89impl_downcast!(Stage);
90
91/// A container of [`Stage`]s set to be run in a linear order.
92///
93/// Since `Schedule` implements the [`Stage`] trait, it can be inserted into another schedule.
94/// In this way, the properties of the child schedule can be set differently from the parent.
95/// For example, it can be set to run only once during app execution, while the parent schedule
96/// runs indefinitely.
97#[derive(Default)]
98pub struct Schedule {
99 stages: HashMap<BoxedStageLabel, Box<dyn Stage>>,
100 stage_order: Vec<BoxedStageLabel>,
101}
102
103impl Schedule {
104 /// Adds the given `stage` at the last position of the schedule.
105 ///
106 /// # Example
107 ///
108 /// ```
109 /// # use maplibre::schedule::{Schedule, NopStage};
110 /// #
111 /// # let mut schedule = Schedule::default();
112 /// schedule.add_stage("my_stage", NopStage);
113 /// ```
114 pub fn add_stage<S: Stage>(&mut self, label: impl StageLabel, stage: S) -> &mut Self {
115 let label: Box<dyn StageLabel> = Box::new(label);
116 self.stage_order.push(label.clone());
117 let prev = self.stages.insert(label.clone(), Box::new(stage));
118 assert!(prev.is_none(), "Stage already exists: {label:?}.");
119 self
120 }
121
122 pub fn remove_stage(&mut self, label: impl StageLabel) -> &mut Self {
123 let remove: Box<dyn StageLabel> = Box::new(label);
124 self.stages.remove(&remove).expect("stage not found");
125 self.stage_order.retain(|label| label != &remove);
126 self
127 }
128
129 /// Adds the given `stage` immediately after the `target` stage.
130 ///
131 /// # Example
132 ///
133 /// ```
134 /// # use maplibre::schedule::{Schedule, NopStage};
135 /// #
136 /// # let mut schedule = Schedule::default();
137 /// # schedule.add_stage("target_stage", NopStage);
138 /// schedule.add_stage_after("target_stage", "my_stage", NopStage);
139 /// ```
140 pub fn add_stage_after<S: Stage>(
141 &mut self,
142 target: impl StageLabel,
143 label: impl StageLabel,
144 stage: S,
145 ) -> &mut Self {
146 let label: Box<dyn StageLabel> = Box::new(label);
147 let target = &target as &dyn StageLabel;
148 let target_index = self
149 .stage_order
150 .iter()
151 .enumerate()
152 .find(|(_i, stage_label)| &***stage_label == target)
153 .map(|(i, _)| i)
154 .unwrap_or_else(|| panic!("Target stage does not exist: {target:?}."));
155
156 self.stage_order.insert(target_index + 1, label.clone());
157 let prev = self.stages.insert(label.clone(), Box::new(stage));
158 assert!(prev.is_none(), "Stage already exists: {label:?}.");
159 self
160 }
161
162 /// Adds the given `stage` immediately before the `target` stage.
163 ///
164 /// # Example
165 ///
166 /// ```
167 /// # use maplibre::schedule::{Schedule, NopStage};
168 /// #
169 /// # let mut schedule = Schedule::default();
170 /// # schedule.add_stage("target_stage", NopStage);
171 /// #
172 /// schedule.add_stage_before("target_stage", "my_stage", NopStage);
173 /// ```
174 pub fn add_stage_before<S: Stage>(
175 &mut self,
176 target: impl StageLabel,
177 label: impl StageLabel,
178 stage: S,
179 ) -> &mut Self {
180 let label: Box<dyn StageLabel> = Box::new(label);
181 let target = &target as &dyn StageLabel;
182 let target_index = self
183 .stage_order
184 .iter()
185 .enumerate()
186 .find(|(_i, stage_label)| &***stage_label == target)
187 .map(|(i, _)| i)
188 .unwrap_or_else(|| panic!("Target stage does not exist: {target:?}."));
189
190 self.stage_order.insert(target_index, label.clone());
191 let prev = self.stages.insert(label.clone(), Box::new(stage));
192 assert!(prev.is_none(), "Stage already exists: {label:?}.");
193 self
194 }
195
196 /// Fetches the [`Stage`] of type `T` marked with `label`, then executes the provided
197 /// `func` passing the fetched stage to it as an argument.
198 ///
199 /// The `func` argument should be a function or a closure that accepts a mutable reference
200 /// to a struct implementing `Stage` and returns the same type. That means that it should
201 /// also assume that the stage has already been fetched successfully.
202 ///
203 /// # Example
204 ///
205 /// ```
206 /// # use maplibre::schedule::{Schedule, NopStage};
207 /// # let mut schedule = Schedule::default();
208 ///
209 /// # schedule.add_stage("my_stage", NopStage);
210 /// #
211 /// schedule.stage("my_stage", |stage: &mut NopStage| {
212 /// // modify stage
213 /// stage
214 /// });
215 /// ```
216 ///
217 /// # Panics
218 ///
219 /// Panics if `label` refers to a non-existing stage, or if it's not of type `T`.
220 pub fn stage<T: Stage, F: FnOnce(&mut T) -> &mut T>(
221 &mut self,
222 label: impl StageLabel,
223 func: F,
224 ) -> &mut Self {
225 let stage = self.get_stage_mut::<T>(&label).unwrap_or_else(move || {
226 panic!("stage '{label:?}' does not exist or is the wrong type")
227 });
228 func(stage);
229 self
230 }
231
232 /// Returns a shared reference to the stage identified by `label`, if it exists.
233 ///
234 /// If the requested stage does not exist, `None` is returned instead.
235 ///
236 /// # Example
237 ///
238 /// ```
239 /// # use maplibre::schedule::{Schedule, NopStage};
240 /// #
241 /// # let mut schedule = Schedule::default();
242 /// # schedule.add_stage("my_stage", NopStage);
243 /// #
244 /// let stage = schedule.get_stage::<NopStage>(&"my_stage").unwrap();
245 /// ```
246 pub fn get_stage<T: Stage>(&self, label: &dyn StageLabel) -> Option<&T> {
247 self.stages
248 .get(label)
249 .and_then(|stage| stage.downcast_ref::<T>())
250 }
251
252 /// Returns a unique, mutable reference to the stage identified by `label`, if it exists.
253 ///
254 /// If the requested stage does not exist, `None` is returned instead.
255 ///
256 /// # Example
257 ///
258 /// ```
259 /// # use maplibre::schedule::{Schedule, NopStage};
260 /// #
261 /// # let mut schedule = Schedule::default();
262 /// # schedule.add_stage("my_stage", NopStage);
263 /// #
264 /// let stage = schedule.get_stage_mut::<NopStage>(&"my_stage").unwrap();
265 /// ```
266 pub fn get_stage_mut<T: Stage>(&mut self, label: &dyn StageLabel) -> Option<&mut T> {
267 self.stages
268 .get_mut(label)
269 .and_then(|stage| stage.downcast_mut::<T>())
270 }
271
272 /// Executes each [`Stage`] contained in the schedule, one at a time.
273 pub fn run_once(&mut self, context: &mut MapContext) -> StageResult {
274 for label in &self.stage_order {
275 #[cfg(feature = "trace")]
276 let _stage_span = tracing::info_span!("stage", name = ?label).entered();
277 let stage = self.stages.get_mut(label).unwrap(); // TODO: Remove unwrap
278 stage.run(context)?;
279 }
280 Ok(())
281 }
282
283 pub fn clear(&mut self) {
284 self.stage_order.clear();
285 self.stages.clear();
286 }
287
288 /// Iterates over all of schedule's stages and their labels, in execution order.
289 pub fn iter_stages(&self) -> impl Iterator<Item = (&dyn StageLabel, &dyn Stage)> {
290 self.stage_order
291 .iter()
292 .map(move |label| (&**label, &*self.stages[label]))
293 }
294
295 /// Adds a system to the [`Stage`] identified by `stage_label`.
296 ///
297 /// # Examples
298 ///
299 /// ```
300 /// # use maplibre::context::MapContext;
301 /// # use maplibre::tcs::system::stage::SystemStage;
302 /// # use maplibre::schedule::{Schedule, NopStage};
303 /// # use maplibre::tcs::system::SystemError;
304 /// #
305 /// # let mut schedule = Schedule::default();
306 /// # schedule.add_stage("my_stage", SystemStage::default());
307 /// # fn my_system(context: &mut MapContext) -> Result<(), SystemError> { Ok(()) }
308 /// #
309 /// schedule.add_system_to_stage("my_stage", my_system);
310 /// ```
311 pub fn add_system_to_stage(
312 &mut self,
313 stage_label: impl StageLabel,
314 system: impl IntoSystemContainer,
315 ) -> &mut Self {
316 let stage = self
317 .get_stage_mut::<SystemStage>(&stage_label)
318 .unwrap_or_else(move || {
319 panic!("Stage '{stage_label:?}' does not exist or is not a SystemStage")
320 });
321 stage.add_system(system);
322 self
323 }
324}
325
326impl Stage for Schedule {
327 fn run(&mut self, context: &mut MapContext) -> StageResult {
328 self.run_once(context)?;
329 Ok(())
330 }
331}