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 type that may be constructed from the input of a [`System`].58/// This is used to allow systems whose first parameter is a `StaticSystemInput<In>`59/// to take an `In` as input, and can be implemented for user types to allow60/// similar conversions.61pub trait FromInput<In: SystemInput>: SystemInput {62/// Converts the system input's inner representation into this type's63/// inner representation.64fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i>;65}6667impl<In: SystemInput> FromInput<In> for In {68#[inline]69fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {70inner71}72}7374impl<'a, In: SystemInput> FromInput<In> for StaticSystemInput<'a, In> {75#[inline]76fn from_inner<'i>(inner: In::Inner<'i>) -> Self::Inner<'i> {77inner78}79}8081/// A [`SystemInput`] type which denotes that a [`System`] receives82/// an input value of type `T` from its caller.83///84/// [`System`]s may take an optional input which they require to be passed to them when they85/// are being [`run`](System::run). For [`FunctionSystem`]s the input may be marked86/// with this `In` type, but only the first param of a function may be tagged as an input. This also87/// means a system can only have one or zero input parameters.88///89/// See [`SystemInput`] to learn more about system inputs in general.90///91/// # Examples92///93/// Here is a simple example of a system that takes a [`usize`] and returns the square of it.94///95/// ```96/// # use bevy_ecs::prelude::*;97/// #98/// fn square(In(input): In<usize>) -> usize {99/// input * input100/// }101///102/// let mut world = World::new();103/// let mut square_system = IntoSystem::into_system(square);104/// square_system.initialize(&mut world);105///106/// assert_eq!(square_system.run(12, &mut world).unwrap(), 144);107/// ```108///109/// [`SystemParam`]: crate::system::SystemParam110/// [`FunctionSystem`]: crate::system::FunctionSystem111#[derive(Debug)]112pub struct In<T>(pub T);113114impl<T: 'static> SystemInput for In<T> {115type Param<'i> = In<T>;116type Inner<'i> = T;117118fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {119In(this)120}121}122123impl<T> Deref for In<T> {124type Target = T;125126fn deref(&self) -> &Self::Target {127&self.0128}129}130131impl<T> DerefMut for In<T> {132fn deref_mut(&mut self) -> &mut Self::Target {133&mut self.0134}135}136137/// A [`SystemInput`] type which denotes that a [`System`] receives138/// a read-only reference to a value of type `T` from its caller.139///140/// This is similar to [`In`] but takes a reference to a value instead of the value itself.141/// See [`InMut`] for the mutable version.142///143/// See [`SystemInput`] to learn more about system inputs in general.144///145/// # Examples146///147/// Here is a simple example of a system that logs the passed in message.148///149/// ```150/// # use bevy_ecs::prelude::*;151/// # use std::fmt::Write as _;152/// #153/// #[derive(Resource, Default)]154/// struct Log(String);155///156/// fn log(InRef(msg): InRef<str>, mut log: ResMut<Log>) {157/// writeln!(log.0, "{}", msg).unwrap();158/// }159///160/// let mut world = World::new();161/// world.init_resource::<Log>();162/// let mut log_system = IntoSystem::into_system(log);163/// log_system.initialize(&mut world);164///165/// log_system.run("Hello, world!", &mut world);166/// # assert_eq!(world.get_resource::<Log>().unwrap().0, "Hello, world!\n");167/// ```168///169/// [`SystemParam`]: crate::system::SystemParam170#[derive(Debug)]171pub struct InRef<'i, T: ?Sized>(pub &'i T);172173impl<T: ?Sized + 'static> SystemInput for InRef<'_, T> {174type Param<'i> = InRef<'i, T>;175type Inner<'i> = &'i T;176177fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {178InRef(this)179}180}181182impl<'i, T: ?Sized> Deref for InRef<'i, T> {183type Target = T;184185fn deref(&self) -> &Self::Target {186self.0187}188}189190/// A [`SystemInput`] type which denotes that a [`System`] receives191/// a mutable reference to a value of type `T` from its caller.192///193/// This is similar to [`In`] but takes a mutable reference to a value instead of the value itself.194/// See [`InRef`] for the read-only version.195///196/// See [`SystemInput`] to learn more about system inputs in general.197///198/// # Examples199///200/// Here is a simple example of a system that takes a `&mut usize` and squares it.201///202/// ```203/// # use bevy_ecs::prelude::*;204/// #205/// fn square(InMut(input): InMut<usize>) {206/// *input *= *input;207/// }208///209/// let mut world = World::new();210/// let mut square_system = IntoSystem::into_system(square);211/// square_system.initialize(&mut world);212///213/// let mut value = 12;214/// square_system.run(&mut value, &mut world);215/// assert_eq!(value, 144);216/// ```217///218/// [`SystemParam`]: crate::system::SystemParam219#[derive(Debug)]220pub struct InMut<'a, T: ?Sized>(pub &'a mut T);221222impl<T: ?Sized + 'static> SystemInput for InMut<'_, T> {223type Param<'i> = InMut<'i, T>;224type Inner<'i> = &'i mut T;225226fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {227InMut(this)228}229}230231impl<'i, T: ?Sized> Deref for InMut<'i, T> {232type Target = T;233234fn deref(&self) -> &Self::Target {235self.0236}237}238239impl<'i, T: ?Sized> DerefMut for InMut<'i, T> {240fn deref_mut(&mut self) -> &mut Self::Target {241self.0242}243}244245/// Used for [`ObserverSystem`]s.246///247/// [`ObserverSystem`]: crate::system::ObserverSystem248impl<E: Event, B: Bundle> SystemInput for On<'_, '_, E, B> {249// Note: the fact that we must use a shared lifetime here is250// a key piece of the complicated safety story documented above251// the `&mut E::Trigger<'_>` cast in `observer_system_runner` and in252// the `On` implementation.253type Param<'i> = On<'i, 'i, E, B>;254type Inner<'i> = On<'i, 'i, E, B>;255256fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {257this258}259}260261/// A helper for using [`SystemInput`]s in generic contexts.262///263/// This type is a [`SystemInput`] adapter which always has264/// `Self::Param == Self` (ignoring lifetimes for brevity),265/// no matter the argument [`SystemInput`] (`I`).266///267/// This makes it useful for having arbitrary [`SystemInput`]s in268/// function systems.269///270/// See [`SystemInput`] to learn more about system inputs in general.271pub struct StaticSystemInput<'a, I: SystemInput>(pub I::Inner<'a>);272273impl<'a, I: SystemInput> SystemInput for StaticSystemInput<'a, I> {274type Param<'i> = StaticSystemInput<'i, I>;275type Inner<'i> = I::Inner<'i>;276277fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {278StaticSystemInput(this)279}280}281282macro_rules! impl_system_input_tuple {283($(#[$meta:meta])* $($name:ident),*) => {284$(#[$meta])*285impl<$($name: SystemInput),*> SystemInput for ($($name,)*) {286type Param<'i> = ($($name::Param<'i>,)*);287type Inner<'i> = ($($name::Inner<'i>,)*);288289#[expect(290clippy::allow_attributes,291reason = "This is in a macro; as such, the below lints may not always apply."292)]293#[allow(294non_snake_case,295reason = "Certain variable names are provided by the caller, not by us."296)]297#[allow(298clippy::unused_unit,299reason = "Zero-length tuples won't have anything to wrap."300)]301fn wrap(this: Self::Inner<'_>) -> Self::Param<'_> {302let ($($name,)*) = this;303($($name::wrap($name),)*)304}305}306};307}308309all_tuples!(310#[doc(fake_variadic)]311impl_system_input_tuple,3120,3138,314I315);316317#[cfg(test)]318mod tests {319use crate::{320system::{assert_is_system, In, InMut, InRef, IntoSystem, StaticSystemInput, System},321world::World,322};323324#[test]325fn two_tuple() {326fn by_value((In(a), In(b)): (In<usize>, In<usize>)) -> usize {327a + b328}329fn by_ref((InRef(a), InRef(b)): (InRef<usize>, InRef<usize>)) -> usize {330*a + *b331}332fn by_mut((InMut(a), In(b)): (InMut<usize>, In<usize>)) {333*a += b;334}335336let mut world = World::new();337let mut by_value = IntoSystem::into_system(by_value);338let mut by_ref = IntoSystem::into_system(by_ref);339let mut by_mut = IntoSystem::into_system(by_mut);340341by_value.initialize(&mut world);342by_ref.initialize(&mut world);343by_mut.initialize(&mut world);344345let mut a = 12;346let b = 24;347348assert_eq!(by_value.run((a, b), &mut world).unwrap(), 36);349assert_eq!(by_ref.run((&a, &b), &mut world).unwrap(), 36);350by_mut.run((&mut a, b), &mut world).unwrap();351assert_eq!(a, 36);352}353354#[test]355fn compatible_input() {356fn takes_usize(In(a): In<usize>) -> usize {357a358}359360fn takes_static_usize(StaticSystemInput(b): StaticSystemInput<In<usize>>) -> usize {361b362}363364assert_is_system::<In<usize>, usize, _>(takes_usize);365// test if StaticSystemInput is compatible with its inner type366assert_is_system::<In<usize>, usize, _>(takes_static_usize);367}368}369370371