1use core::ops::{Deref, DerefMut};
23use variadics_please::all_tuples;
45use crate::{event::EventPattern, prelude::On, system::System};
67/// 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/// - `Option<I>`: For optional inputs of some [`SystemInput`] `I`
17/// - Tuples of [`SystemInput`]s up to 8 elements
18///
19/// For advanced usecases, you can implement this trait for your own types.
20///
21/// # Examples
22///
23/// ## Tuples of [`SystemInput`]s
24///
25/// ```
26/// use bevy_ecs::prelude::*;
27///
28/// fn add((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
29/// *a += b;
30/// }
31/// # let mut world = World::new();
32/// # let mut add = IntoSystem::into_system(add);
33/// # add.initialize(&mut world);
34/// # let mut a = 12;
35/// # let b = 24;
36/// # add.run((&mut a, b), &mut world);
37/// # assert_eq!(a, 36);
38/// ```
39///
40/// [`ObserverSystem`]: crate::system::ObserverSystem
41pub trait SystemInput: Sized {
42/// The wrapper input type that is defined as the first argument to [`FunctionSystem`]s.
43 ///
44 /// [`FunctionSystem`]: crate::system::FunctionSystem
45type Param<'i>: SystemInput;
46/// The inner input type that is passed to functions that run systems,
47 /// such as [`System::run`].
48 ///
49 /// [`System::run`]: crate::system::System::run
50type Inner<'i>;
5152/// Converts a [`SystemInput::Inner`] into a [`SystemInput::Param`].
53fn wrap(this: Self::Inner<'_>) -> Self::Param<'_>;
54}
5556/// Shorthand way to get the [`System::In`] for a [`System`] as a [`SystemInput::Inner`].
57pub type SystemIn<'a, S> = <<S as System>::Inas SystemInput>::Inner<'a>;
5859/// A type that may be constructed from the input of a [`System`].
60/// This is used to allow systems whose first parameter is a `StaticSystemInput<In>`
61/// to take an `In` as input, and can be implemented for user types to allow
62/// similar conversions.
63pub trait FromInput<In: SystemInput>: SystemInput {
64/// Converts the system input's inner representation into this type's
65 /// inner representation.
66fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i>;
67}
6869impl<In: SystemInput> FromInput<In> for In {
70#[inline]
71fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {
72inner73 }
74}
7576impl<'a, In: SystemInput> FromInput<In> for StaticSystemInput<'a, In> {
77#[inline]
78fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {
79inner80 }
81}
8283/// A [`SystemInput`] type which denotes that a [`System`] receives
84/// an input value of type `T` from its caller.
85///
86/// [`System`]s may take an optional input which they require to be passed to them when they
87/// are being [`run`](System::run). For [`FunctionSystem`]s the input may be marked
88/// with this `In` type, but only the first param of a function may be tagged as an input. This also
89/// means a system can only have one or zero input parameters.
90///
91/// See [`SystemInput`] to learn more about system inputs in general.
92///
93/// # Examples
94///
95/// Here is a simple example of a system that takes a [`usize`] and returns the square of it.
96///
97/// ```
98/// # use bevy_ecs::prelude::*;
99/// #
100/// fn square(In(input): In<usize>) -> usize {
101/// input * input
102/// }
103///
104/// let mut world = World::new();
105/// let mut square_system = IntoSystem::into_system(square);
106/// square_system.initialize(&mut world);
107///
108/// assert_eq!(square_system.run(12, &mut world).unwrap(), 144);
109/// ```
110///
111/// [`SystemParam`]: crate::system::SystemParam
112/// [`FunctionSystem`]: crate::system::FunctionSystem
113#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for In<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "In", &&self.0)
}
}Debug)]
114pub struct In<T>(pub T);
115116impl<T: 'static> SystemInputfor In<T> {
117type Param<'i> = In<T>;
118type Inner<'i> = T;
119120fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
121In(this)
122 }
123}
124125impl<T> Dereffor In<T> {
126type Target = T;
127128fn deref(&self) -> &Self::Target {
129&self.0
130}
131}
132133impl<T> DerefMutfor In<T> {
134fn deref_mut(&mut self) -> &mut Self::Target {
135&mut self.0
136}
137}
138139/// A [`SystemInput`] type which denotes that a [`System`] receives
140/// a read-only reference to a value of type `T` from its caller.
141///
142/// This is similar to [`In`] but takes a reference to a value instead of the value itself.
143/// See [`InMut`] for the mutable version.
144///
145/// See [`SystemInput`] to learn more about system inputs in general.
146///
147/// # Examples
148///
149/// Here is a simple example of a system that logs the passed in message.
150///
151/// ```
152/// # use bevy_ecs::prelude::*;
153/// # use std::fmt::Write as _;
154/// #
155/// #[derive(Resource, Default)]
156/// struct Log(String);
157///
158/// fn log(InRef(msg): InRef<str>, mut log: ResMut<Log>) {
159/// writeln!(log.0, "{}", msg).unwrap();
160/// }
161///
162/// let mut world = World::new();
163/// world.init_resource::<Log>();
164/// let mut log_system = IntoSystem::into_system(log);
165/// log_system.initialize(&mut world);
166///
167/// log_system.run("Hello, world!", &mut world);
168/// # assert_eq!(world.get_resource::<Log>().unwrap().0, "Hello, world!\n");
169/// ```
170///
171/// [`SystemParam`]: crate::system::SystemParam
172#[derive(#[automatically_derived]
impl<'i, T: ::core::fmt::Debug + ?Sized> ::core::fmt::Debug for InRef<'i, T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "InRef",
&&self.0)
}
}Debug)]
173pub struct InRef<'i, T: ?Sized>(pub &'i T);
174175impl<T: ?Sized + 'static> SystemInputfor InRef<'_, T> {
176type Param<'i> = InRef<'i, T>;
177type Inner<'i> = &'i T;
178179fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
180InRef(this)
181 }
182}
183184impl<'i, T: ?Sized> Dereffor InRef<'i, T> {
185type Target = T;
186187fn deref(&self) -> &Self::Target {
188self.0
189}
190}
191192/// A [`SystemInput`] type which denotes that a [`System`] receives
193/// a mutable reference to a value of type `T` from its caller.
194///
195/// This is similar to [`In`] but takes a mutable reference to a value instead of the value itself.
196/// See [`InRef`] for the read-only version.
197///
198/// See [`SystemInput`] to learn more about system inputs in general.
199///
200/// # Examples
201///
202/// Here is a simple example of a system that takes a `&mut usize` and squares it.
203///
204/// ```
205/// # use bevy_ecs::prelude::*;
206/// #
207/// fn square(InMut(input): InMut<usize>) {
208/// *input *= *input;
209/// }
210///
211/// let mut world = World::new();
212/// let mut square_system = IntoSystem::into_system(square);
213/// square_system.initialize(&mut world);
214///
215/// let mut value = 12;
216/// square_system.run(&mut value, &mut world);
217/// assert_eq!(value, 144);
218/// ```
219///
220/// [`SystemParam`]: crate::system::SystemParam
221#[derive(#[automatically_derived]
impl<'a, T: ::core::fmt::Debug + ?Sized> ::core::fmt::Debug for InMut<'a, T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "InMut",
&&self.0)
}
}Debug)]
222pub struct InMut<'a, T: ?Sized>(pub &'a mut T);
223224impl<T: ?Sized + 'static> SystemInputfor InMut<'_, T> {
225type Param<'i> = InMut<'i, T>;
226type Inner<'i> = &'i mut T;
227228fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
229InMut(this)
230 }
231}
232233impl<'i, T: ?Sized> Dereffor InMut<'i, T> {
234type Target = T;
235236fn deref(&self) -> &Self::Target {
237self.0
238}
239}
240241impl<'i, T: ?Sized> DerefMutfor InMut<'i, T> {
242fn deref_mut(&mut self) -> &mut Self::Target {
243self.0
244}
245}
246247/// Used for [`ObserverSystem`]s.
248///
249/// [`ObserverSystem`]: crate::system::ObserverSystem
250impl<E: EventPattern> SystemInputfor On<'_, '_, E> {
251// Note: the fact that we must use a shared lifetime here is
252 // a key piece of the complicated safety story documented above
253 // the `&mut E::Trigger<'_>` cast in `observer_system_runner` and in
254 // the `On` implementation.
255type Param<'i> = On<'i, 'i, E>;
256type Inner<'i> = On<'i, 'i, E>;
257258fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
259this260 }
261}
262263/// A helper for using [`SystemInput`]s in generic contexts.
264///
265/// This type is a [`SystemInput`] adapter which always has
266/// `Self::Param == Self` (ignoring lifetimes for brevity),
267/// no matter the argument [`SystemInput`] (`I`).
268///
269/// This makes it useful for having arbitrary [`SystemInput`]s in
270/// function systems.
271///
272/// See [`SystemInput`] to learn more about system inputs in general.
273pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);
274275impl<'a, I: SystemInput> SystemInputfor StaticSystemInput<'a, I> {
276type Param<'i> = StaticSystemInput<'i, I>;
277type Inner<'i> = I::Inner<'i>;
278279fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
280StaticSystemInput(this)
281 }
282}
283284impl<I: SystemInput> SystemInputfor Option<I> {
285type Param<'i> = Option<I::Param<'i>>;
286type Inner<'i> = Option<I::Inner<'i>>;
287288fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
289this.map(I::wrap)
290 }
291}
292293macro_rules! impl_system_input_tuple {
294 ($(#[$meta:meta])* $($name:ident),*) => {
295 $(#[$meta])*
296impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {
297type Param<'i> = ($($name::Param<'i>,)*);
298type Inner<'i> = ($($name::Inner<'i>,)*);
299300#[expect(
301 clippy::allow_attributes,
302 reason = "This is in a macro; as such, the below lints may not always apply."
303)]
304 #[allow(
305 non_snake_case,
306 reason = "Certain variable names are provided by the caller, not by us."
307)]
308 #[allow(
309 clippy::unused_unit,
310 reason = "Zero-length tuples won't have anything to wrap."
311)]
312fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
313let ($($name,)*) = this;
314 ($($name::wrap($name),)*)
315 }
316 }
317 };
318}
319320#[doc(hidden)]
impl<I0: SystemInput, I1: SystemInput, I2: SystemInput, I3: SystemInput,
I4: SystemInput, I5: SystemInput, I6: SystemInput, I7: SystemInput>
SystemInput for (I0, I1, I2, I3, I4, I5, I6, I7) {
type Param<'i> =
(I0::Param<'i>, I1::Param<'i>, I2::Param<'i>, I3::Param<'i>,
I4::Param<'i>, I5::Param<'i>, I6::Param<'i>, I7::Param<'i>);
type Inner<'i> =
(I0::Inner<'i>, I1::Inner<'i>, I2::Inner<'i>, I3::Inner<'i>,
I4::Inner<'i>, I5::Inner<'i>, I6::Inner<'i>, I7::Inner<'i>);
#[expect(clippy :: allow_attributes, reason =
"This is in a macro; as such, the below lints may not always apply.")]
#[allow(non_snake_case, reason =
"Certain variable names are provided by the caller, not by us.")]
#[allow(clippy :: unused_unit, reason =
"Zero-length tuples won't have anything to wrap.")]
fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {
let (I0, I1, I2, I3, I4, I5, I6, I7) = this;
(I0::wrap(I0), I1::wrap(I1), I2::wrap(I2), I3::wrap(I3), I4::wrap(I4),
I5::wrap(I5), I6::wrap(I6), I7::wrap(I7))
}
}all_tuples!(
321#[doc(fake_variadic)]
322impl_system_input_tuple,
3230,
3248,
325 I
326);
327328#[cfg(test)]
329mod tests {
330use crate::{
331 system::{assert_is_system, In, InMut, InRef, IntoSystem, StaticSystemInput, System},
332 world::World,
333 };
334335#[test]
336fn two_tuple() {
337fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {
338 a + b
339 }
340fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {
341*a + *b
342 }
343fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {
344*a += b;
345 }
346347let mut world = World::new();
348let mut by_value = IntoSystem::into_system(by_value);
349let mut by_ref = IntoSystem::into_system(by_ref);
350let mut by_mut = IntoSystem::into_system(by_mut);
351352 by_value.initialize(&mut world);
353 by_ref.initialize(&mut world);
354 by_mut.initialize(&mut world);
355356let mut a = 12;
357let b = 24;
358359assert_eq!(by_value.run((a, b), &mut world).unwrap(), 36);
360assert_eq!(by_ref.run((&a, &b), &mut world).unwrap(), 36);
361 by_mut.run((&mut a, b), &mut world).unwrap();
362assert_eq!(a, 36);
363 }
364365#[test]
366fn compatible_input() {
367fn takes_usize(In(a): In<usize>) -> usize {
368 a
369 }
370371fn takes_static_usize(StaticSystemInput(b): StaticSystemInput<In<usize>>) -> usize {
372 b
373 }
374375 assert_is_system::<In<usize>, usize, _>(takes_usize);
376// test if StaticSystemInput is compatible with its inner type
377assert_is_system::<In<usize>, usize, _>(takes_static_usize);
378 }
379380#[test]
381fn option_input() {
382fn takes_option_mut(a: Option<InMut<usize>>) -> usize {
383 a.map(|InMut(x)| *x).unwrap_or(0)
384 }
385386let mut world = World::new();
387388let mut system = IntoSystem::into_system(takes_option_mut);
389 system.initialize(&mut world);
390391let mut value = 12;
392assert_eq!(system.run(Some(&mut value), &mut world).unwrap(), 12);
393assert_eq!(system.run(None, &mut world).unwrap(), 0);
394 }
395}