1use std::collections::VecDeque;
4
5use crate::prelude::*;
6
7#[derive(Deref, DerefMut, Clone, Copy, HasSchema, Default)]
12pub struct CurrentSystemStage(pub Ulid);
13
14pub struct SystemStages {
16 pub stages: Vec<Box<dyn SystemStage>>,
18 pub has_started: bool,
20 pub startup_systems: Vec<StaticSystem<(), ()>>,
22 pub single_success_systems: Vec<StaticSystem<(), Option<()>>>,
24}
25
26impl std::fmt::Debug for SystemStages {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 f.debug_struct("SystemStages")
29 .finish()
33 }
34}
35
36impl Default for SystemStages {
37 fn default() -> Self {
38 Self::with_core_stages()
39 }
40}
41
42impl SystemStages {
43 pub fn run(&mut self, world: &mut World) {
45 if !self.has_started {
47 world.insert_resource(CurrentSystemStage(Ulid(0)));
49
50 for system in &mut self.startup_systems {
52 system.run(world, ());
54 }
55
56 self.has_started = true;
58 }
59
60 self.single_success_systems.retain_mut(|system| {
62 let result = system.run(world, ());
63 result.is_none() });
65
66 for stage in &mut self.stages {
68 world.insert_resource(CurrentSystemStage(stage.id()));
70
71 stage.run(world);
73 }
74
75 world.maintain();
77
78 world.resources.remove::<CurrentSystemStage>();
80 }
81
82 pub fn with_core_stages() -> Self {
84 Self {
85 stages: vec![
86 Box::new(SimpleSystemStage::new(CoreStage::First)),
87 Box::new(SimpleSystemStage::new(CoreStage::PreUpdate)),
88 Box::new(SimpleSystemStage::new(CoreStage::Update)),
89 Box::new(SimpleSystemStage::new(CoreStage::PostUpdate)),
90 Box::new(SimpleSystemStage::new(CoreStage::Last)),
91 ],
92 has_started: false,
93 startup_systems: default(),
94 single_success_systems: Vec::new(),
95 }
96 }
97
98 pub fn add_startup_system<Args, S>(&mut self, system: S) -> &mut Self
100 where
101 S: IntoSystem<Args, (), (), Sys = StaticSystem<(), ()>>,
102 {
103 self.startup_systems.push(system.system());
104 self
105 }
106
107 pub fn add_single_success_system<Args, S>(&mut self, system: S) -> &mut Self
109 where
110 S: IntoSystem<Args, (), Option<()>, Sys = StaticSystem<(), Option<()>>>,
111 {
112 self.single_success_systems.push(system.system());
113 self
114 }
115
116 pub fn add_system_to_stage<Args, S>(&mut self, label: impl StageLabel, system: S) -> &mut Self
118 where
119 S: IntoSystem<Args, (), (), Sys = StaticSystem<(), ()>>,
120 {
121 let name = label.name();
122 let id = label.id();
123 let mut stage = None;
124
125 for st in &mut self.stages {
126 if st.id() == id {
127 stage = Some(st);
128 }
129 }
130
131 let Some(stage) = stage else {
132 panic!("Stage with label `{}` ( {} ) doesn't exist.", name, id);
133 };
134
135 stage.add_system(system.system());
136
137 self
138 }
139
140 #[track_caller]
142 pub fn insert_stage_before<L: StageLabel, S: SystemStage + 'static>(
143 &mut self,
144 label: L,
145 stage: S,
146 ) -> &mut Self {
147 let stage_idx = self
148 .stages
149 .iter()
150 .position(|x| x.id() == label.id())
151 .unwrap_or_else(|| panic!("Could not find stage with label `{}`", label.name()));
152 self.stages.insert(stage_idx, Box::new(stage));
153
154 self
155 }
156
157 #[track_caller]
159 pub fn insert_stage_after<L: StageLabel, S: SystemStage + 'static>(
160 &mut self,
161 label: L,
162 stage: S,
163 ) -> &mut Self {
164 let stage_idx = self
165 .stages
166 .iter()
167 .position(|x| x.id() == label.id())
168 .unwrap_or_else(|| panic!("Could not find stage with label `{}`", label.name()));
169 self.stages.insert(stage_idx + 1, Box::new(stage));
170
171 self
172 }
173
174 pub fn reset_remove_all_systems(&mut self) {
176 self.has_started = false;
178 self.remove_all_systems();
179 }
180
181 pub fn remove_all_systems(&mut self) {
183 self.startup_systems.clear();
185
186 self.single_success_systems.clear();
188
189 for stage in &mut self.stages {
191 stage.remove_all_systems();
192 }
193 }
194}
195
196pub trait SystemStage: Sync + Send {
198 fn id(&self) -> Ulid;
200 fn name(&self) -> String;
202 fn run(&mut self, world: &World);
204
205 fn add_system(&mut self, system: StaticSystem<(), ()>);
207 fn remove_all_systems(&mut self);
209}
210
211pub struct SimpleSystemStage {
213 pub id: Ulid,
215 pub name: String,
217 pub systems: Vec<StaticSystem<(), ()>>,
221}
222
223impl SimpleSystemStage {
224 pub fn new<L: StageLabel>(label: L) -> Self {
226 Self {
227 id: label.id(),
228 name: label.name(),
229 systems: Default::default(),
230 }
231 }
232}
233
234impl SystemStage for SimpleSystemStage {
235 fn id(&self) -> Ulid {
236 self.id
237 }
238
239 fn name(&self) -> String {
240 self.name.clone()
241 }
242
243 fn run(&mut self, world: &World) {
244 for system in &mut self.systems {
246 system.run(world, ());
247 }
248
249 let queue = world.resources.get_mut::<CommandQueue>();
251 if let Some(mut command_queue) = queue {
252 for mut system in command_queue.queue.drain(..) {
253 system.run(world, ());
254 }
255 }
256 }
257
258 fn add_system(&mut self, system: StaticSystem<(), ()>) {
259 self.systems.push(system);
260 }
261
262 fn remove_all_systems(&mut self) {
263 self.systems.clear();
264 }
265}
266
267pub trait StageLabel {
269 fn name(&self) -> String;
271 fn id(&self) -> Ulid;
273}
274
275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
277pub enum CoreStage {
278 First,
280 PreUpdate,
282 Update,
284 PostUpdate,
286 Last,
288}
289
290impl StageLabel for CoreStage {
291 fn name(&self) -> String {
292 format!("{:?}", self)
293 }
294
295 fn id(&self) -> Ulid {
296 match self {
297 CoreStage::First => Ulid(2021715391084198804812356024998495966),
298 CoreStage::PreUpdate => Ulid(2021715401330719559452824437611089988),
299 CoreStage::Update => Ulid(2021715410160177201728645950400543948),
300 CoreStage::PostUpdate => Ulid(2021715423103233646561968734173322317),
301 CoreStage::Last => Ulid(2021715433398666914977687392909851554),
302 }
303 }
304}
305
306#[derive(HasSchema, Default)]
310pub struct CommandQueue {
311 pub queue: VecDeque<StaticSystem<(), ()>>,
313}
314
315impl Clone for CommandQueue {
316 fn clone(&self) -> Self {
317 if self.queue.is_empty() {
318 Self {
319 queue: VecDeque::with_capacity(self.queue.capacity()),
320 }
321 } else {
322 panic!(
323 "Cannot clone CommandQueue. This probably happened because you are \
324 trying to clone a World while a system stage is still executing."
325 )
326 }
327 }
328}
329
330impl CommandQueue {
331 pub fn add<Args, S>(&mut self, system: S)
333 where
334 S: IntoSystem<Args, (), (), Sys = StaticSystem<(), ()>>,
335 {
336 self.queue.push_back(system.system());
337 }
338}
339
340#[derive(Deref, DerefMut)]
345pub struct Commands<'a>(RefMut<'a, CommandQueue>);
346
347impl<'a> SystemParam for Commands<'a> {
348 type State = AtomicResource<CommandQueue>;
349 type Param<'s> = Commands<'s>;
350
351 fn get_state(world: &World) -> Self::State {
352 let cell = world.resources.get_cell::<CommandQueue>();
353 cell.init(world);
354 cell
355 }
356
357 fn borrow<'s>(_world: &'s World, state: &'s mut Self::State) -> Self::Param<'s> {
358 Commands(state.borrow_mut().unwrap())
359 }
360}