bevy_ecs/system/
input.rs

1use core::ops::{Deref, DerefMut};
2
3use variadics_please::all_tuples;
4
5use crate::{bundle::Bundle, event::Event, prelude::On, 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/// - [`On<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 type that may be constructed from the input of a [`System`].
59/// This is used to allow systems whose first parameter is a `StaticSystemInput<In>`
60/// to take an `In` as input, and can be implemented for user types to allow
61/// similar conversions.
62pub trait FromInput<In: SystemInput>: SystemInput {
63    /// Converts the system input's inner representation into this type's
64    /// inner representation.
65    fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i>;
66}
67
68impl<In: SystemInput> FromInput<In> for In {
69    #[inline]
70    fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {
71        inner
72    }
73}
74
75impl<'a, In: SystemInput> FromInput<In> for StaticSystemInput<'a, In> {
76    #[inline]
77    fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {
78        inner
79    }
80}
81
82/// A [`SystemInput`] type which denotes that a [`System`] receives
83/// an input value of type `T` from its caller.
84///
85/// [`System`]s may take an optional input which they require to be passed to them when they
86/// are being [`run`](System::run). For [`FunctionSystem`]s the input may be marked
87/// with this `In` type, but only the first param of a function may be tagged as an input. This also
88/// means a system can only have one or zero input parameters.
89///
90/// See [`SystemInput`] to learn more about system inputs in general.
91///
92/// # Examples
93///
94/// Here is a simple example of a system that takes a [`usize`] and returns the square of it.
95///
96/// ```
97/// # use bevy_ecs::prelude::*;
98/// #
99/// fn square(In(input): In<usize>) -> usize {
100///     input * input
101/// }
102///
103/// let mut world = World::new();
104/// let mut square_system = IntoSystem::into_system(square);
105/// square_system.initialize(&mut world);
106///
107/// assert_eq!(square_system.run(12, &mut world).unwrap(), 144);
108/// ```
109///
110/// [`SystemParam`]: crate::system::SystemParam
111/// [`FunctionSystem`]: crate::system::FunctionSystem
112#[derive(Debug)]
113pub struct In<T>(pub T);
114
115impl<T: 'static> SystemInput for In<T> {
116    type Param<'i> = In<T>;
117    type Inner<'i> = T;
118
119    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
120        In(this)
121    }
122}
123
124impl<T> Deref for In<T> {
125    type Target = T;
126
127    fn deref(&self) -> &Self::Target {
128        &self.0
129    }
130}
131
132impl<T> DerefMut for In<T> {
133    fn deref_mut(&mut self) -> &mut Self::Target {
134        &mut self.0
135    }
136}
137
138/// A [`SystemInput`] type which denotes that a [`System`] receives
139/// a read-only reference to a value of type `T` from its caller.
140///
141/// This is similar to [`In`] but takes a reference to a value instead of the value itself.
142/// See [`InMut`] for the mutable version.
143///
144/// See [`SystemInput`] to learn more about system inputs in general.
145///
146/// # Examples
147///
148/// Here is a simple example of a system that logs the passed in message.
149///
150/// ```
151/// # use bevy_ecs::prelude::*;
152/// # use std::fmt::Write as _;
153/// #
154/// #[derive(Resource, Default)]
155/// struct Log(String);
156///
157/// fn log(InRef(msg): InRef<str>, mut log: ResMut<Log>) {
158///     writeln!(log.0, "{}", msg).unwrap();
159/// }
160///
161/// let mut world = World::new();
162/// world.init_resource::<Log>();
163/// let mut log_system = IntoSystem::into_system(log);
164/// log_system.initialize(&mut world);
165///
166/// log_system.run("Hello, world!", &mut world);
167/// # assert_eq!(world.get_resource::<Log>().unwrap().0, "Hello, world!\n");
168/// ```
169///
170/// [`SystemParam`]: crate::system::SystemParam
171#[derive(Debug)]
172pub struct InRef<'i, T: ?Sized>(pub &'i T);
173
174impl<T: ?Sized + 'static> SystemInput for InRef<'_, T> {
175    type Param<'i> = InRef<'i, T>;
176    type Inner<'i> = &'i T;
177
178    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
179        InRef(this)
180    }
181}
182
183impl<'i, T: ?Sized> Deref for InRef<'i, T> {
184    type Target = T;
185
186    fn deref(&self) -> &Self::Target {
187        self.0
188    }
189}
190
191/// A [`SystemInput`] type which denotes that a [`System`] receives
192/// a mutable reference to a value of type `T` from its caller.
193///
194/// This is similar to [`In`] but takes a mutable reference to a value instead of the value itself.
195/// See [`InRef`] for the read-only version.
196///
197/// See [`SystemInput`] to learn more about system inputs in general.
198///
199/// # Examples
200///
201/// Here is a simple example of a system that takes a `&mut usize` and squares it.
202///
203/// ```
204/// # use bevy_ecs::prelude::*;
205/// #
206/// fn square(InMut(input): InMut<usize>) {
207///     *input *= *input;
208/// }
209///
210/// let mut world = World::new();
211/// let mut square_system = IntoSystem::into_system(square);
212/// square_system.initialize(&mut world);
213///     
214/// let mut value = 12;
215/// square_system.run(&mut value, &mut world);
216/// assert_eq!(value, 144);
217/// ```
218///
219/// [`SystemParam`]: crate::system::SystemParam
220#[derive(Debug)]
221pub struct InMut<'a, T: ?Sized>(pub &'a mut T);
222
223impl<T: ?Sized + 'static> SystemInput for InMut<'_, T> {
224    type Param<'i> = InMut<'i, T>;
225    type Inner<'i> = &'i mut T;
226
227    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
228        InMut(this)
229    }
230}
231
232impl<'i, T: ?Sized> Deref for InMut<'i, T> {
233    type Target = T;
234
235    fn deref(&self) -> &Self::Target {
236        self.0
237    }
238}
239
240impl<'i, T: ?Sized> DerefMut for InMut<'i, T> {
241    fn deref_mut(&mut self) -> &mut Self::Target {
242        self.0
243    }
244}
245
246/// Used for [`ObserverSystem`]s.
247///
248/// [`ObserverSystem`]: crate::system::ObserverSystem
249impl<E: Event, B: Bundle> SystemInput for On<'_, '_, E, B> {
250    // Note: the fact that we must use a shared lifetime here is
251    // a key piece of the complicated safety story documented above
252    // the `&mut E::Trigger<'_>` cast in `observer_system_runner` and in
253    // the `On` implementation.
254    type Param<'i> = On<'i, 'i, E, B>;
255    type Inner<'i> = On<'i, 'i, E, B>;
256
257    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
258        this
259    }
260}
261
262/// A helper for using [`SystemInput`]s in generic contexts.
263///
264/// This type is a [`SystemInput`] adapter which always has
265/// `Self::Param == Self` (ignoring lifetimes for brevity),
266/// no matter the argument [`SystemInput`] (`I`).
267///
268/// This makes it useful for having arbitrary [`SystemInput`]s in
269/// function systems.
270///
271/// See [`SystemInput`] to learn more about system inputs in general.
272pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);
273
274impl<'a, I: SystemInput> SystemInput for StaticSystemInput<'a, I> {
275    type Param<'i> = StaticSystemInput<'i, I>;
276    type Inner<'i> = I::Inner<'i>;
277
278    fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
279        StaticSystemInput(this)
280    }
281}
282
283macro_rules! impl_system_input_tuple {
284    ($(#[$meta:meta])* $($name:ident),*) => {
285        $(#[$meta])*
286        impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {
287            type Param<'i> = ($($name::Param<'i>,)*);
288            type Inner<'i> = ($($name::Inner<'i>,)*);
289
290            #[expect(
291                clippy::allow_attributes,
292                reason = "This is in a macro; as such, the below lints may not always apply."
293            )]
294            #[allow(
295                non_snake_case,
296                reason = "Certain variable names are provided by the caller, not by us."
297            )]
298            #[allow(
299                clippy::unused_unit,
300                reason = "Zero-length tuples won't have anything to wrap."
301            )]
302            fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
303                let ($($name,)*) = this;
304                ($($name::wrap($name),)*)
305            }
306        }
307    };
308}
309
310all_tuples!(
311    #[doc(fake_variadic)]
312    impl_system_input_tuple,
313    0,
314    8,
315    I
316);
317
318#[cfg(test)]
319mod tests {
320    use crate::{
321        system::{assert_is_system, In, InMut, InRef, IntoSystem, StaticSystemInput, System},
322        world::World,
323    };
324
325    #[test]
326    fn two_tuple() {
327        fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {
328            a + b
329        }
330        fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {
331            *a + *b
332        }
333        fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
334            *a += b;
335        }
336
337        let mut world = World::new();
338        let mut by_value = IntoSystem::into_system(by_value);
339        let mut by_ref = IntoSystem::into_system(by_ref);
340        let mut by_mut = IntoSystem::into_system(by_mut);
341
342        by_value.initialize(&mut world);
343        by_ref.initialize(&mut world);
344        by_mut.initialize(&mut world);
345
346        let mut a = 12;
347        let b = 24;
348
349        assert_eq!(by_value.run((a, b), &mut world).unwrap(), 36);
350        assert_eq!(by_ref.run((&a, &b), &mut world).unwrap(), 36);
351        by_mut.run((&mut a, b), &mut world).unwrap();
352        assert_eq!(a, 36);
353    }
354
355    #[test]
356    fn compatible_input() {
357        fn takes_usize(In(a): In<usize>) -> usize {
358            a
359        }
360
361        fn takes_static_usize(StaticSystemInput(b): StaticSystemInput<In<usize>>) -> usize {
362            b
363        }
364
365        assert_is_system::<In<usize>, usize, _>(takes_usize);
366        // test if StaticSystemInput is compatible with its inner type
367        assert_is_system::<In<usize>, usize, _>(takes_static_usize);
368    }
369}