Path: blob/main/crates/bevy_ecs/src/system/function_system.rs
6604 views
use crate::{1component::{CheckChangeTicks, Tick},2error::{BevyError, Result},3never::Never,4prelude::FromWorld,5query::FilteredAccessSet,6schedule::{InternedSystemSet, SystemSet},7system::{8check_system_change_tick, ReadOnlySystemParam, System, SystemIn, SystemInput, SystemParam,9SystemParamItem,10},11world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World, WorldId},12};1314use alloc::{borrow::Cow, vec, vec::Vec};15use bevy_utils::prelude::DebugName;16use core::marker::PhantomData;17use variadics_please::all_tuples;1819#[cfg(feature = "trace")]20use tracing::{info_span, Span};2122use super::{23IntoSystem, ReadOnlySystem, RunSystemError, SystemParamBuilder, SystemParamValidationError,24SystemStateFlags,25};2627/// The metadata of a [`System`].28#[derive(Clone)]29pub struct SystemMeta {30pub(crate) name: DebugName,31// NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent32// SystemParams from overriding each other33flags: SystemStateFlags,34pub(crate) last_run: Tick,35#[cfg(feature = "trace")]36pub(crate) system_span: Span,37#[cfg(feature = "trace")]38pub(crate) commands_span: Span,39}4041impl SystemMeta {42pub(crate) fn new<T>() -> Self {43let name = DebugName::type_name::<T>();44Self {45// These spans are initialized during plugin build, so we set the parent to `None` to prevent46// them from being children of the span that is measuring the plugin build time.47#[cfg(feature = "trace")]48system_span: info_span!(parent: None, "system", name = name.clone().as_string()),49#[cfg(feature = "trace")]50commands_span: info_span!(parent: None, "system_commands", name = name.clone().as_string()),51name,52flags: SystemStateFlags::empty(),53last_run: Tick::new(0),54}55}5657/// Returns the system's name58#[inline]59pub fn name(&self) -> &DebugName {60&self.name61}6263/// Sets the name of this system.64///65/// Useful to give closure systems more readable and unique names for debugging and tracing.66#[inline]67pub fn set_name(&mut self, new_name: impl Into<Cow<'static, str>>) {68let new_name: Cow<'static, str> = new_name.into();69#[cfg(feature = "trace")]70{71let name = new_name.as_ref();72self.system_span = info_span!(parent: None, "system", name = name);73self.commands_span = info_span!(parent: None, "system_commands", name = name);74}75self.name = new_name.into();76}7778/// Returns true if the system is [`Send`].79#[inline]80pub fn is_send(&self) -> bool {81!self.flags.intersects(SystemStateFlags::NON_SEND)82}8384/// Sets the system to be not [`Send`].85///86/// This is irreversible.87#[inline]88pub fn set_non_send(&mut self) {89self.flags |= SystemStateFlags::NON_SEND;90}9192/// Returns true if the system has deferred [`SystemParam`]'s93#[inline]94pub fn has_deferred(&self) -> bool {95self.flags.intersects(SystemStateFlags::DEFERRED)96}9798/// Marks the system as having deferred buffers like [`Commands`](`super::Commands`)99/// This lets the scheduler insert [`ApplyDeferred`](`crate::prelude::ApplyDeferred`) systems automatically.100#[inline]101pub fn set_has_deferred(&mut self) {102self.flags |= SystemStateFlags::DEFERRED;103}104}105106// TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference107// (to avoid the need for unwrapping to retrieve SystemMeta)108/// Holds on to persistent state required to drive [`SystemParam`] for a [`System`].109///110/// This is a powerful and convenient tool for working with exclusive world access,111/// allowing you to fetch data from the [`World`] as if you were running a [`System`].112/// However, simply calling `world::run_system(my_system)` using a [`World::run_system`](World::run_system)113/// can be significantly simpler and ensures that change detection and command flushing work as expected.114///115/// Borrow-checking is handled for you, allowing you to mutably access multiple compatible system parameters at once,116/// and arbitrary system parameters (like [`EventWriter`](crate::event::EventWriter)) can be conveniently fetched.117///118/// For an alternative approach to split mutable access to the world, see [`World::resource_scope`].119///120/// # Warning121///122/// [`SystemState`] values created can be cached to improve performance,123/// and *must* be cached and reused in order for system parameters that rely on local state to work correctly.124/// These include:125/// - [`Added`](crate::query::Added), [`Changed`](crate::query::Changed) and [`Spawned`](crate::query::Spawned) query filters126/// - [`Local`](crate::system::Local) variables that hold state127/// - [`EventReader`](crate::event::EventReader) system parameters, which rely on a [`Local`](crate::system::Local) to track which events have been seen128///129/// Note that this is automatically handled for you when using a [`World::run_system`](World::run_system).130///131/// # Example132///133/// Basic usage:134/// ```135/// # use bevy_ecs::prelude::*;136/// # use bevy_ecs::system::SystemState;137/// # use bevy_ecs::event::Events;138/// #139/// # #[derive(BufferedEvent)]140/// # struct MyEvent;141/// # #[derive(Resource)]142/// # struct MyResource(u32);143/// #144/// # #[derive(Component)]145/// # struct MyComponent;146/// #147/// // Work directly on the `World`148/// let mut world = World::new();149/// world.init_resource::<Events<MyEvent>>();150///151/// // Construct a `SystemState` struct, passing in a tuple of `SystemParam`152/// // as if you were writing an ordinary system.153/// let mut system_state: SystemState<(154/// EventWriter<MyEvent>,155/// Option<ResMut<MyResource>>,156/// Query<&MyComponent>,157/// )> = SystemState::new(&mut world);158///159/// // Use system_state.get_mut(&mut world) and unpack your system parameters into variables!160/// // system_state.get(&world) provides read-only versions of your system parameters instead.161/// let (event_writer, maybe_resource, query) = system_state.get_mut(&mut world);162///163/// // If you are using `Commands`, you can choose when you want to apply them to the world.164/// // You need to manually call `.apply(world)` on the `SystemState` to apply them.165/// ```166/// Caching:167/// ```168/// # use bevy_ecs::prelude::*;169/// # use bevy_ecs::system::SystemState;170/// # use bevy_ecs::event::Events;171/// #172/// # #[derive(BufferedEvent)]173/// # struct MyEvent;174/// #[derive(Resource)]175/// struct CachedSystemState {176/// event_state: SystemState<EventReader<'static, 'static, MyEvent>>,177/// }178///179/// // Create and store a system state once180/// let mut world = World::new();181/// world.init_resource::<Events<MyEvent>>();182/// let initial_state: SystemState<EventReader<MyEvent>> = SystemState::new(&mut world);183///184/// // The system state is cached in a resource185/// world.insert_resource(CachedSystemState {186/// event_state: initial_state,187/// });188///189/// // Later, fetch the cached system state, saving on overhead190/// world.resource_scope(|world, mut cached_state: Mut<CachedSystemState>| {191/// let mut event_reader = cached_state.event_state.get_mut(world);192///193/// for events in event_reader.read() {194/// println!("Hello World!");195/// }196/// });197/// ```198/// Exclusive System:199/// ```200/// # use bevy_ecs::prelude::*;201/// # use bevy_ecs::system::SystemState;202/// #203/// # #[derive(BufferedEvent)]204/// # struct MyEvent;205/// #206/// fn exclusive_system(world: &mut World, system_state: &mut SystemState<EventReader<MyEvent>>) {207/// let mut event_reader = system_state.get_mut(world);208///209/// for events in event_reader.read() {210/// println!("Hello World!");211/// }212/// }213/// ```214pub struct SystemState<Param: SystemParam + 'static> {215meta: SystemMeta,216param_state: Param::State,217world_id: WorldId,218}219220// Allow closure arguments to be inferred.221// For a closure to be used as a `SystemParamFunction`, it needs to be generic in any `'w` or `'s` lifetimes.222// Rust will only infer a closure to be generic over lifetimes if it's passed to a function with a Fn constraint.223// So, generate a function for each arity with an explicit `FnMut` constraint to enable higher-order lifetimes,224// along with a regular `SystemParamFunction` constraint to allow the system to be built.225macro_rules! impl_build_system {226($(#[$meta:meta])* $($param: ident),*) => {227$(#[$meta])*228impl<$($param: SystemParam),*> SystemState<($($param,)*)> {229/// Create a [`FunctionSystem`] from a [`SystemState`].230/// This method signature allows type inference of closure parameters for a system with no input.231/// You can use [`SystemState::build_system_with_input()`] if you have input, or [`SystemState::build_any_system()`] if you don't need type inference.232pub fn build_system<233InnerOut: IntoResult<Out>,234Out: 'static,235Marker,236F: FnMut($(SystemParamItem<$param>),*) -> InnerOut237+ SystemParamFunction<Marker, Param = ($($param,)*), In = (), Out = InnerOut>238>239(240self,241func: F,242) -> FunctionSystem<Marker, Out, F>243{244self.build_any_system(func)245}246247/// Create a [`FunctionSystem`] from a [`SystemState`].248/// This method signature allows type inference of closure parameters for a system with input.249/// You can use [`SystemState::build_system()`] if you have no input, or [`SystemState::build_any_system()`] if you don't need type inference.250pub fn build_system_with_input<251Input: SystemInput,252InnerOut: IntoResult<Out>,253Out: 'static,254Marker,255F: FnMut(Input, $(SystemParamItem<$param>),*) -> InnerOut256+ SystemParamFunction<Marker, Param = ($($param,)*), In = Input, Out = InnerOut>,257>(258self,259func: F,260) -> FunctionSystem<Marker, Out, F> {261self.build_any_system(func)262}263}264}265}266267all_tuples!(268#[doc(fake_variadic)]269impl_build_system,2700,27116,272P273);274275impl<Param: SystemParam> SystemState<Param> {276/// Creates a new [`SystemState`] with default state.277pub fn new(world: &mut World) -> Self {278let mut meta = SystemMeta::new::<Param>();279meta.last_run = world.change_tick().relative_to(Tick::MAX);280let param_state = Param::init_state(world);281let mut component_access_set = FilteredAccessSet::new();282// We need to call `init_access` to ensure there are no panics from conflicts within `Param`,283// even though we don't use the calculated access.284Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);285Self {286meta,287param_state,288world_id: world.id(),289}290}291292/// Create a [`SystemState`] from a [`SystemParamBuilder`]293pub(crate) fn from_builder(world: &mut World, builder: impl SystemParamBuilder<Param>) -> Self {294let mut meta = SystemMeta::new::<Param>();295meta.last_run = world.change_tick().relative_to(Tick::MAX);296let param_state = builder.build(world);297let mut component_access_set = FilteredAccessSet::new();298// We need to call `init_access` to ensure there are no panics from conflicts within `Param`,299// even though we don't use the calculated access.300Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);301Self {302meta,303param_state,304world_id: world.id(),305}306}307308/// Create a [`FunctionSystem`] from a [`SystemState`].309/// This method signature allows any system function, but the compiler will not perform type inference on closure parameters.310/// You can use [`SystemState::build_system()`] or [`SystemState::build_system_with_input()`] to get type inference on parameters.311pub fn build_any_system<Marker, Out, F>(self, func: F) -> FunctionSystem<Marker, Out, F>312where313F: SystemParamFunction<Marker, Param = Param, Out: IntoResult<Out>>,314{315FunctionSystem {316func,317#[cfg(feature = "hotpatching")]318current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)319.ptr_address(),320state: Some(FunctionSystemState {321param: self.param_state,322world_id: self.world_id,323}),324system_meta: self.meta,325marker: PhantomData,326}327}328329/// Gets the metadata for this instance.330#[inline]331pub fn meta(&self) -> &SystemMeta {332&self.meta333}334335/// Gets the metadata for this instance.336#[inline]337pub fn meta_mut(&mut self) -> &mut SystemMeta {338&mut self.meta339}340341/// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.342#[inline]343pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>344where345Param: ReadOnlySystemParam,346{347self.validate_world(world.id());348// SAFETY: Param is read-only and doesn't allow mutable access to World.349// It also matches the World this SystemState was created with.350unsafe { self.get_unchecked(world.as_unsafe_world_cell_readonly()) }351}352353/// Retrieve the mutable [`SystemParam`] values.354#[inline]355pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {356self.validate_world(world.id());357// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.358unsafe { self.get_unchecked(world.as_unsafe_world_cell()) }359}360361/// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up362/// by a [`Commands`](`super::Commands`) parameter to the given [`World`].363/// This function should be called manually after the values returned by [`SystemState::get`] and [`SystemState::get_mut`]364/// are finished being used.365pub fn apply(&mut self, world: &mut World) {366Param::apply(&mut self.param_state, &self.meta, world);367}368369/// Wrapper over [`SystemParam::validate_param`].370///371/// # Safety372///373/// - The passed [`UnsafeWorldCell`] must have read-only access to374/// world data in `component_access_set`.375/// - `world` must be the same [`World`] that was used to initialize [`state`](SystemParam::init_state).376pub unsafe fn validate_param(377state: &mut Self,378world: UnsafeWorldCell,379) -> Result<(), SystemParamValidationError> {380// SAFETY: Delegated to existing `SystemParam` implementations.381unsafe { Param::validate_param(&mut state.param_state, &state.meta, world) }382}383384/// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].385/// Otherwise, this returns false.386#[inline]387pub fn matches_world(&self, world_id: WorldId) -> bool {388self.world_id == world_id389}390391/// Asserts that the [`SystemState`] matches the provided world.392#[inline]393#[track_caller]394fn validate_world(&self, world_id: WorldId) {395#[inline(never)]396#[track_caller]397#[cold]398fn panic_mismatched(this: WorldId, other: WorldId) -> ! {399panic!("Encountered a mismatched World. This SystemState was created from {this:?}, but a method was called using {other:?}.");400}401402if !self.matches_world(world_id) {403panic_mismatched(self.world_id, world_id);404}405}406407/// Has no effect408#[inline]409#[deprecated(410since = "0.17.0",411note = "No longer has any effect. Calls may be removed."412)]413pub fn update_archetypes(&mut self, _world: &World) {}414415/// Has no effect416#[inline]417#[deprecated(418since = "0.17.0",419note = "No longer has any effect. Calls may be removed."420)]421pub fn update_archetypes_unsafe_world_cell(&mut self, _world: UnsafeWorldCell) {}422423/// Identical to [`SystemState::get`].424#[inline]425#[deprecated(since = "0.17.0", note = "Call `SystemState::get` instead.")]426pub fn get_manual<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>427where428Param: ReadOnlySystemParam,429{430self.get(world)431}432433/// Identical to [`SystemState::get_mut`].434#[inline]435#[deprecated(since = "0.17.0", note = "Call `SystemState::get_mut` instead.")]436pub fn get_manual_mut<'w, 's>(437&'s mut self,438world: &'w mut World,439) -> SystemParamItem<'w, 's, Param> {440self.get_mut(world)441}442443/// Identical to [`SystemState::get_unchecked`].444///445/// # Safety446/// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data447/// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was448/// created with.449#[inline]450#[deprecated(since = "0.17.0", note = "Call `SystemState::get_unchecked` instead.")]451pub unsafe fn get_unchecked_manual<'w, 's>(452&'s mut self,453world: UnsafeWorldCell<'w>,454) -> SystemParamItem<'w, 's, Param> {455// SAFETY: Caller ensures safety requirements456unsafe { self.get_unchecked(world) }457}458459/// Retrieve the [`SystemParam`] values.460///461/// # Safety462/// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data463/// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was464/// created with.465#[inline]466pub unsafe fn get_unchecked<'w, 's>(467&'s mut self,468world: UnsafeWorldCell<'w>,469) -> SystemParamItem<'w, 's, Param> {470let change_tick = world.increment_change_tick();471// SAFETY: The invariants are upheld by the caller.472unsafe { self.fetch(world, change_tick) }473}474475/// # Safety476/// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data477/// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was478/// created with.479#[inline]480unsafe fn fetch<'w, 's>(481&'s mut self,482world: UnsafeWorldCell<'w>,483change_tick: Tick,484) -> SystemParamItem<'w, 's, Param> {485// SAFETY: The invariants are upheld by the caller.486let param =487unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) };488self.meta.last_run = change_tick;489param490}491492/// Returns a reference to the current system param states.493pub fn param_state(&self) -> &Param::State {494&self.param_state495}496497/// Returns a mutable reference to the current system param states.498/// Marked as unsafe because modifying the system states may result in violation to certain499/// assumptions made by the [`SystemParam`]. Use with care.500///501/// # Safety502/// Modifying the system param states may have unintended consequences.503/// The param state is generally considered to be owned by the [`SystemParam`]. Modifications504/// should respect any invariants as required by the [`SystemParam`].505/// For example, modifying the system state of [`ResMut`](crate::system::ResMut) will obviously create issues.506pub unsafe fn param_state_mut(&mut self) -> &mut Param::State {507&mut self.param_state508}509}510511impl<Param: SystemParam> FromWorld for SystemState<Param> {512fn from_world(world: &mut World) -> Self {513Self::new(world)514}515}516517/// The [`System`] counter part of an ordinary function.518///519/// You get this by calling [`IntoSystem::into_system`] on a function that only accepts520/// [`SystemParam`]s. The output of the system becomes the functions return type, while the input521/// becomes the functions first parameter or `()` if no such parameter exists.522///523/// [`FunctionSystem`] must be `.initialized` before they can be run.524///525/// The [`Clone`] implementation for [`FunctionSystem`] returns a new instance which526/// is NOT initialized. The cloned system must also be `.initialized` before it can be run.527pub struct FunctionSystem<Marker, Out, F>528where529F: SystemParamFunction<Marker>,530{531func: F,532#[cfg(feature = "hotpatching")]533current_ptr: subsecond::HotFnPtr,534state: Option<FunctionSystemState<F::Param>>,535system_meta: SystemMeta,536// NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls537marker: PhantomData<fn() -> (Marker, Out)>,538}539540/// The state of a [`FunctionSystem`], which must be initialized with541/// [`System::initialize`] before the system can be run. A panic will occur if542/// the system is run without being initialized.543struct FunctionSystemState<P: SystemParam> {544/// The cached state of the system's [`SystemParam`]s.545param: P::State,546/// The id of the [`World`] this system was initialized with. If the world547/// passed to [`System::run_unsafe`] or [`System::validate_param_unsafe`] does not match548/// this id, a panic will occur.549world_id: WorldId,550}551552impl<Marker, Out, F> FunctionSystem<Marker, Out, F>553where554F: SystemParamFunction<Marker>,555{556/// Return this system with a new name.557///558/// Useful to give closure systems more readable and unique names for debugging and tracing.559pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {560self.system_meta.set_name(new_name.into());561self562}563}564565// De-initializes the cloned system.566impl<Marker, Out, F> Clone for FunctionSystem<Marker, Out, F>567where568F: SystemParamFunction<Marker> + Clone,569{570fn clone(&self) -> Self {571Self {572func: self.func.clone(),573#[cfg(feature = "hotpatching")]574current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)575.ptr_address(),576state: None,577system_meta: SystemMeta::new::<F>(),578marker: PhantomData,579}580}581}582583/// A marker type used to distinguish regular function systems from exclusive function systems.584#[doc(hidden)]585pub struct IsFunctionSystem;586587impl<Marker, Out, F> IntoSystem<F::In, Out, (IsFunctionSystem, Marker)> for F588where589Out: 'static,590Marker: 'static,591F: SystemParamFunction<Marker, Out: IntoResult<Out>>,592{593type System = FunctionSystem<Marker, Out, F>;594fn into_system(func: Self) -> Self::System {595FunctionSystem {596func,597#[cfg(feature = "hotpatching")]598current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)599.ptr_address(),600state: None,601system_meta: SystemMeta::new::<F>(),602marker: PhantomData,603}604}605}606607/// A type that may be converted to the output of a [`System`].608/// This is used to allow systems to return either a plain value or a [`Result`].609pub trait IntoResult<Out>: Sized {610/// Converts this type into the system output type.611fn into_result(self) -> Result<Out, RunSystemError>;612}613614impl<T> IntoResult<T> for T {615fn into_result(self) -> Result<T, RunSystemError> {616Ok(self)617}618}619620impl<T> IntoResult<T> for Result<T, RunSystemError> {621fn into_result(self) -> Result<T, RunSystemError> {622self623}624}625626impl<T> IntoResult<T> for Result<T, BevyError> {627fn into_result(self) -> Result<T, RunSystemError> {628Ok(self?)629}630}631632// The `!` impl can't be generic in `Out`, since that would overlap with633// `impl<T> IntoResult<T> for T` when `T` = `!`.634// Use explicit impls for `()` and `bool` so diverging functions635// can be used for systems and conditions.636impl IntoResult<()> for Never {637fn into_result(self) -> Result<(), RunSystemError> {638self639}640}641642impl IntoResult<bool> for Never {643fn into_result(self) -> Result<bool, RunSystemError> {644self645}646}647648impl<Marker, Out, F> FunctionSystem<Marker, Out, F>649where650F: SystemParamFunction<Marker>,651{652/// Message shown when a system isn't initialized653// When lines get too long, rustfmt can sometimes refuse to format them.654// Work around this by storing the message separately.655const ERROR_UNINITIALIZED: &'static str =656"System's state was not found. Did you forget to initialize this system before running it?";657}658659impl<Marker, Out, F> System for FunctionSystem<Marker, Out, F>660where661Marker: 'static,662Out: 'static,663F: SystemParamFunction<Marker, Out: IntoResult<Out>>,664{665type In = F::In;666type Out = Out;667668#[inline]669fn name(&self) -> DebugName {670self.system_meta.name.clone()671}672673#[inline]674fn flags(&self) -> SystemStateFlags {675self.system_meta.flags676}677678#[inline]679unsafe fn run_unsafe(680&mut self,681input: SystemIn<'_, Self>,682world: UnsafeWorldCell,683) -> Result<Self::Out, RunSystemError> {684#[cfg(feature = "trace")]685let _span_guard = self.system_meta.system_span.enter();686687let change_tick = world.increment_change_tick();688689let state = self.state.as_mut().expect(Self::ERROR_UNINITIALIZED);690assert_eq!(state.world_id, world.id(), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");691// SAFETY:692// - The above assert ensures the world matches.693// - All world accesses used by `F::Param` have been registered, so the caller694// will ensure that there are no data access conflicts.695let params =696unsafe { F::Param::get_param(&mut state.param, &self.system_meta, world, change_tick) };697698#[cfg(feature = "hotpatching")]699let out = {700let mut hot_fn = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run);701// SAFETY:702// - pointer used to call is from the current jump table703unsafe {704hot_fn705.try_call_with_ptr(self.current_ptr, (&mut self.func, input, params))706.expect("Error calling hotpatched system. Run a full rebuild")707}708};709#[cfg(not(feature = "hotpatching"))]710let out = self.func.run(input, params);711712self.system_meta.last_run = change_tick;713IntoResult::into_result(out)714}715716#[cfg(feature = "hotpatching")]717#[inline]718fn refresh_hotpatch(&mut self) {719let new = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run).ptr_address();720if new != self.current_ptr {721log::debug!("system {} hotpatched", self.name());722}723self.current_ptr = new;724}725726#[inline]727fn apply_deferred(&mut self, world: &mut World) {728let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;729F::Param::apply(param_state, &self.system_meta, world);730}731732#[inline]733fn queue_deferred(&mut self, world: DeferredWorld) {734let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;735F::Param::queue(param_state, &self.system_meta, world);736}737738#[inline]739unsafe fn validate_param_unsafe(740&mut self,741world: UnsafeWorldCell,742) -> Result<(), SystemParamValidationError> {743let state = self.state.as_mut().expect(Self::ERROR_UNINITIALIZED);744assert_eq!(state.world_id, world.id(), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");745// SAFETY:746// - The above assert ensures the world matches.747// - All world accesses used by `F::Param` have been registered, so the caller748// will ensure that there are no data access conflicts.749unsafe { F::Param::validate_param(&mut state.param, &self.system_meta, world) }750}751752#[inline]753fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {754if let Some(state) = &self.state {755assert_eq!(756state.world_id,757world.id(),758"System built with a different world than the one it was added to.",759);760}761let state = self.state.get_or_insert_with(|| FunctionSystemState {762param: F::Param::init_state(world),763world_id: world.id(),764});765self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);766let mut component_access_set = FilteredAccessSet::new();767F::Param::init_access(768&state.param,769&mut self.system_meta,770&mut component_access_set,771world,772);773component_access_set774}775776#[inline]777fn check_change_tick(&mut self, check: CheckChangeTicks) {778check_system_change_tick(779&mut self.system_meta.last_run,780check,781self.system_meta.name.clone(),782);783}784785fn default_system_sets(&self) -> Vec<InternedSystemSet> {786let set = crate::schedule::SystemTypeSet::<Self>::new();787vec![set.intern()]788}789790fn get_last_run(&self) -> Tick {791self.system_meta.last_run792}793794fn set_last_run(&mut self, last_run: Tick) {795self.system_meta.last_run = last_run;796}797}798799/// SAFETY: `F`'s param is [`ReadOnlySystemParam`], so this system will only read from the world.800unsafe impl<Marker, Out, F> ReadOnlySystem for FunctionSystem<Marker, Out, F>801where802Marker: 'static,803Out: 'static,804F: SystemParamFunction<Marker, Out: IntoResult<Out>>,805F::Param: ReadOnlySystemParam,806{807}808809/// A trait implemented for all functions that can be used as [`System`]s.810///811/// This trait can be useful for making your own systems which accept other systems,812/// sometimes called higher order systems.813///814/// This should be used in combination with [`ParamSet`] when calling other systems815/// within your system.816/// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.817///818/// # Example819///820/// To create something like [`PipeSystem`], but in entirely safe code.821///822/// ```823/// use std::num::ParseIntError;824///825/// use bevy_ecs::prelude::*;826/// use bevy_ecs::system::StaticSystemInput;827///828/// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`829/// pub fn pipe<A, B, AMarker, BMarker>(830/// mut a: A,831/// mut b: B,832/// ) -> impl FnMut(StaticSystemInput<A::In>, ParamSet<(A::Param, B::Param)>) -> B::Out833/// where834/// // We need A and B to be systems, add those bounds835/// A: SystemParamFunction<AMarker>,836/// B: SystemParamFunction<BMarker>,837/// for<'a> B::In: SystemInput<Inner<'a> = A::Out>,838/// {839/// // The type of `params` is inferred based on the return of this function above840/// move |StaticSystemInput(a_in), mut params| {841/// let shared = a.run(a_in, params.p0());842/// b.run(shared, params.p1())843/// }844/// }845///846/// // Usage example for `pipe`:847/// fn main() {848/// let mut world = World::default();849/// world.insert_resource(Message("42".to_string()));850///851/// // pipe the `parse_message_system`'s output into the `filter_system`s input852/// let mut piped_system = IntoSystem::into_system(pipe(parse_message, filter));853/// piped_system.initialize(&mut world);854/// assert_eq!(piped_system.run((), &mut world).unwrap(), Some(42));855/// }856///857/// #[derive(Resource)]858/// struct Message(String);859///860/// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {861/// message.0.parse::<usize>()862/// }863///864/// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {865/// result.ok().filter(|&n| n < 100)866/// }867/// ```868/// [`PipeSystem`]: crate::system::PipeSystem869/// [`ParamSet`]: crate::system::ParamSet870#[diagnostic::on_unimplemented(871message = "`{Self}` is not a valid system",872label = "invalid system"873)]874pub trait SystemParamFunction<Marker>: Send + Sync + 'static {875/// The input type of this system. See [`System::In`].876type In: SystemInput;877/// The return type of this system. See [`System::Out`].878type Out;879880/// The [`SystemParam`]/s used by this system to access the [`World`].881type Param: SystemParam;882883/// Executes this system once. See [`System::run`] or [`System::run_unsafe`].884fn run(885&mut self,886input: <Self::In as SystemInput>::Inner<'_>,887param_value: SystemParamItem<Self::Param>,888) -> Self::Out;889}890891/// A marker type used to distinguish function systems with and without input.892#[doc(hidden)]893pub struct HasSystemInput;894895macro_rules! impl_system_function {896($($param: ident),*) => {897#[expect(898clippy::allow_attributes,899reason = "This is within a macro, and as such, the below lints may not always apply."900)]901#[allow(902non_snake_case,903reason = "Certain variable names are provided by the caller, not by us."904)]905impl<Out, Func, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*) -> Out> for Func906where907Func: Send + Sync + 'static,908for <'a> &'a mut Func:909FnMut($($param),*) -> Out +910FnMut($(SystemParamItem<$param>),*) -> Out,911Out: 'static912{913type In = ();914type Out = Out;915type Param = ($($param,)*);916#[inline]917fn run(&mut self, _input: (), param_value: SystemParamItem< ($($param,)*)>) -> Out {918// Yes, this is strange, but `rustc` fails to compile this impl919// without using this function. It fails to recognize that `func`920// is a function, potentially because of the multiple impls of `FnMut`921fn call_inner<Out, $($param,)*>(922mut f: impl FnMut($($param,)*)->Out,923$($param: $param,)*924)->Out{925f($($param,)*)926}927let ($($param,)*) = param_value;928call_inner(self, $($param),*)929}930}931932#[expect(933clippy::allow_attributes,934reason = "This is within a macro, and as such, the below lints may not always apply."935)]936#[allow(937non_snake_case,938reason = "Certain variable names are provided by the caller, not by us."939)]940impl<In, Out, Func, $($param: SystemParam),*> SystemParamFunction<(HasSystemInput, fn(In, $($param,)*) -> Out)> for Func941where942Func: Send + Sync + 'static,943for <'a> &'a mut Func:944FnMut(In, $($param),*) -> Out +945FnMut(In::Param<'_>, $(SystemParamItem<$param>),*) -> Out,946In: SystemInput + 'static,947Out: 'static948{949type In = In;950type Out = Out;951type Param = ($($param,)*);952#[inline]953fn run(&mut self, input: In::Inner<'_>, param_value: SystemParamItem< ($($param,)*)>) -> Out {954fn call_inner<In: SystemInput, Out, $($param,)*>(955_: PhantomData<In>,956mut f: impl FnMut(In::Param<'_>, $($param,)*)->Out,957input: In::Inner<'_>,958$($param: $param,)*959)->Out{960f(In::wrap(input), $($param,)*)961}962let ($($param,)*) = param_value;963call_inner(PhantomData::<In>, self, input, $($param),*)964}965}966};967}968969// Note that we rely on the highest impl to be <= the highest order of the tuple impls970// of `SystemParam` created.971all_tuples!(impl_system_function, 0, 16, F);972973#[cfg(test)]974mod tests {975use super::*;976977#[test]978fn into_system_type_id_consistency() {979fn test<T, In: SystemInput, Out, Marker>(function: T)980where981T: IntoSystem<In, Out, Marker> + Copy,982{983fn reference_system() {}984985use core::any::TypeId;986987let system = IntoSystem::into_system(function);988989assert_eq!(990system.type_id(),991function.system_type_id(),992"System::type_id should be consistent with IntoSystem::system_type_id"993);994995assert_eq!(996system.type_id(),997TypeId::of::<T::System>(),998"System::type_id should be consistent with TypeId::of::<T::System>()"999);10001001assert_ne!(1002system.type_id(),1003IntoSystem::into_system(reference_system).type_id(),1004"Different systems should have different TypeIds"1005);1006}10071008fn function_system() {}10091010test(function_system);1011}1012}101310141015