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}