1use std::any::TypeId;
2
3use crate::ecs::resources::Resources;
4
5pub trait SystemParam {
12 type Item<'a>;
14 type State: Default + 'static;
17
18 fn fetch<'a>(
19 world: &'a hecs::World,
20 resources: &'a Resources,
21 state: &'a mut Self::State,
22 ) -> Self::Item<'a>;
23}
24
25impl<'a> SystemParam for &'a hecs::World {
26 type Item<'w> = &'w hecs::World;
27 type State = ();
28
29 fn fetch<'w>(
30 world: &'w hecs::World,
31 _resources: &'w Resources,
32 _state: &'w mut Self::State,
33 ) -> Self::Item<'w> {
34 world
35 }
36}
37
38impl<'a> SystemParam for &'a Resources {
39 type Item<'w> = &'w Resources;
40 type State = ();
41
42 fn fetch<'w>(
43 _world: &'w hecs::World,
44 resources: &'w Resources,
45 _state: &'w mut Self::State,
46 ) -> Self::Item<'w> {
47 resources
48 }
49}
50
51pub trait System: 'static {
55 fn run(&mut self, world: &hecs::World, resources: &Resources);
56}
57
58pub struct FunctionSystem<F, Marker, State = ()> {
61 pub func: F,
62 state: State,
63 _marker: std::marker::PhantomData<Marker>,
64}
65
66pub trait IntoSystem<Marker> {
70 type System: System;
71
72 fn into_system(self) -> Self::System;
73}
74
75enum OrderConstraint {
80 After(TypeId),
81 Before(TypeId),
82}
83
84pub struct SystemConfig<S, Params> {
88 system: S,
89 priority: i32,
90 constraints: Vec<OrderConstraint>,
91 _marker: std::marker::PhantomData<fn() -> Params>,
92}
93
94impl<S, Params> SystemConfig<S, Params>
95where
96 S: IntoSystem<Params> + 'static,
97{
98 pub fn after<S2, P2>(mut self, _other: S2) -> Self
102 where
103 S2: IntoSystem<P2> + 'static,
104 {
105 self.constraints.push(OrderConstraint::After(TypeId::of::<S2>()));
106 self
107 }
108
109 pub fn before<S2, P2>(mut self, _other: S2) -> Self
113 where
114 S2: IntoSystem<P2> + 'static,
115 {
116 self.constraints.push(OrderConstraint::Before(TypeId::of::<S2>()));
117 self
118 }
119
120 pub fn priority(mut self, priority: i32) -> Self {
127 self.priority = priority;
128 self
129 }
130
131 #[doc(hidden)]
136 pub fn into_parts(self) -> (TypeId, Box<dyn System>, i32, Vec<(TypeId, TypeId)>) {
137 let id = TypeId::of::<S>();
138 let constraints = self
140 .constraints
141 .into_iter()
142 .map(|constraint| match constraint {
143 OrderConstraint::After(dependency) => (id, dependency),
144 OrderConstraint::Before(dependent) => (dependent, id),
145 })
146 .collect();
147 (id, Box::new(self.system.into_system()), self.priority, constraints)
148 }
149}
150
151impl<S, Params> From<S> for SystemConfig<S, Params>
155where
156 S: IntoSystem<Params> + 'static,
157{
158 fn from(system: S) -> Self {
159 SystemConfig {
160 system,
161 priority: 0,
162 constraints: Vec::new(),
163 _marker: std::marker::PhantomData,
164 }
165 }
166}
167
168pub trait IntoSystemConfig<Params>: IntoSystem<Params> + Sized {
182 fn after<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
184 where
185 S2: IntoSystem<P2> + 'static;
186
187 fn before<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
189 where
190 S2: IntoSystem<P2> + 'static;
191
192 fn priority(self, priority: i32) -> SystemConfig<Self, Params>;
194}
195
196impl<T, Params> IntoSystemConfig<Params> for T
197where
198 T: IntoSystem<Params> + 'static,
199{
200 fn after<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
201 where
202 S2: IntoSystem<P2> + 'static,
203 {
204 SystemConfig::from(self).after(other)
205 }
206
207 fn before<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
208 where
209 S2: IntoSystem<P2> + 'static,
210 {
211 SystemConfig::from(self).before(other)
212 }
213
214 fn priority(self, priority: i32) -> SystemConfig<Self, Params> {
215 SystemConfig::from(self).priority(priority)
216 }
217}
218
219pub struct SystemChain {
233 systems: Vec<(TypeId, Box<dyn System>, i32)>,
234 constraints: Vec<(TypeId, TypeId)>,
235}
236
237impl SystemChain {
238 fn first_id(&self) -> TypeId {
239 self.systems[0].0
240 }
241
242 fn last_id(&self) -> TypeId {
243 self.systems[self.systems.len() - 1].0
244 }
245
246 pub fn after<S2, P2>(mut self, _other: S2) -> Self
249 where
250 S2: IntoSystem<P2> + 'static,
251 {
252 let first = self.first_id();
253 self.constraints.push((first, TypeId::of::<S2>()));
254 self
255 }
256
257 pub fn before<S2, P2>(mut self, _other: S2) -> Self
260 where
261 S2: IntoSystem<P2> + 'static,
262 {
263 let last = self.last_id();
264 self.constraints.push((TypeId::of::<S2>(), last));
265 self
266 }
267
268 pub fn priority(mut self, priority: i32) -> Self {
271 for (_, _, p) in &mut self.systems {
272 *p = priority;
273 }
274 self
275 }
276
277 #[doc(hidden)]
283 pub fn into_parts(self) -> (Vec<(TypeId, Box<dyn System>, i32)>, Vec<(TypeId, TypeId)>) {
284 (self.systems, self.constraints)
285 }
286}
287
288pub trait Chain<Marker> {
302 fn chain(self) -> SystemChain;
303}
304
305macro_rules! impl_chain {
306 ($($S:ident : $P:ident),+) => {
307 impl<$($S, $P),+> Chain<($($P,)+)> for ($($S,)+)
308 where
309 $($S: IntoSystem<$P> + 'static,)+
310 {
311 #[allow(non_snake_case)]
312 fn chain(self) -> SystemChain {
313 let ($($S,)+) = self;
314 let systems: Vec<(TypeId, Box<dyn System>, i32)> = vec![
315 $((TypeId::of::<$S>(), Box::new($S.into_system()) as Box<dyn System>, 0),)+
316 ];
317 let constraints = systems.windows(2).map(|w| (w[1].0, w[0].0)).collect();
319 SystemChain { systems, constraints }
320 }
321 }
322 };
323}
324
325impl_chain!(A: PA, B: PB);
326impl_chain!(A: PA, B: PB, C: PC);
327impl_chain!(A: PA, B: PB, C: PC, D: PD);
328impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE);
329impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE, F: PF);
330impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE, F: PF, G: PG);
331impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE, F: PF, G: PG, H: PH);
332impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE, F: PF, G: PG, H: PH, I: PI);
333impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE, F: PF, G: PG, H: PH, I: PI, J: PJ);
334impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE, F: PF, G: PG, H: PH, I: PI, J: PJ, K: PK);
335impl_chain!(A: PA, B: PB, C: PC, D: PD, E: PE, F: PF, G: PG, H: PH, I: PI, J: PJ, K: PK, L: PL);
336
337macro_rules! impl_system {
338 ($($param:ident),*) => {
339 impl<T, $($param),*> IntoSystem<($($param,)*)> for T
340 where
341 T: FnMut($($param),*) + for<'a> FnMut($($param::Item<'a>),*) + 'static,
342 $($param: SystemParam + 'static),*
343 {
344 type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
345 fn into_system(self) -> Self::System {
346 FunctionSystem {
347 func: self,
348 state: Default::default(),
349 _marker: std::marker::PhantomData,
350 }
351 }
352 }
353 impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
354 where
355 T: FnMut($($param),*) + for<'a> FnMut($($param::Item<'a>),*) + 'static,
356 $($param: SystemParam + 'static),*
357 {
358 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
359 #[allow(non_snake_case)]
360 let ($($param,)*) = &mut self.state;
361 (self.func)($($param::fetch(_world, _resources, $param)),*);
362 }
363 }
364 };
365}
366
367impl_system!();
368impl_system!(A);
369impl_system!(A, B);
370impl_system!(A, B, C);
371impl_system!(A, B, C, D);
372impl_system!(A, B, C, D, E);
373impl_system!(A, B, C, D, E, F);
374impl_system!(A, B, C, D, E, F, G);
375impl_system!(A, B, C, D, E, F, G, H);
376impl_system!(A, B, C, D, E, F, G, H, I);
377impl_system!(A, B, C, D, E, F, G, H, I, J);
378impl_system!(A, B, C, D, E, F, G, H, I, J, K);
379impl_system!(A, B, C, D, E, F, G, H, I, J, K, L);