Path: blob/main/crates/bevy_ecs/src/system/function_system.rs
9328 views
use crate::{1change_detection::{CheckChangeTicks, Tick},2error::{BevyError, Result},3never::Never,4prelude::FromWorld,5query::FilteredAccessSet,6schedule::{InternedSystemSet, SystemSet},7system::{8check_system_change_tick, FromInput, ReadOnlySystemParam, System, SystemIn, SystemInput,9SystemParam, SystemParamItem,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};2122#[cfg(feature = "trace")]23use alloc::string::ToString as _;2425use super::{26IntoSystem, ReadOnlySystem, RunSystemError, SystemParamBuilder, SystemParamValidationError,27SystemStateFlags,28};2930/// The metadata of a [`System`].31#[derive(Clone)]32pub struct SystemMeta {33pub(crate) name: DebugName,34// NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent35// SystemParams from overriding each other36flags: SystemStateFlags,37pub(crate) last_run: Tick,38#[cfg(feature = "trace")]39pub(crate) system_span: Span,40#[cfg(feature = "trace")]41pub(crate) commands_span: Span,42}4344impl SystemMeta {45pub(crate) fn new<T>() -> Self {46let name = DebugName::type_name::<T>();47Self {48// These spans are initialized during plugin build, so we set the parent to `None` to prevent49// them from being children of the span that is measuring the plugin build time.50#[cfg(feature = "trace")]51system_span: info_span!(parent: None, "system", name = name.clone().to_string()),52#[cfg(feature = "trace")]53commands_span: info_span!(parent: None, "system_commands", name = name.clone().to_string()),54name,55flags: SystemStateFlags::empty(),56last_run: Tick::new(0),57}58}5960/// Returns the system's name61#[inline]62pub fn name(&self) -> &DebugName {63&self.name64}6566/// Sets the name of this system.67///68/// Useful to give closure systems more readable and unique names for debugging and tracing.69#[inline]70pub fn set_name(&mut self, new_name: impl Into<Cow<'static, str>>) {71let new_name: Cow<'static, str> = new_name.into();72#[cfg(feature = "trace")]73{74let name = new_name.as_ref();75self.system_span = info_span!(parent: None, "system", name = name);76self.commands_span = info_span!(parent: None, "system_commands", name = name);77}78self.name = new_name.into();79}8081/// Returns true if the system is [`Send`].82#[inline]83pub fn is_send(&self) -> bool {84!self.flags.intersects(SystemStateFlags::NON_SEND)85}8687/// Sets the system to be not [`Send`].88///89/// This is irreversible.90#[inline]91pub fn set_non_send(&mut self) {92self.flags |= SystemStateFlags::NON_SEND;93}9495/// Returns true if the system has deferred [`SystemParam`]'s96#[inline]97pub fn has_deferred(&self) -> bool {98self.flags.intersects(SystemStateFlags::DEFERRED)99}100101/// Marks the system as having deferred buffers like [`Commands`](`super::Commands`)102/// This lets the scheduler insert [`ApplyDeferred`](`crate::prelude::ApplyDeferred`) systems automatically.103#[inline]104pub fn set_has_deferred(&mut self) {105self.flags |= SystemStateFlags::DEFERRED;106}107108/// Mark the system to run exclusively. i.e. no other systems will run at the same time.109pub fn set_exclusive(&mut self) {110self.flags |= SystemStateFlags::EXCLUSIVE;111}112113/// Expose a read only copy of `last_run`.114pub fn get_last_run(&self) -> Tick {115self.last_run116}117}118119// TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference120// (to avoid the need for unwrapping to retrieve SystemMeta)121/// Holds on to persistent state required to drive [`SystemParam`] for a [`System`].122///123/// This is a powerful and convenient tool for working with exclusive world access,124/// allowing you to fetch data from the [`World`] as if you were running a [`System`].125/// However, simply calling `world::run_system(my_system)` using a [`World::run_system`](World::run_system)126/// can be significantly simpler and ensures that change detection and command flushing work as expected.127///128/// Borrow-checking is handled for you, allowing you to mutably access multiple compatible system parameters at once,129/// and arbitrary system parameters (like [`MessageWriter`](crate::message::MessageWriter)) can be conveniently fetched.130///131/// For an alternative approach to split mutable access to the world, see [`World::resource_scope`].132///133/// # Warning134///135/// [`SystemState`] values created can be cached to improve performance,136/// and *must* be cached and reused in order for system parameters that rely on local state to work correctly.137/// These include:138/// - [`Added`](crate::query::Added), [`Changed`](crate::query::Changed) and [`Spawned`](crate::query::Spawned) query filters139/// - [`Local`](crate::system::Local) variables that hold state140/// - [`MessageReader`](crate::message::MessageReader) system parameters, which rely on a [`Local`](crate::system::Local) to track which messages have been seen141///142/// Note that this is automatically handled for you when using a [`World::run_system`](World::run_system).143///144/// # Example145///146/// Basic usage:147/// ```148/// # use bevy_ecs::prelude::*;149/// # use bevy_ecs::system::SystemState;150/// #151/// # #[derive(Message)]152/// # struct MyMessage;153/// # #[derive(Resource)]154/// # struct MyResource(u32);155/// #156/// # #[derive(Component)]157/// # struct MyComponent;158/// #159/// // Work directly on the `World`160/// let mut world = World::new();161/// world.init_resource::<Messages<MyMessage>>();162///163/// // Construct a `SystemState` struct, passing in a tuple of `SystemParam`164/// // as if you were writing an ordinary system.165/// let mut system_state: SystemState<(166/// MessageWriter<MyMessage>,167/// Option<ResMut<MyResource>>,168/// Query<&MyComponent>,169/// )> = SystemState::new(&mut world);170///171/// // Use system_state.get_mut(&mut world) and unpack your system parameters into variables!172/// // system_state.get(&world) provides read-only versions of your system parameters instead.173/// let (message_writer, maybe_resource, query) = system_state.get_mut(&mut world);174///175/// // If you are using `Commands`, you can choose when you want to apply them to the world.176/// // You need to manually call `.apply(world)` on the `SystemState` to apply them.177/// ```178/// Caching:179/// ```180/// # use bevy_ecs::prelude::*;181/// # use bevy_ecs::system::SystemState;182/// # use bevy_ecs::message::Messages;183/// #184/// # #[derive(Message)]185/// # struct MyMessage;186/// #[derive(Resource)]187/// struct CachedSystemState {188/// message_state: SystemState<MessageReader<'static, 'static, MyMessage>>,189/// }190///191/// // Create and store a system state once192/// let mut world = World::new();193/// world.init_resource::<Messages<MyMessage>>();194/// let initial_state: SystemState<MessageReader<MyMessage>> = SystemState::new(&mut world);195///196/// // The system state is cached in a resource197/// world.insert_resource(CachedSystemState {198/// message_state: initial_state,199/// });200///201/// // Later, fetch the cached system state, saving on overhead202/// world.resource_scope(|world, mut cached_state: Mut<CachedSystemState>| {203/// let mut message_reader = cached_state.message_state.get_mut(world);204///205/// for message in message_reader.read() {206/// println!("Hello World!");207/// }208/// });209/// ```210/// Exclusive System:211/// ```212/// # use bevy_ecs::prelude::*;213/// # use bevy_ecs::system::SystemState;214/// #215/// # #[derive(Message)]216/// # struct MyMessage;217/// #218/// fn exclusive_system(world: &mut World, system_state: &mut SystemState<MessageReader<MyMessage>>) {219/// let mut message_reader = system_state.get_mut(world);220///221/// for message in message_reader.read() {222/// println!("Hello World!");223/// }224/// }225/// ```226pub struct SystemState<Param: SystemParam + 'static> {227meta: SystemMeta,228param_state: Param::State,229world_id: WorldId,230}231232// Allow closure arguments to be inferred.233// For a closure to be used as a `SystemParamFunction`, it needs to be generic in any `'w` or `'s` lifetimes.234// Rust will only infer a closure to be generic over lifetimes if it's passed to a function with a Fn constraint.235// So, generate a function for each arity with an explicit `FnMut` constraint to enable higher-order lifetimes,236// along with a regular `SystemParamFunction` constraint to allow the system to be built.237macro_rules! impl_build_system {238($(#[$meta:meta])* $($param: ident),*) => {239$(#[$meta])*240impl<$($param: SystemParam),*> SystemState<($($param,)*)> {241/// Create a [`FunctionSystem`] from a [`SystemState`].242/// This method signature allows type inference of closure parameters for a system with no input.243/// You can use [`SystemState::build_system_with_input()`] if you have input, or [`SystemState::build_any_system()`] if you don't need type inference.244#[inline]245pub fn build_system<246InnerOut: IntoResult<Out>,247Out,248Marker,249F: FnMut($(SystemParamItem<$param>),*) -> InnerOut250+ SystemParamFunction<Marker, In = (), Out = InnerOut, Param = ($($param,)*)>251>252(253self,254func: F,255) -> FunctionSystem<Marker, (), Out, F>256{257self.build_any_system(func)258}259260/// Create a [`FunctionSystem`] from a [`SystemState`].261/// This method signature allows type inference of closure parameters for a system with input.262/// You can use [`SystemState::build_system()`] if you have no input, or [`SystemState::build_any_system()`] if you don't need type inference.263#[inline]264pub fn build_system_with_input<265InnerIn: SystemInput + FromInput<In>,266In: SystemInput,267InnerOut: IntoResult<Out>,268Out,269Marker,270F: FnMut(InnerIn, $(SystemParamItem<$param>),*) -> InnerOut271+ SystemParamFunction<Marker, In = InnerIn, Out = InnerOut, Param = ($($param,)*)>272>273(274self,275func: F,276) -> FunctionSystem<Marker, In, Out, F> {277self.build_any_system(func)278}279}280}281}282283all_tuples!(284#[doc(fake_variadic)]285impl_build_system,2860,28716,288P289);290291impl<Param: SystemParam> SystemState<Param> {292/// Creates a new [`SystemState`] with default state.293#[track_caller]294pub fn new(world: &mut World) -> Self {295let mut meta = SystemMeta::new::<Param>();296meta.last_run = world.change_tick().relative_to(Tick::MAX);297let param_state = Param::init_state(world);298let mut component_access_set = FilteredAccessSet::new();299// We need to call `init_access` to ensure there are no panics from conflicts within `Param`,300// even though we don't use the calculated access.301Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);302Self {303meta,304param_state,305world_id: world.id(),306}307}308309/// Create a [`SystemState`] from a [`SystemParamBuilder`]310pub(crate) fn from_builder(world: &mut World, builder: impl SystemParamBuilder<Param>) -> Self {311let mut meta = SystemMeta::new::<Param>();312meta.last_run = world.change_tick().relative_to(Tick::MAX);313let param_state = builder.build(world);314let mut component_access_set = FilteredAccessSet::new();315// We need to call `init_access` to ensure there are no panics from conflicts within `Param`,316// even though we don't use the calculated access.317Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);318Self {319meta,320param_state,321world_id: world.id(),322}323}324325/// Create a [`FunctionSystem`] from a [`SystemState`].326/// This method signature allows any system function, but the compiler will not perform type inference on closure parameters.327/// You can use [`SystemState::build_system()`] or [`SystemState::build_system_with_input()`] to get type inference on parameters.328#[inline]329pub fn build_any_system<Marker, In, Out, F>(self, func: F) -> FunctionSystem<Marker, In, Out, F>330where331In: SystemInput,332F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>, Param = Param>,333{334FunctionSystem::new(335func,336self.meta,337Some(FunctionSystemState {338param: self.param_state,339world_id: self.world_id,340}),341)342}343344/// Gets the metadata for this instance.345#[inline]346pub fn meta(&self) -> &SystemMeta {347&self.meta348}349350/// Gets the metadata for this instance.351#[inline]352pub fn meta_mut(&mut self) -> &mut SystemMeta {353&mut self.meta354}355356/// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.357#[inline]358pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>359where360Param: ReadOnlySystemParam,361{362self.validate_world(world.id());363// SAFETY: Param is read-only and doesn't allow mutable access to World.364// It also matches the World this SystemState was created with.365unsafe { self.get_unchecked(world.as_unsafe_world_cell_readonly()) }366}367368/// Retrieve the mutable [`SystemParam`] values.369#[inline]370#[track_caller]371pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {372self.validate_world(world.id());373// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.374unsafe { self.get_unchecked(world.as_unsafe_world_cell()) }375}376377/// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up378/// by a [`Commands`](`super::Commands`) parameter to the given [`World`].379/// This function should be called manually after the values returned by [`SystemState::get`] and [`SystemState::get_mut`]380/// are finished being used.381pub fn apply(&mut self, world: &mut World) {382Param::apply(&mut self.param_state, &self.meta, world);383}384385/// Wrapper over [`SystemParam::validate_param`].386///387/// # Safety388///389/// - The passed [`UnsafeWorldCell`] must have read-only access to390/// world data in `component_access_set`.391/// - `world` must be the same [`World`] that was used to initialize [`state`](SystemParam::init_state).392pub unsafe fn validate_param(393state: &mut Self,394world: UnsafeWorldCell,395) -> Result<(), SystemParamValidationError> {396// SAFETY: Delegated to existing `SystemParam` implementations.397unsafe { Param::validate_param(&mut state.param_state, &state.meta, world) }398}399400/// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].401/// Otherwise, this returns false.402#[inline]403pub fn matches_world(&self, world_id: WorldId) -> bool {404self.world_id == world_id405}406407/// Asserts that the [`SystemState`] matches the provided world.408#[inline]409#[track_caller]410fn validate_world(&self, world_id: WorldId) {411#[inline(never)]412#[track_caller]413#[cold]414fn panic_mismatched(this: WorldId, other: WorldId) -> ! {415panic!("Encountered a mismatched World. This SystemState was created from {this:?}, but a method was called using {other:?}.");416}417418if !self.matches_world(world_id) {419panic_mismatched(self.world_id, world_id);420}421}422423/// Retrieve the [`SystemParam`] values.424///425/// # Safety426/// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data427/// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was428/// created with.429#[inline]430#[track_caller]431pub unsafe fn get_unchecked<'w, 's>(432&'s mut self,433world: UnsafeWorldCell<'w>,434) -> SystemParamItem<'w, 's, Param> {435let change_tick = world.increment_change_tick();436// SAFETY: The invariants are upheld by the caller.437unsafe { self.fetch(world, change_tick) }438}439440/// # Safety441/// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data442/// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was443/// created with.444#[inline]445#[track_caller]446unsafe fn fetch<'w, 's>(447&'s mut self,448world: UnsafeWorldCell<'w>,449change_tick: Tick,450) -> SystemParamItem<'w, 's, Param> {451// SAFETY: The invariants are upheld by the caller.452let param =453unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) };454self.meta.last_run = change_tick;455param456}457458/// Returns a reference to the current system param states.459pub fn param_state(&self) -> &Param::State {460&self.param_state461}462463/// Returns a mutable reference to the current system param states.464/// Marked as unsafe because modifying the system states may result in violation to certain465/// assumptions made by the [`SystemParam`]. Use with care.466///467/// # Safety468/// Modifying the system param states may have unintended consequences.469/// The param state is generally considered to be owned by the [`SystemParam`]. Modifications470/// should respect any invariants as required by the [`SystemParam`].471/// For example, modifying the system state of [`ResMut`](crate::system::ResMut) will obviously create issues.472pub unsafe fn param_state_mut(&mut self) -> &mut Param::State {473&mut self.param_state474}475}476477impl<Param: SystemParam> FromWorld for SystemState<Param> {478fn from_world(world: &mut World) -> Self {479Self::new(world)480}481}482483/// The [`System`] counter part of an ordinary function.484///485/// You get this by calling [`IntoSystem::into_system`] on a function that only accepts486/// [`SystemParam`]s. The output of the system becomes the functions return type, while the input487/// becomes the functions first parameter or `()` if no such parameter exists.488///489/// [`FunctionSystem`] must be `.initialized` before they can be run.490///491/// The [`Clone`] implementation for [`FunctionSystem`] returns a new instance which492/// is NOT initialized. The cloned system must also be `.initialized` before it can be run.493pub struct FunctionSystem<Marker, In, Out, F>494where495F: SystemParamFunction<Marker>,496{497func: F,498#[cfg(feature = "hotpatching")]499current_ptr: subsecond::HotFnPtr,500state: Option<FunctionSystemState<F::Param>>,501system_meta: SystemMeta,502// NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls503marker: PhantomData<fn(In) -> (Marker, Out)>,504}505506/// The state of a [`FunctionSystem`], which must be initialized with507/// [`System::initialize`] before the system can be run. A panic will occur if508/// the system is run without being initialized.509struct FunctionSystemState<P: SystemParam> {510/// The cached state of the system's [`SystemParam`]s.511param: P::State,512/// The id of the [`World`] this system was initialized with. If the world513/// passed to [`System::run_unsafe`] or [`System::validate_param_unsafe`] does not match514/// this id, a panic will occur.515world_id: WorldId,516}517518impl<Marker, In, Out, F> FunctionSystem<Marker, In, Out, F>519where520F: SystemParamFunction<Marker>,521{522#[inline]523fn new(func: F, system_meta: SystemMeta, state: Option<FunctionSystemState<F::Param>>) -> Self {524Self {525func,526#[cfg(feature = "hotpatching")]527current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)528.ptr_address(),529state,530system_meta,531marker: PhantomData,532}533}534535/// Return this system with a new name.536///537/// Useful to give closure systems more readable and unique names for debugging and tracing.538pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {539self.system_meta.set_name(new_name.into());540self541}542}543544// De-initializes the cloned system.545impl<Marker, In, Out, F> Clone for FunctionSystem<Marker, In, Out, F>546where547F: SystemParamFunction<Marker> + Clone,548{549fn clone(&self) -> Self {550Self {551func: self.func.clone(),552#[cfg(feature = "hotpatching")]553current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)554.ptr_address(),555state: None,556system_meta: SystemMeta::new::<F>(),557marker: PhantomData,558}559}560}561562/// A marker type used to distinguish regular function systems from exclusive function systems.563#[doc(hidden)]564pub struct IsFunctionSystem;565566impl<Marker, In, Out, F> IntoSystem<In, Out, (IsFunctionSystem, Marker)> for F567where568Marker: 'static,569In: SystemInput + 'static,570Out: 'static,571F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,572{573type System = FunctionSystem<Marker, In, Out, F>;574fn into_system(func: Self) -> Self::System {575FunctionSystem::new(func, SystemMeta::new::<F>(), None)576}577}578579/// A type that may be converted to the output of a [`System`].580/// This is used to allow systems to return either a plain value or a [`Result`].581pub trait IntoResult<Out>: Sized {582/// Converts this type into the system output type.583fn into_result(self) -> Result<Out, RunSystemError>;584}585586impl<T> IntoResult<T> for T {587fn into_result(self) -> Result<T, RunSystemError> {588Ok(self)589}590}591592impl<T> IntoResult<T> for Result<T, RunSystemError> {593fn into_result(self) -> Result<T, RunSystemError> {594self595}596}597598impl<T> IntoResult<T> for Result<T, BevyError> {599fn into_result(self) -> Result<T, RunSystemError> {600Ok(self?)601}602}603604// The `!` impl can't be generic in `Out`, since that would overlap with605// `impl<T> IntoResult<T> for T` when `T` = `!`.606// Use explicit impls for `()` and `bool` so diverging functions607// can be used for systems and conditions.608impl IntoResult<()> for Never {609fn into_result(self) -> Result<(), RunSystemError> {610self611}612}613614impl IntoResult<bool> for Never {615fn into_result(self) -> Result<bool, RunSystemError> {616self617}618}619620impl<Marker, In, Out, F> FunctionSystem<Marker, In, Out, F>621where622F: SystemParamFunction<Marker>,623{624/// Message shown when a system isn't initialized625// When lines get too long, rustfmt can sometimes refuse to format them.626// Work around this by storing the message separately.627const ERROR_UNINITIALIZED: &'static str =628"System's state was not found. Did you forget to initialize this system before running it?";629}630631impl<Marker, In, Out, F> System for FunctionSystem<Marker, In, Out, F>632where633Marker: 'static,634In: SystemInput + 'static,635Out: 'static,636F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,637{638type In = In;639type Out = Out;640641#[inline]642fn name(&self) -> DebugName {643self.system_meta.name.clone()644}645646#[inline]647fn flags(&self) -> SystemStateFlags {648self.system_meta.flags649}650651#[inline]652unsafe fn run_unsafe(653&mut self,654input: SystemIn<'_, Self>,655world: UnsafeWorldCell,656) -> Result<Self::Out, RunSystemError> {657#[cfg(feature = "trace")]658let _span_guard = self.system_meta.system_span.enter();659660let change_tick = world.increment_change_tick();661662let input = F::In::from_inner(input);663664let state = self.state.as_mut().expect(Self::ERROR_UNINITIALIZED);665assert_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.");666// SAFETY:667// - The above assert ensures the world matches.668// - All world accesses used by `F::Param` have been registered, so the caller669// will ensure that there are no data access conflicts.670let params =671unsafe { F::Param::get_param(&mut state.param, &self.system_meta, world, change_tick) };672673#[cfg(feature = "hotpatching")]674let out = {675let mut hot_fn = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run);676// SAFETY:677// - pointer used to call is from the current jump table678unsafe {679hot_fn680.try_call_with_ptr(self.current_ptr, (&mut self.func, input, params))681.expect("Error calling hotpatched system. Run a full rebuild")682}683};684#[cfg(not(feature = "hotpatching"))]685let out = self.func.run(input, params);686687self.system_meta.last_run = change_tick;688IntoResult::into_result(out)689}690691#[cfg(feature = "hotpatching")]692#[inline]693fn refresh_hotpatch(&mut self) {694let new = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run).ptr_address();695if new != self.current_ptr {696log::debug!("system {} hotpatched", self.name());697}698self.current_ptr = new;699}700701#[inline]702fn apply_deferred(&mut self, world: &mut World) {703let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;704F::Param::apply(param_state, &self.system_meta, world);705}706707#[inline]708fn queue_deferred(&mut self, world: DeferredWorld) {709let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;710F::Param::queue(param_state, &self.system_meta, world);711}712713#[inline]714unsafe fn validate_param_unsafe(715&mut self,716world: UnsafeWorldCell,717) -> Result<(), SystemParamValidationError> {718let state = self.state.as_mut().expect(Self::ERROR_UNINITIALIZED);719assert_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.");720// SAFETY:721// - The above assert ensures the world matches.722// - All world accesses used by `F::Param` have been registered, so the caller723// will ensure that there are no data access conflicts.724unsafe { F::Param::validate_param(&mut state.param, &self.system_meta, world) }725}726727#[inline]728fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {729if let Some(state) = &self.state {730assert_eq!(731state.world_id,732world.id(),733"System built with a different world than the one it was added to.",734);735}736let state = self.state.get_or_insert_with(|| FunctionSystemState {737param: F::Param::init_state(world),738world_id: world.id(),739});740self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);741let mut component_access_set = FilteredAccessSet::new();742F::Param::init_access(743&state.param,744&mut self.system_meta,745&mut component_access_set,746world,747);748component_access_set749}750751#[inline]752fn check_change_tick(&mut self, check: CheckChangeTicks) {753check_system_change_tick(754&mut self.system_meta.last_run,755check,756self.system_meta.name.clone(),757);758}759760fn default_system_sets(&self) -> Vec<InternedSystemSet> {761let set = crate::schedule::SystemTypeSet::<F>::new();762vec![set.intern()]763}764765fn get_last_run(&self) -> Tick {766self.system_meta.last_run767}768769fn set_last_run(&mut self, last_run: Tick) {770self.system_meta.last_run = last_run;771}772}773774// SAFETY: `F`'s param is [`ReadOnlySystemParam`], so this system will only read from the world.775unsafe impl<Marker, In, Out, F> ReadOnlySystem for FunctionSystem<Marker, In, Out, F>776where777Marker: 'static,778In: SystemInput + 'static,779Out: 'static,780F: SystemParamFunction<781Marker,782In: FromInput<In>,783Out: IntoResult<Out>,784Param: ReadOnlySystemParam,785>,786{787}788789/// A trait implemented for all functions that can be used as [`System`]s.790///791/// This trait can be useful for making your own systems which accept other systems,792/// sometimes called higher order systems.793///794/// This should be used in combination with [`ParamSet`] when calling other systems795/// within your system.796/// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.797///798/// # Example799///800/// To create something like [`PipeSystem`], but in entirely safe code.801///802/// ```803/// use std::num::ParseIntError;804///805/// use bevy_ecs::prelude::*;806/// use bevy_ecs::system::StaticSystemInput;807///808/// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`809/// pub fn pipe<A, B, AMarker, BMarker>(810/// mut a: A,811/// mut b: B,812/// ) -> impl FnMut(StaticSystemInput<A::In>, ParamSet<(A::Param, B::Param)>) -> B::Out813/// where814/// // We need A and B to be systems, add those bounds815/// A: SystemParamFunction<AMarker>,816/// B: SystemParamFunction<BMarker>,817/// for<'a> B::In: SystemInput<Inner<'a> = A::Out>,818/// {819/// // The type of `params` is inferred based on the return of this function above820/// move |StaticSystemInput(a_in), mut params| {821/// let shared = a.run(a_in, params.p0());822/// b.run(shared, params.p1())823/// }824/// }825///826/// // Usage example for `pipe`:827/// fn main() {828/// let mut world = World::default();829/// world.insert_resource(Message("42".to_string()));830///831/// // pipe the `parse_message_system`'s output into the `filter_system`s input.832/// // Type annotations should only needed when using `StaticSystemInput` as input833/// // AND the input type isn't constrained by nearby code.834/// let mut piped_system = IntoSystem::<(), Option<usize>, _>::into_system(pipe(parse_message, filter));835/// piped_system.initialize(&mut world);836/// assert_eq!(piped_system.run((), &mut world).unwrap(), Some(42));837/// }838///839/// #[derive(Resource)]840/// struct Message(String);841///842/// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {843/// message.0.parse::<usize>()844/// }845///846/// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {847/// result.ok().filter(|&n| n < 100)848/// }849/// ```850/// [`PipeSystem`]: crate::system::PipeSystem851/// [`ParamSet`]: crate::system::ParamSet852#[diagnostic::on_unimplemented(853message = "`{Self}` is not a valid system",854label = "invalid system"855)]856pub trait SystemParamFunction<Marker>: Send + Sync + 'static {857/// The input type of this system. See [`System::In`].858type In: SystemInput;859/// The return type of this system. See [`System::Out`].860type Out;861862/// The [`SystemParam`]/s used by this system to access the [`World`].863type Param: SystemParam;864865/// Executes this system once. See [`System::run`] or [`System::run_unsafe`].866fn run(867&mut self,868input: <Self::In as SystemInput>::Inner<'_>,869param_value: SystemParamItem<Self::Param>,870) -> Self::Out;871}872873/// A marker type used to distinguish function systems with and without input.874#[doc(hidden)]875pub struct HasSystemInput;876877macro_rules! impl_system_function {878($($param: ident),*) => {879#[expect(880clippy::allow_attributes,881reason = "This is within a macro, and as such, the below lints may not always apply."882)]883#[allow(884non_snake_case,885reason = "Certain variable names are provided by the caller, not by us."886)]887impl<Out, Func, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*) -> Out> for Func888where889Func: Send + Sync + 'static,890for <'a> &'a mut Func:891FnMut($($param),*) -> Out +892FnMut($(SystemParamItem<$param>),*) -> Out,893Out: 'static894{895type In = ();896type Out = Out;897type Param = ($($param,)*);898#[inline]899fn run(&mut self, _input: (), param_value: SystemParamItem< ($($param,)*)>) -> Out {900// Yes, this is strange, but `rustc` fails to compile this impl901// without using this function. It fails to recognize that `func`902// is a function, potentially because of the multiple impls of `FnMut`903fn call_inner<Out, $($param,)*>(904mut f: impl FnMut($($param,)*)->Out,905$($param: $param,)*906)->Out{907f($($param,)*)908}909let ($($param,)*) = param_value;910call_inner(self, $($param),*)911}912}913914#[expect(915clippy::allow_attributes,916reason = "This is within a macro, and as such, the below lints may not always apply."917)]918#[allow(919non_snake_case,920reason = "Certain variable names are provided by the caller, not by us."921)]922impl<In, Out, Func, $($param: SystemParam),*> SystemParamFunction<(HasSystemInput, fn(In, $($param,)*) -> Out)> for Func923where924Func: Send + Sync + 'static,925for <'a> &'a mut Func:926FnMut(In, $($param),*) -> Out +927FnMut(In::Param<'_>, $(SystemParamItem<$param>),*) -> Out,928In: SystemInput + 'static,929Out: 'static930{931type In = In;932type Out = Out;933type Param = ($($param,)*);934#[inline]935fn run(&mut self, input: In::Inner<'_>, param_value: SystemParamItem< ($($param,)*)>) -> Out {936fn call_inner<In: SystemInput, Out, $($param,)*>(937_: PhantomData<In>,938mut f: impl FnMut(In::Param<'_>, $($param,)*)->Out,939input: In::Inner<'_>,940$($param: $param,)*941)->Out{942f(In::wrap(input), $($param,)*)943}944let ($($param,)*) = param_value;945call_inner(PhantomData::<In>, self, input, $($param),*)946}947}948};949}950951// Note that we rely on the highest impl to be <= the highest order of the tuple impls952// of `SystemParam` created.953all_tuples!(impl_system_function, 0, 16, F);954955#[cfg(test)]956mod tests {957use super::*;958959#[test]960fn into_system_type_id_consistency() {961fn test<T, In: SystemInput, Out, Marker>(function: T)962where963T: IntoSystem<In, Out, Marker> + Copy,964{965fn reference_system() {}966967use core::any::TypeId;968969let system = IntoSystem::into_system(function);970971assert_eq!(972system.type_id(),973function.system_type_id(),974"System::type_id should be consistent with IntoSystem::system_type_id"975);976977assert_eq!(978system.type_id(),979TypeId::of::<T::System>(),980"System::type_id should be consistent with TypeId::of::<T::System>()"981);982983assert_ne!(984system.type_id(),985IntoSystem::into_system(reference_system).type_id(),986"Different systems should have different TypeIds"987);988}989990fn function_system() {}991992test(function_system);993}994}995996997