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 [`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).unwrap(), 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: Event, B: Bundle> SystemInput for On<'_, '_, E, B> {
226 // Note: the fact that we must use a shared lifetime here is
227 // a key piece of the complicated safety story documented above
228 // the `&mut E::Trigger<'_>` cast in `observer_system_runner` and in
229 // the `On` implementation.
230 type Param<'i> = On<'i, 'i, E, B>;
231 type Inner<'i> = On<'i, 'i, E, B>;
232
233 fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
234 this
235 }
236}
237
238/// A helper for using [`SystemInput`]s in generic contexts.
239///
240/// This type is a [`SystemInput`] adapter which always has
241/// `Self::Param == Self` (ignoring lifetimes for brevity),
242/// no matter the argument [`SystemInput`] (`I`).
243///
244/// This makes it useful for having arbitrary [`SystemInput`]s in
245/// function systems.
246///
247/// See [`SystemInput`] to learn more about system inputs in general.
248pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);
249
250impl<'a, I: SystemInput> SystemInput for StaticSystemInput<'a, I> {
251 type Param<'i> = StaticSystemInput<'i, I>;
252 type Inner<'i> = I::Inner<'i>;
253
254 fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
255 StaticSystemInput(this)
256 }
257}
258
259macro_rules! impl_system_input_tuple {
260 ($(#[$meta:meta])* $($name:ident),*) => {
261 $(#[$meta])*
262 impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {
263 type Param<'i> = ($($name::Param<'i>,)*);
264 type Inner<'i> = ($($name::Inner<'i>,)*);
265
266 #[expect(
267 clippy::allow_attributes,
268 reason = "This is in a macro; as such, the below lints may not always apply."
269 )]
270 #[allow(
271 non_snake_case,
272 reason = "Certain variable names are provided by the caller, not by us."
273 )]
274 #[allow(
275 clippy::unused_unit,
276 reason = "Zero-length tuples won't have anything to wrap."
277 )]
278 fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
279 let ($($name,)*) = this;
280 ($($name::wrap($name),)*)
281 }
282 }
283 };
284}
285
286all_tuples!(
287 #[doc(fake_variadic)]
288 impl_system_input_tuple,
289 0,
290 8,
291 I
292);
293
294#[cfg(test)]
295mod tests {
296 use crate::{
297 system::{In, InMut, InRef, IntoSystem, System},
298 world::World,
299 };
300
301 #[test]
302 fn two_tuple() {
303 fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {
304 a + b
305 }
306 fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {
307 *a + *b
308 }
309 fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
310 *a += b;
311 }
312
313 let mut world = World::new();
314 let mut by_value = IntoSystem::into_system(by_value);
315 let mut by_ref = IntoSystem::into_system(by_ref);
316 let mut by_mut = IntoSystem::into_system(by_mut);
317
318 by_value.initialize(&mut world);
319 by_ref.initialize(&mut world);
320 by_mut.initialize(&mut world);
321
322 let mut a = 12;
323 let b = 24;
324
325 assert_eq!(by_value.run((a, b), &mut world).unwrap(), 36);
326 assert_eq!(by_ref.run((&a, &b), &mut world).unwrap(), 36);
327 by_mut.run((&mut a, b), &mut world).unwrap();
328 assert_eq!(a, 36);
329 }
330}