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}