limnus_stage/lib.rs
1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/limnus
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use limnus_system::{IntoSystem, System, SystemParam};
6use limnus_system_state::State;
7use std::any::TypeId;
8use std::collections::HashMap;
9use std::fmt::{Debug, Formatter};
10
11/// A marker trait used to uniquely identify stages.
12///
13/// Implement this trait for any type you wish to use as a stage identifier.
14pub trait StageTag: 'static {}
15
16/// Manages multiple stages, each identified by a unique `StageTag`.
17///
18/// The `Stages` struct provides methods to add, retrieve, and modify stages.
19#[derive(Default, Debug)]
20pub struct Stages {
21 pub stages: HashMap<TypeId, Stage>,
22}
23
24impl Stages {
25 /// Creates a new, empty `Stages` instance.
26 ///
27 /// # Examples
28 ///
29 /// ```
30 /// use limnus_stage::Stages;
31 ///
32 /// let stages = Stages::new();
33 /// ```
34 #[must_use]
35 pub fn new() -> Self {
36 Self {
37 stages: HashMap::default(),
38 }
39 }
40
41 /// Adds a stage to the `Stages` collection with the specified tag.
42 ///
43 /// # Type Parameters
44 ///
45 /// - `S`: A type that implements the `StageTag` trait, used to uniquely identify the stage.
46 ///
47 /// # Parameters
48 ///
49 /// - `stage`: The `Stage` instance to be added.
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use limnus_stage::{Stages, Stage, StageTag};
55 ///
56 /// struct UpdateStage;
57 /// impl StageTag for UpdateStage {}
58 ///
59 /// let mut stages = Stages::new();
60 /// let stage = Stage::new();
61 /// stages.add::<UpdateStage>(stage);
62 /// ```
63 pub fn add<S>(&mut self, stage: Stage)
64 where
65 S: StageTag,
66 {
67 let stage_id = TypeId::of::<S>();
68 self.stages.insert(stage_id, stage);
69 }
70
71 /// Retrieves a mutable reference to a stage identified by the specified tag.
72 ///
73 /// # Type Parameters
74 ///
75 /// - `S`: A type that implements the `StageTag` trait, used to uniquely identify the stage.
76 ///
77 /// # Returns
78 ///
79 /// An `Option` containing a mutable reference to the `Stage` if it exists, or `None` otherwise.
80 ///
81 /// # Examples
82 ///
83 /// ```
84 /// use limnus_stage::{Stages, Stage, StageTag};
85 ///
86 /// struct UpdateStage;
87 /// impl StageTag for UpdateStage {}
88 ///
89 /// let mut stages = Stages::new();
90 /// let stage = Stage::new();
91 /// stages.add::<UpdateStage>(stage);
92 ///
93 /// if let Some(stage) = stages.get_mut::<UpdateStage>() {
94 /// // Modify the stage
95 /// }
96 /// ```
97 #[must_use]
98 pub fn get_mut<S>(&mut self) -> Option<&mut Stage>
99 where
100 S: StageTag,
101 {
102 let stage_id = TypeId::of::<S>();
103 self.stages.get_mut(&stage_id)
104 }
105
106 /// Retrieves an immutable reference to a stage identified by the specified tag.
107 ///
108 /// # Type Parameters
109 ///
110 /// - `S`: A type that implements the `StageTag` trait, used to uniquely identify the stage.
111 ///
112 /// # Returns
113 ///
114 /// An `Option` containing a reference to the `Stage` if it exists, or `None` otherwise.
115 ///
116 /// # Examples
117 ///
118 /// ```
119 /// use limnus_stage::{Stages, Stage, StageTag};
120 ///
121 /// struct UpdateStage;
122 /// impl StageTag for UpdateStage {}
123 ///
124 /// let mut stages = Stages::new();
125 /// let stage = Stage::new();
126 /// stages.add::<UpdateStage>(stage);
127 ///
128 /// if let Some(stage) = stages.get::<UpdateStage>() {
129 /// // Access the stage
130 /// }
131 /// ```
132 #[must_use]
133 pub fn get<S>(&self) -> Option<&Stage>
134 where
135 S: StageTag,
136 {
137 let stage_id = TypeId::of::<S>();
138 self.stages.get(&stage_id)
139 }
140
141 /// Retrieves an immutable reference to a stage by its `TypeId`.
142 ///
143 /// # Parameters
144 ///
145 /// - `stage_id`: A reference to the `TypeId` of the stage to retrieve.
146 ///
147 /// # Returns
148 ///
149 /// An `Option` containing a reference to the `Stage` if it exists, or `None` otherwise.
150 ///
151 /// # Examples
152 ///
153 /// ```
154 /// use limnus_stage::{Stages, Stage};
155 /// use std::any::TypeId;
156 ///
157 /// pub struct MyStageTag;
158 ///
159 /// let stages = Stages::new();
160 /// let stage_id = TypeId::of::<MyStageTag>();
161 /// if let Some(stage) = stages.get_by_id(&stage_id) {
162 /// // Access the stage
163 /// }
164 /// ```
165 #[inline]
166 #[must_use]
167 pub fn get_by_id(&self, stage_id: &TypeId) -> Option<&Stage> {
168 self.stages.get(stage_id)
169 }
170}
171
172/// Represents a single stage containing a collection of systems.
173///
174/// A `Stage` can have multiple systems that execute with access to shared state.
175pub struct Stage {
176 systems: Vec<Box<dyn System>>,
177}
178
179impl Debug for Stage {
180 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
181 write!(f, "stage")
182 }
183}
184
185impl Default for Stage {
186 /// Creates a new `Stage` instance with no systems.
187 ///
188 /// # Examples
189 ///
190 /// ```
191 /// use limnus_stage::Stage;
192 ///
193 /// let stage = Stage::default();
194 /// ```
195 fn default() -> Self {
196 Self::new()
197 }
198}
199
200impl Stage {
201 /// Creates a new, empty `Stage` instance.
202 ///
203 /// # Examples
204 ///
205 /// ```
206 /// use limnus_stage::Stage;
207 ///
208 /// let stage = Stage::new();
209 /// ```
210 #[must_use]
211 pub fn new() -> Self {
212 Self { systems: vec![] }
213 }
214
215 /// Adds a system to the stage.
216 ///
217 /// Systems are the core units of logic that run within a stage. They are executed in the order they are added.
218 ///
219 /// # Type Parameters
220 ///
221 /// - `F`: A function or closure that can be converted into a `System`.
222 /// - `Params`: Parameters required by the system, implementing the `SystemParam` trait.
223 ///
224 /// # Parameters
225 ///
226 /// - `function`: The system function or closure to add.
227 ///
228 pub fn add_system<F, Params>(&mut self, function: F)
229 where
230 F: IntoSystem<Params>,
231 Params: SystemParam,
232 {
233 self.systems.push(Box::new(function.into_system()));
234 }
235
236 /// Executes all systems within the stage, providing mutable access to the shared `State`.
237 ///
238 /// Systems are run in the order they were added to the stage.
239 ///
240 /// # Parameters
241 ///
242 /// - `state`: A mutable reference to the shared `State` that systems can modify.
243 ///
244 /// # Examples
245 ///
246 /// ```
247 /// use limnus_stage::Stage;
248 /// use limnus_system_state::State;
249 ///
250 /// let stage = Stage::new();
251 /// let mut state = State::default();
252 /// stage.run(&mut state);
253 /// ```
254 pub fn run(&self, state: &mut State) {
255 for system in &self.systems {
256 system.run(state);
257 }
258 }
259}