use core::ops::{Deref, DerefMut};12use variadics_please::all_tuples;34use crate::{bundle::Bundle, event::Event, prelude::On, system::System};56/// Trait for types that can be used as input to [`System`]s.7///8/// Provided implementations are:9/// - `()`: No input10/// - [`In<T>`]: For values11/// - [`InRef<T>`]: For read-only references to values12/// - [`InMut<T>`]: For mutable references to values13/// - [`On<E, B>`]: For [`ObserverSystem`]s14/// - [`StaticSystemInput<I>`]: For arbitrary [`SystemInput`]s in generic contexts15/// - Tuples of [`SystemInput`]s up to 8 elements16///17/// For advanced usecases, you can implement this trait for your own types.18///19/// # Examples20///21/// ## Tuples of [`SystemInput`]s22///23/// ```24/// use bevy_ecs::prelude::*;25///26/// fn add((InMut(a), In(b)): (InMut<usize>, In<usize>)) {27/// *a += b;28/// }29/// # let mut world = World::new();30/// # let mut add = IntoSystem::into_system(add);31/// # add.initialize(&mut world);32/// # let mut a = 12;33/// # let b = 24;34/// # add.run((&mut a, b), &mut world);35/// # assert_eq!(a, 36);36/// ```37///38/// [`ObserverSystem`]: crate::system::ObserverSystem39pub trait SystemInput: Sized {40/// The wrapper input type that is defined as the first argument to [`FunctionSystem`]s.41///42/// [`FunctionSystem`]: crate::system::FunctionSystem43type Param<'i>: SystemInput;44/// The inner input type that is passed to functions that run systems,45/// such as [`System::run`].46///47/// [`System::run`]: crate::system::System::run48type Inner<'i>;4950/// Converts a [`SystemInput::Inner`] into a [`SystemInput::Param`].51fn wrap(this: Self::Inner<'_>) -> Self::Param<'_>;52}5354/// Shorthand way to get the [`System::In`] for a [`System`] as a [`SystemInput::Inner`].55pub type SystemIn<'a, S> = <<S as System>::In as SystemInput>::Inner<'a>;5657/// A [`SystemInput`] type which denotes that a [`System`] receives58/// an input value of type `T` from its caller.59///60/// [`System`]s may take an optional input which they require to be passed to them when they61/// are being [`run`](System::run). For [`FunctionSystem`]s the input may be marked62/// with this `In` type, but only the first param of a function may be tagged as an input. This also63/// means a system can only have one or zero input parameters.64///65/// See [`SystemInput`] to learn more about system inputs in general.66///67/// # Examples68///69/// Here is a simple example of a system that takes a [`usize`] and returns the square of it.70///71/// ```72/// # use bevy_ecs::prelude::*;73/// #74/// fn square(In(input): In<usize>) -> usize {75/// input * input76/// }77///78/// let mut world = World::new();79/// let mut square_system = IntoSystem::into_system(square);80/// square_system.initialize(&mut world);81///82/// assert_eq!(square_system.run(12, &mut world).unwrap(), 144);83/// ```84///85/// [`SystemParam`]: crate::system::SystemParam86/// [`FunctionSystem`]: crate::system::FunctionSystem87#[derive(Debug)]88pub struct In<T>(pub T);8990impl<T: 'static> SystemInput for In<T> {91type Param<'i> = In<T>;92type Inner<'i> = T;9394fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {95In(this)96}97}9899impl<T> Deref for In<T> {100type Target = T;101102fn deref(&self) -> &Self::Target {103&self.0104}105}106107impl<T> DerefMut for In<T> {108fn deref_mut(&mut self) -> &mut Self::Target {109&mut self.0110}111}112113/// A [`SystemInput`] type which denotes that a [`System`] receives114/// a read-only reference to a value of type `T` from its caller.115///116/// This is similar to [`In`] but takes a reference to a value instead of the value itself.117/// See [`InMut`] for the mutable version.118///119/// See [`SystemInput`] to learn more about system inputs in general.120///121/// # Examples122///123/// Here is a simple example of a system that logs the passed in message.124///125/// ```126/// # use bevy_ecs::prelude::*;127/// # use std::fmt::Write as _;128/// #129/// #[derive(Resource, Default)]130/// struct Log(String);131///132/// fn log(InRef(msg): InRef<str>, mut log: ResMut<Log>) {133/// writeln!(log.0, "{}", msg).unwrap();134/// }135///136/// let mut world = World::new();137/// world.init_resource::<Log>();138/// let mut log_system = IntoSystem::into_system(log);139/// log_system.initialize(&mut world);140///141/// log_system.run("Hello, world!", &mut world);142/// # assert_eq!(world.get_resource::<Log>().unwrap().0, "Hello, world!\n");143/// ```144///145/// [`SystemParam`]: crate::system::SystemParam146#[derive(Debug)]147pub struct InRef<'i, T: ?Sized>(pub &'i T);148149impl<T: ?Sized + 'static> SystemInput for InRef<'_, T> {150type Param<'i> = InRef<'i, T>;151type Inner<'i> = &'i T;152153fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {154InRef(this)155}156}157158impl<'i, T: ?Sized> Deref for InRef<'i, T> {159type Target = T;160161fn deref(&self) -> &Self::Target {162self.0163}164}165166/// A [`SystemInput`] type which denotes that a [`System`] receives167/// a mutable reference to a value of type `T` from its caller.168///169/// This is similar to [`In`] but takes a mutable reference to a value instead of the value itself.170/// See [`InRef`] for the read-only version.171///172/// See [`SystemInput`] to learn more about system inputs in general.173///174/// # Examples175///176/// Here is a simple example of a system that takes a `&mut usize` and squares it.177///178/// ```179/// # use bevy_ecs::prelude::*;180/// #181/// fn square(InMut(input): InMut<usize>) {182/// *input *= *input;183/// }184///185/// let mut world = World::new();186/// let mut square_system = IntoSystem::into_system(square);187/// square_system.initialize(&mut world);188///189/// let mut value = 12;190/// square_system.run(&mut value, &mut world);191/// assert_eq!(value, 144);192/// ```193///194/// [`SystemParam`]: crate::system::SystemParam195#[derive(Debug)]196pub struct InMut<'a, T: ?Sized>(pub &'a mut T);197198impl<T: ?Sized + 'static> SystemInput for InMut<'_, T> {199type Param<'i> = InMut<'i, T>;200type Inner<'i> = &'i mut T;201202fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {203InMut(this)204}205}206207impl<'i, T: ?Sized> Deref for InMut<'i, T> {208type Target = T;209210fn deref(&self) -> &Self::Target {211self.0212}213}214215impl<'i, T: ?Sized> DerefMut for InMut<'i, T> {216fn deref_mut(&mut self) -> &mut Self::Target {217self.0218}219}220221/// Used for [`ObserverSystem`]s.222///223/// [`ObserverSystem`]: crate::system::ObserverSystem224impl<E: Event, B: Bundle> SystemInput for On<'_, '_, E, B> {225// Note: the fact that we must use a shared lifetime here is226// a key piece of the complicated safety story documented above227// the `&mut E::Trigger<'_>` cast in `observer_system_runner` and in228// the `On` implementation.229type Param<'i> = On<'i, 'i, E, B>;230type Inner<'i> = On<'i, 'i, E, B>;231232fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {233this234}235}236237/// A helper for using [`SystemInput`]s in generic contexts.238///239/// This type is a [`SystemInput`] adapter which always has240/// `Self::Param == Self` (ignoring lifetimes for brevity),241/// no matter the argument [`SystemInput`] (`I`).242///243/// This makes it useful for having arbitrary [`SystemInput`]s in244/// function systems.245///246/// See [`SystemInput`] to learn more about system inputs in general.247pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);248249impl<'a, I: SystemInput> SystemInput for StaticSystemInput<'a, I> {250type Param<'i> = StaticSystemInput<'i, I>;251type Inner<'i> = I::Inner<'i>;252253fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {254StaticSystemInput(this)255}256}257258macro_rules! impl_system_input_tuple {259($(#[$meta:meta])* $($name:ident),*) => {260$(#[$meta])*261impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {262type Param<'i> = ($($name::Param<'i>,)*);263type Inner<'i> = ($($name::Inner<'i>,)*);264265#[expect(266clippy::allow_attributes,267reason = "This is in a macro; as such, the below lints may not always apply."268)]269#[allow(270non_snake_case,271reason = "Certain variable names are provided by the caller, not by us."272)]273#[allow(274clippy::unused_unit,275reason = "Zero-length tuples won't have anything to wrap."276)]277fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {278let ($($name,)*) = this;279($($name::wrap($name),)*)280}281}282};283}284285all_tuples!(286#[doc(fake_variadic)]287impl_system_input_tuple,2880,2898,290I291);292293#[cfg(test)]294mod tests {295use crate::{296system::{In, InMut, InRef, IntoSystem, System},297world::World,298};299300#[test]301fn two_tuple() {302fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {303a + b304}305fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {306*a + *b307}308fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {309*a += b;310}311312let mut world = World::new();313let mut by_value = IntoSystem::into_system(by_value);314let mut by_ref = IntoSystem::into_system(by_ref);315let mut by_mut = IntoSystem::into_system(by_mut);316317by_value.initialize(&mut world);318by_ref.initialize(&mut world);319by_mut.initialize(&mut world);320321let mut a = 12;322let b = 24;323324assert_eq!(by_value.run((a, b), &mut world).unwrap(), 36);325assert_eq!(by_ref.run((&a, &b), &mut world).unwrap(), 36);326by_mut.run((&mut a, b), &mut world).unwrap();327assert_eq!(a, 36);328}329}330331332