bevy_ecs/system/
input.rs

1use core::ops::{Deref, DerefMut};
2
3use variadics_please::all_tuples;
4
5use crate::{bundle::Bundle, prelude::Trigger, system::System};
6
7/// Trait for types that can be used as input to [`System`]s.
8///
9/// Provided implementations are:
10/// - `()`: No input
11/// - [`In<T>`]: For values
12/// - [`InRef<T>`]: For read-only references to values
13/// - [`InMut<T>`]: For mutable references to values
14/// - [`Trigger<E, B>`]: For [`ObserverSystem`]s
15/// - [`StaticSystemInput<I>`]: For arbitrary [`SystemInput`]s in generic contexts
16/// - Tuples of [`SystemInput`]s up to 8 elements
17///
18/// For advanced usecases, you can implement this trait for your own types.
19///
20/// # Examples
21///
22/// ## Tuples of [`SystemInput`]s
23///
24/// ```
25/// use bevy_ecs::prelude::*;
26///
27/// fn add((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
28///     *a += b;
29/// }
30/// # let mut world = World::new();
31/// # let mut add = IntoSystem::into_system(add);
32/// # add.initialize(&mut world);
33/// # let mut a = 12;
34/// # let b = 24;
35/// # add.run((&mut a, b), &mut world);
36/// # assert_eq!(a, 36);
37/// ```
38///
39/// [`ObserverSystem`]: crate::system::ObserverSystem
40pub trait SystemInput: Sized {
41    /// The wrapper input type that is defined as the first argument to [`FunctionSystem`]s.
42    ///
43    /// [`FunctionSystem`]: crate::system::FunctionSystem
44    type Param<'i>: SystemInput;
45    /// The inner input type that is passed to functions that run systems,
46    /// such as [`System::run`].
47    ///
48    /// [`System::run`]: crate::system::System::run
49    type Inner<'i>;
50
51    /// Converts a [`SystemInput::Inner`] into a [`SystemInput::Param`].
52    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_>;
53}
54
55/// Shorthand way to get the [`System::In`] for a [`System`] as a [`SystemInput::Inner`].
56pub type SystemIn<'a, S> = <<S as System>::In as SystemInput>::Inner<'a>;
57
58/// A [`SystemInput`] type which denotes that a [`System`] receives
59/// an input value of type `T` from its caller.
60///
61/// [`System`]s may take an optional input which they require to be passed to them when they
62/// are being [`run`](System::run). For [`FunctionSystem`]s the input may be marked
63/// with this `In` type, but only the first param of a function may be tagged as an input. This also
64/// means a system can only have one or zero input parameters.
65///
66/// See [`SystemInput`] to learn more about system inputs in general.
67///
68/// # Examples
69///
70/// Here is a simple example of a system that takes a [`usize`] and returns the square of it.
71///
72/// ```
73/// # use bevy_ecs::prelude::*;
74/// #
75/// fn square(In(input): In<usize>) -> usize {
76///     input * input
77/// }
78///
79/// let mut world = World::new();
80/// let mut square_system = IntoSystem::into_system(square);
81/// square_system.initialize(&mut world);
82///
83/// assert_eq!(square_system.run(12, &mut world), 144);
84/// ```
85///
86/// [`SystemParam`]: crate::system::SystemParam
87/// [`FunctionSystem`]: crate::system::FunctionSystem
88#[derive(Debug)]
89pub struct In<T>(pub T);
90
91impl<T: 'static> SystemInput for In<T> {
92    type Param<'i> = In<T>;
93    type Inner<'i> = T;
94
95    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
96        In(this)
97    }
98}
99
100impl<T> Deref for In<T> {
101    type Target = T;
102
103    fn deref(&self) -> &Self::Target {
104        &self.0
105    }
106}
107
108impl<T> DerefMut for In<T> {
109    fn deref_mut(&mut self) -> &mut Self::Target {
110        &mut self.0
111    }
112}
113
114/// A [`SystemInput`] type which denotes that a [`System`] receives
115/// a read-only reference to a value of type `T` from its caller.
116///
117/// This is similar to [`In`] but takes a reference to a value instead of the value itself.
118/// See [`InMut`] for the mutable version.
119///
120/// See [`SystemInput`] to learn more about system inputs in general.
121///
122/// # Examples
123///
124/// Here is a simple example of a system that logs the passed in message.
125///
126/// ```
127/// # use bevy_ecs::prelude::*;
128/// # use std::fmt::Write as _;
129/// #
130/// #[derive(Resource, Default)]
131/// struct Log(String);
132///
133/// fn log(InRef(msg): InRef<str>, mut log: ResMut<Log>) {
134///     writeln!(log.0, "{}", msg).unwrap();
135/// }
136///
137/// let mut world = World::new();
138/// world.init_resource::<Log>();
139/// let mut log_system = IntoSystem::into_system(log);
140/// log_system.initialize(&mut world);
141///
142/// log_system.run("Hello, world!", &mut world);
143/// # assert_eq!(world.get_resource::<Log>().unwrap().0, "Hello, world!\n");
144/// ```
145///
146/// [`SystemParam`]: crate::system::SystemParam
147#[derive(Debug)]
148pub struct InRef<'i, T: ?Sized>(pub &'i T);
149
150impl<T: ?Sized + 'static> SystemInput for InRef<'_, T> {
151    type Param<'i> = InRef<'i, T>;
152    type Inner<'i> = &'i T;
153
154    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
155        InRef(this)
156    }
157}
158
159impl<'i, T: ?Sized> Deref for InRef<'i, T> {
160    type Target = T;
161
162    fn deref(&self) -> &Self::Target {
163        self.0
164    }
165}
166
167/// A [`SystemInput`] type which denotes that a [`System`] receives
168/// a mutable reference to a value of type `T` from its caller.
169///
170/// This is similar to [`In`] but takes a mutable reference to a value instead of the value itself.
171/// See [`InRef`] for the read-only version.
172///
173/// See [`SystemInput`] to learn more about system inputs in general.
174///
175/// # Examples
176///
177/// Here is a simple example of a system that takes a `&mut usize` and squares it.
178///
179/// ```
180/// # use bevy_ecs::prelude::*;
181/// #
182/// fn square(InMut(input): InMut<usize>) {
183///     *input *= *input;
184/// }
185///
186/// let mut world = World::new();
187/// let mut square_system = IntoSystem::into_system(square);
188/// square_system.initialize(&mut world);
189///     
190/// let mut value = 12;
191/// square_system.run(&mut value, &mut world);
192/// assert_eq!(value, 144);
193/// ```
194///
195/// [`SystemParam`]: crate::system::SystemParam
196#[derive(Debug)]
197pub struct InMut<'a, T: ?Sized>(pub &'a mut T);
198
199impl<T: ?Sized + 'static> SystemInput for InMut<'_, T> {
200    type Param<'i> = InMut<'i, T>;
201    type Inner<'i> = &'i mut T;
202
203    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
204        InMut(this)
205    }
206}
207
208impl<'i, T: ?Sized> Deref for InMut<'i, T> {
209    type Target = T;
210
211    fn deref(&self) -> &Self::Target {
212        self.0
213    }
214}
215
216impl<'i, T: ?Sized> DerefMut for InMut<'i, T> {
217    fn deref_mut(&mut self) -> &mut Self::Target {
218        self.0
219    }
220}
221
222/// Used for [`ObserverSystem`]s.
223///
224/// [`ObserverSystem`]: crate::system::ObserverSystem
225impl<E: 'static, B: Bundle> SystemInput for Trigger<'_, E, B> {
226    type Param<'i> = Trigger<'i, E, B>;
227    type Inner<'i> = Trigger<'i, E, B>;
228
229    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
230        this
231    }
232}
233
234/// A helper for using [`SystemInput`]s in generic contexts.
235///
236/// This type is a [`SystemInput`] adapter which always has
237/// `Self::Param == Self` (ignoring lifetimes for brevity),
238/// no matter the argument [`SystemInput`] (`I`).
239///
240/// This makes it useful for having arbitrary [`SystemInput`]s in
241/// function systems.
242///
243/// See [`SystemInput`] to learn more about system inputs in general.
244pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);
245
246impl<'a, I: SystemInput> SystemInput for StaticSystemInput<'a, I> {
247    type Param<'i> = StaticSystemInput<'i, I>;
248    type Inner<'i> = I::Inner<'i>;
249
250    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
251        StaticSystemInput(this)
252    }
253}
254
255macro_rules! impl_system_input_tuple {
256    ($(#[$meta:meta])* $($name:ident),*) => {
257        $(#[$meta])*
258        impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {
259            type Param<'i> = ($($name::Param<'i>,)*);
260            type Inner<'i> = ($($name::Inner<'i>,)*);
261
262            #[expect(
263                clippy::allow_attributes,
264                reason = "This is in a macro; as such, the below lints may not always apply."
265            )]
266            #[allow(
267                non_snake_case,
268                reason = "Certain variable names are provided by the caller, not by us."
269            )]
270            #[allow(
271                clippy::unused_unit,
272                reason = "Zero-length tuples won't have anything to wrap."
273            )]
274            fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
275                let ($($name,)*) = this;
276                ($($name::wrap($name),)*)
277            }
278        }
279    };
280}
281
282all_tuples!(
283    #[doc(fake_variadic)]
284    impl_system_input_tuple,
285    0,
286    8,
287    I
288);
289
290#[cfg(test)]
291mod tests {
292    use crate::{
293        system::{In, InMut, InRef, IntoSystem, System},
294        world::World,
295    };
296
297    #[test]
298    fn two_tuple() {
299        fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {
300            a + b
301        }
302        fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {
303            *a + *b
304        }
305        fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
306            *a += b;
307        }
308
309        let mut world = World::new();
310        let mut by_value = IntoSystem::into_system(by_value);
311        let mut by_ref = IntoSystem::into_system(by_ref);
312        let mut by_mut = IntoSystem::into_system(by_mut);
313
314        by_value.initialize(&mut world);
315        by_ref.initialize(&mut world);
316        by_mut.initialize(&mut world);
317
318        let mut a = 12;
319        let b = 24;
320
321        assert_eq!(by_value.run((a, b), &mut world), 36);
322        assert_eq!(by_ref.run((&a, &b), &mut world), 36);
323        by_mut.run((&mut a, b), &mut world);
324        assert_eq!(a, 36);
325    }
326}