Skip to main content

pebble/ecs/
system_param.rs

1use crate::ecs::resources::Resources;
2
3/// Anything that can be fetched as a system function parameter —
4/// implemented for [`Read`](crate::ecs::resources::Read)/[`Write`](crate::ecs::resources::Write),
5/// [`Query`](crate::ecs::query::Query), [`Local`](crate::ecs::local::Local),
6/// [`Commands`](crate::ecs::commands::Commands), tuples of `SystemParam`s
7/// (so a function can take several), and a few others. You generally don't
8/// implement this yourself unless you're adding a new kind of parameter.
9pub trait SystemParam {
10    /// The value actually handed to the system function.
11    type Item<'a>;
12    /// Per-system persistent state (e.g. [`Local`](crate::ecs::local::Local)'s
13    /// stored value) — `()` for anything stateless.
14    type State: Default + 'static;
15
16    fn fetch<'a>(
17        world: &'a hecs::World,
18        resources: &'a Resources,
19        state: &'a mut Self::State,
20    ) -> Self::Item<'a>;
21}
22
23impl<'a> SystemParam for &'a hecs::World {
24    type Item<'w> = &'w hecs::World;
25    type State = ();
26
27    fn fetch<'w>(
28        world: &'w hecs::World,
29        _resources: &'w Resources,
30        _state: &'w mut Self::State,
31    ) -> Self::Item<'w> {
32        world
33    }
34}
35
36impl<'a> SystemParam for &'a Resources {
37    type Item<'w> = &'w Resources;
38    type State = ();
39
40    fn fetch<'w>(
41        _world: &'w hecs::World,
42        resources: &'w Resources,
43        _state: &'w mut Self::State,
44    ) -> Self::Item<'w> {
45        resources
46    }
47}
48
49/// A runnable system — the type-erased form `IntoSystem` produces, so
50/// different systems (different parameter lists) can live in the same
51/// `Vec<Box<dyn System>>`.
52pub trait System: 'static {
53    fn run(&mut self, world: &hecs::World, resources: &Resources);
54}
55
56/// Wraps a plain function into a [`System`], holding its per-call
57/// [`SystemParam::State`] between runs.
58pub struct FunctionSystem<F, Marker, State = ()> {
59    pub func: F,
60    state: State,
61    _marker: std::marker::PhantomData<Marker>,
62}
63
64/// Implemented for any function whose parameters are all [`SystemParam`]s —
65/// this is what lets a plain `fn my_system(time: Read<Time>)` be passed
66/// directly to `add_system`.
67pub trait IntoSystem<Marker> {
68    type System: System;
69
70    fn into_system(self) -> Self::System;
71}
72
73macro_rules! impl_system {
74    ($($param:ident),*) => {
75        impl<T, $($param),*> IntoSystem<($($param,)*)> for T
76        where
77            T: FnMut($($param),*) + for<'a> FnMut($($param::Item<'a>),*) + 'static,
78            $($param: SystemParam + 'static),*
79        {
80            type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
81            fn into_system(self) -> Self::System {
82                FunctionSystem {
83                    func: self,
84                    state: Default::default(),
85                    _marker: std::marker::PhantomData,
86                }
87            }
88        }
89        impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
90        where
91            T: FnMut($($param),*) + for<'a> FnMut($($param::Item<'a>),*) + 'static,
92            $($param: SystemParam + 'static),*
93        {
94            fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
95                #[allow(non_snake_case)]
96                let ($($param,)*) = &mut self.state;
97                (self.func)($($param::fetch(_world, _resources, $param)),*);
98            }
99        }
100    };
101}
102
103impl_system!();
104impl_system!(A);
105impl_system!(A, B);
106impl_system!(A, B, C);
107impl_system!(A, B, C, D);
108impl_system!(A, B, C, D, E);
109impl_system!(A, B, C, D, E, F);
110impl_system!(A, B, C, D, E, F, G);
111impl_system!(A, B, C, D, E, F, G, H);
112impl_system!(A, B, C, D, E, F, G, H, I);
113impl_system!(A, B, C, D, E, F, G, H, I, J);
114impl_system!(A, B, C, D, E, F, G, H, I, J, K);
115impl_system!(A, B, C, D, E, F, G, H, I, J, K, L);