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 constraints: Vec<OrderConstraint>,
90 _marker: std::marker::PhantomData<fn() -> Params>,
91}
92
93impl<S, Params> SystemConfig<S, Params>
94where
95 S: IntoSystem<Params> + 'static,
96{
97 pub fn after<S2, P2>(mut self, _other: S2) -> Self
101 where
102 S2: IntoSystem<P2> + 'static,
103 {
104 self.constraints.push(OrderConstraint::After(TypeId::of::<S2>()));
105 self
106 }
107
108 pub fn before<S2, P2>(mut self, _other: S2) -> Self
112 where
113 S2: IntoSystem<P2> + 'static,
114 {
115 self.constraints.push(OrderConstraint::Before(TypeId::of::<S2>()));
116 self
117 }
118
119 #[doc(hidden)]
123 pub fn into_parts(self) -> (TypeId, Box<dyn System>, Vec<(TypeId, TypeId)>) {
124 let id = TypeId::of::<S>();
125 let constraints = self
127 .constraints
128 .into_iter()
129 .map(|constraint| match constraint {
130 OrderConstraint::After(dependency) => (id, dependency),
131 OrderConstraint::Before(dependent) => (dependent, id),
132 })
133 .collect();
134 (id, Box::new(self.system.into_system()), constraints)
135 }
136}
137
138impl<S, Params> From<S> for SystemConfig<S, Params>
142where
143 S: IntoSystem<Params> + 'static,
144{
145 fn from(system: S) -> Self {
146 SystemConfig {
147 system,
148 constraints: Vec::new(),
149 _marker: std::marker::PhantomData,
150 }
151 }
152}
153
154pub trait IntoSystemConfig<Params>: IntoSystem<Params> + Sized {
166 fn after<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
168 where
169 S2: IntoSystem<P2> + 'static;
170
171 fn before<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
173 where
174 S2: IntoSystem<P2> + 'static;
175}
176
177impl<T, Params> IntoSystemConfig<Params> for T
178where
179 T: IntoSystem<Params> + 'static,
180{
181 fn after<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
182 where
183 S2: IntoSystem<P2> + 'static,
184 {
185 SystemConfig::from(self).after(other)
186 }
187
188 fn before<S2, P2>(self, other: S2) -> SystemConfig<Self, Params>
189 where
190 S2: IntoSystem<P2> + 'static,
191 {
192 SystemConfig::from(self).before(other)
193 }
194}
195
196macro_rules! impl_system {
197 ($($param:ident),*) => {
198 impl<T, $($param),*> IntoSystem<($($param,)*)> for T
199 where
200 T: FnMut($($param),*) + for<'a> FnMut($($param::Item<'a>),*) + 'static,
201 $($param: SystemParam + 'static),*
202 {
203 type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
204 fn into_system(self) -> Self::System {
205 FunctionSystem {
206 func: self,
207 state: Default::default(),
208 _marker: std::marker::PhantomData,
209 }
210 }
211 }
212 impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
213 where
214 T: FnMut($($param),*) + for<'a> FnMut($($param::Item<'a>),*) + 'static,
215 $($param: SystemParam + 'static),*
216 {
217 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
218 #[allow(non_snake_case)]
219 let ($($param,)*) = &mut self.state;
220 (self.func)($($param::fetch(_world, _resources, $param)),*);
221 }
222 }
223 };
224}
225
226impl_system!();
227impl_system!(A);
228impl_system!(A, B);
229impl_system!(A, B, C);
230impl_system!(A, B, C, D);
231impl_system!(A, B, C, D, E);
232impl_system!(A, B, C, D, E, F);
233impl_system!(A, B, C, D, E, F, G);
234impl_system!(A, B, C, D, E, F, G, H);
235impl_system!(A, B, C, D, E, F, G, H, I);
236impl_system!(A, B, C, D, E, F, G, H, I, J);
237impl_system!(A, B, C, D, E, F, G, H, I, J, K);
238impl_system!(A, B, C, D, E, F, G, H, I, J, K, L);