 950bd2284d
			
		
	
	
		950bd2284d
		
			
		
	
	
	
	
		
			
			# Objective - Fixes #11679 ## Solution - Added `IntoSystem::system_type_id` which returns the equivalent of `system.into_system().type_id()` without construction. This allows for getting the `TypeId` of functions (a function is an unnamed type and therefore you cannot call `TypeId::of::<apply_deferred::System>()`) - Added default implementation of `System::type_id` to ensure consistency between implementations. Some returned `Self`, while others were returning an inner value instead. This ensures consistency with `IntoSystem::system_type_id`. ## Migration Guide If you use `System::type_id()` on function systems (exclusive or not), ensure you are comparing its value to other `System::type_id()` calls, or `IntoSystem::system_type_id()`. This code wont require any changes, because `IntoSystem`'s are directly compared to each other. ```rust fn test_system() {} let type_id = test_system.type_id(); // ... // No change required assert_eq!(test_system.type_id(), type_id); ``` Likewise, this code wont, because `System`'s are directly compared. ```rust fn test_system() {} let type_id = IntoSystem::into_system(test_system).type_id(); // ... // No change required assert_eq!(IntoSystem::into_system(test_system).type_id(), type_id); ``` The below _does_ require a change, since you're comparing a `System` type to a `IntoSystem` type. ```rust fn test_system() {} // Before assert_eq!(test_system.type_id(), IntoSystem::into_system(test_system).type_id()); // After assert_eq!(test_system.system_type_id(), IntoSystem::into_system(test_system).type_id()); ```
		
			
				
	
	
		
			734 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			734 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::{
 | |
|     archetype::{ArchetypeComponentId, ArchetypeGeneration},
 | |
|     component::{ComponentId, Tick},
 | |
|     prelude::FromWorld,
 | |
|     query::{Access, FilteredAccessSet},
 | |
|     schedule::{InternedSystemSet, SystemSet},
 | |
|     system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem},
 | |
|     world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
 | |
| };
 | |
| 
 | |
| use bevy_utils::all_tuples;
 | |
| use std::{borrow::Cow, marker::PhantomData};
 | |
| 
 | |
| #[cfg(feature = "trace")]
 | |
| use bevy_utils::tracing::{info_span, Span};
 | |
| 
 | |
| use super::{In, IntoSystem, ReadOnlySystem};
 | |
| 
 | |
| /// The metadata of a [`System`].
 | |
| #[derive(Clone)]
 | |
| pub struct SystemMeta {
 | |
|     pub(crate) name: Cow<'static, str>,
 | |
|     pub(crate) component_access_set: FilteredAccessSet<ComponentId>,
 | |
|     pub(crate) archetype_component_access: Access<ArchetypeComponentId>,
 | |
|     // NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent
 | |
|     // SystemParams from overriding each other
 | |
|     is_send: bool,
 | |
|     has_deferred: bool,
 | |
|     pub(crate) last_run: Tick,
 | |
|     #[cfg(feature = "trace")]
 | |
|     pub(crate) system_span: Span,
 | |
|     #[cfg(feature = "trace")]
 | |
|     pub(crate) commands_span: Span,
 | |
| }
 | |
| 
 | |
| impl SystemMeta {
 | |
|     pub(crate) fn new<T>() -> Self {
 | |
|         let name = std::any::type_name::<T>();
 | |
|         Self {
 | |
|             name: name.into(),
 | |
|             archetype_component_access: Access::default(),
 | |
|             component_access_set: FilteredAccessSet::default(),
 | |
|             is_send: true,
 | |
|             has_deferred: false,
 | |
|             last_run: Tick::new(0),
 | |
|             #[cfg(feature = "trace")]
 | |
|             system_span: info_span!("system", name = name),
 | |
|             #[cfg(feature = "trace")]
 | |
|             commands_span: info_span!("system_commands", name = name),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Returns the system's name
 | |
|     #[inline]
 | |
|     pub fn name(&self) -> &str {
 | |
|         &self.name
 | |
|     }
 | |
| 
 | |
|     /// Returns true if the system is [`Send`].
 | |
|     #[inline]
 | |
|     pub fn is_send(&self) -> bool {
 | |
|         self.is_send
 | |
|     }
 | |
| 
 | |
|     /// Sets the system to be not [`Send`].
 | |
|     ///
 | |
|     /// This is irreversible.
 | |
|     #[inline]
 | |
|     pub fn set_non_send(&mut self) {
 | |
|         self.is_send = false;
 | |
|     }
 | |
| 
 | |
|     /// Returns true if the system has deferred [`SystemParam`]'s
 | |
|     #[inline]
 | |
|     pub fn has_deferred(&self) -> bool {
 | |
|         self.has_deferred
 | |
|     }
 | |
| 
 | |
|     /// Marks the system as having deferred buffers like [`Commands`](`super::Commands`)
 | |
|     /// This lets the scheduler insert [`apply_deferred`](`crate::prelude::apply_deferred`) systems automatically.
 | |
|     pub fn set_has_deferred(&mut self) {
 | |
|         self.has_deferred = true;
 | |
|     }
 | |
| }
 | |
| 
 | |
| // TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference
 | |
| // (to avoid the need for unwrapping to retrieve SystemMeta)
 | |
| /// Holds on to persistent state required to drive [`SystemParam`] for a [`System`].
 | |
| ///
 | |
| /// This is a powerful and convenient tool for working with exclusive world access,
 | |
| /// allowing you to fetch data from the [`World`] as if you were running a [`System`].
 | |
| /// However, simply calling `world::run_system(my_system)` using a [`World::run_system`](World::run_system)
 | |
| /// can be significantly simpler and ensures that change detection and command flushing work as expected.
 | |
| ///
 | |
| /// Borrow-checking is handled for you, allowing you to mutably access multiple compatible system parameters at once,
 | |
| /// and arbitrary system parameters (like [`EventWriter`](crate::event::EventWriter)) can be conveniently fetched.
 | |
| ///
 | |
| /// For an alternative approach to split mutable access to the world, see [`World::resource_scope`].
 | |
| ///
 | |
| /// # Warning
 | |
| ///
 | |
| /// [`SystemState`] values created can be cached to improve performance,
 | |
| /// and *must* be cached and reused in order for system parameters that rely on local state to work correctly.
 | |
| /// These include:
 | |
| /// - [`Added`](crate::query::Added) and [`Changed`](crate::query::Changed) query filters
 | |
| /// - [`Local`](crate::system::Local) variables that hold state
 | |
| /// - [`EventReader`](crate::event::EventReader) system parameters, which rely on a [`Local`](crate::system::Local) to track which events have been seen
 | |
| ///
 | |
| /// Note that this is automatically handled for you when using a [`World::run_system`](World::run_system).
 | |
| ///
 | |
| /// # Example
 | |
| ///
 | |
| /// Basic usage:
 | |
| /// ```
 | |
| /// # use bevy_ecs::prelude::*;
 | |
| /// # use bevy_ecs::system::SystemState;
 | |
| /// # use bevy_ecs::event::Events;
 | |
| /// #
 | |
| /// # #[derive(Event)]
 | |
| /// # struct MyEvent;
 | |
| /// # #[derive(Resource)]
 | |
| /// # struct MyResource(u32);
 | |
| /// #
 | |
| /// # #[derive(Component)]
 | |
| /// # struct MyComponent;
 | |
| /// #
 | |
| /// // Work directly on the `World`
 | |
| /// let mut world = World::new();
 | |
| /// world.init_resource::<Events<MyEvent>>();
 | |
| ///
 | |
| /// // Construct a `SystemState` struct, passing in a tuple of `SystemParam`
 | |
| /// // as if you were writing an ordinary system.
 | |
| /// let mut system_state: SystemState<(
 | |
| ///     EventWriter<MyEvent>,
 | |
| ///     Option<ResMut<MyResource>>,
 | |
| ///     Query<&MyComponent>,
 | |
| /// )> = SystemState::new(&mut world);
 | |
| ///
 | |
| /// // Use system_state.get_mut(&mut world) and unpack your system parameters into variables!
 | |
| /// // system_state.get(&world) provides read-only versions of your system parameters instead.
 | |
| /// let (event_writer, maybe_resource, query) = system_state.get_mut(&mut world);
 | |
| ///
 | |
| /// // If you are using `Commands`, you can choose when you want to apply them to the world.
 | |
| /// // You need to manually call `.apply(world)` on the `SystemState` to apply them.
 | |
| /// ```
 | |
| /// Caching:
 | |
| /// ```
 | |
| /// # use bevy_ecs::prelude::*;
 | |
| /// # use bevy_ecs::system::SystemState;
 | |
| /// # use bevy_ecs::event::Events;
 | |
| /// #
 | |
| /// # #[derive(Event)]
 | |
| /// # struct MyEvent;
 | |
| /// #[derive(Resource)]
 | |
| /// struct CachedSystemState {
 | |
| ///     event_state: SystemState<EventReader<'static, 'static, MyEvent>>,
 | |
| /// }
 | |
| ///
 | |
| /// // Create and store a system state once
 | |
| /// let mut world = World::new();
 | |
| /// world.init_resource::<Events<MyEvent>>();
 | |
| /// let initial_state: SystemState<EventReader<MyEvent>> = SystemState::new(&mut world);
 | |
| ///
 | |
| /// // The system state is cached in a resource
 | |
| /// world.insert_resource(CachedSystemState {
 | |
| ///     event_state: initial_state,
 | |
| /// });
 | |
| ///
 | |
| /// // Later, fetch the cached system state, saving on overhead
 | |
| /// world.resource_scope(|world, mut cached_state: Mut<CachedSystemState>| {
 | |
| ///     let mut event_reader = cached_state.event_state.get_mut(world);
 | |
| ///
 | |
| ///     for events in event_reader.read() {
 | |
| ///         println!("Hello World!");
 | |
| ///     }
 | |
| /// });
 | |
| /// ```
 | |
| pub struct SystemState<Param: SystemParam + 'static> {
 | |
|     meta: SystemMeta,
 | |
|     param_state: Param::State,
 | |
|     world_id: WorldId,
 | |
|     archetype_generation: ArchetypeGeneration,
 | |
| }
 | |
| 
 | |
| impl<Param: SystemParam> SystemState<Param> {
 | |
|     /// Creates a new [`SystemState`] with default state.
 | |
|     ///
 | |
|     /// ## Note
 | |
|     /// For users of [`SystemState::get_manual`] or [`get_manual_mut`](SystemState::get_manual_mut):
 | |
|     ///
 | |
|     /// `new` does not cache any of the world's archetypes, so you must call [`SystemState::update_archetypes`]
 | |
|     /// manually before calling `get_manual{_mut}`.
 | |
|     pub fn new(world: &mut World) -> Self {
 | |
|         let mut meta = SystemMeta::new::<Param>();
 | |
|         meta.last_run = world.change_tick().relative_to(Tick::MAX);
 | |
|         let param_state = Param::init_state(world, &mut meta);
 | |
|         Self {
 | |
|             meta,
 | |
|             param_state,
 | |
|             world_id: world.id(),
 | |
|             archetype_generation: ArchetypeGeneration::initial(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Gets the metadata for this instance.
 | |
|     #[inline]
 | |
|     pub fn meta(&self) -> &SystemMeta {
 | |
|         &self.meta
 | |
|     }
 | |
| 
 | |
|     /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
 | |
|     #[inline]
 | |
|     pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
 | |
|     where
 | |
|         Param: ReadOnlySystemParam,
 | |
|     {
 | |
|         self.validate_world(world.id());
 | |
|         self.update_archetypes(world);
 | |
|         // SAFETY: Param is read-only and doesn't allow mutable access to World.
 | |
|         // It also matches the World this SystemState was created with.
 | |
|         unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell_readonly()) }
 | |
|     }
 | |
| 
 | |
|     /// Retrieve the mutable [`SystemParam`] values.
 | |
|     #[inline]
 | |
|     pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {
 | |
|         self.validate_world(world.id());
 | |
|         self.update_archetypes(world);
 | |
|         // SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
 | |
|         unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell()) }
 | |
|     }
 | |
| 
 | |
|     /// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
 | |
|     /// by a [`Commands`](`super::Commands`) parameter to the given [`World`].
 | |
|     /// This function should be called manually after the values returned by [`SystemState::get`] and [`SystemState::get_mut`]
 | |
|     /// are finished being used.
 | |
|     pub fn apply(&mut self, world: &mut World) {
 | |
|         Param::apply(&mut self.param_state, &self.meta, world);
 | |
|     }
 | |
| 
 | |
|     /// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].
 | |
|     /// Otherwise, this returns false.
 | |
|     #[inline]
 | |
|     pub fn matches_world(&self, world_id: WorldId) -> bool {
 | |
|         self.world_id == world_id
 | |
|     }
 | |
| 
 | |
|     /// Asserts that the [`SystemState`] matches the provided world.
 | |
|     #[inline]
 | |
|     #[track_caller]
 | |
|     fn validate_world(&self, world_id: WorldId) {
 | |
|         #[inline(never)]
 | |
|         #[track_caller]
 | |
|         #[cold]
 | |
|         fn panic_mismatched(this: WorldId, other: WorldId) -> ! {
 | |
|             panic!("Encountered a mismatched World. This SystemState was created from {this:?}, but a method was called using {other:?}.");
 | |
|         }
 | |
| 
 | |
|         if !self.matches_world(world_id) {
 | |
|             panic_mismatched(self.world_id, world_id);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Updates the state's internal view of the [`World`]'s archetypes. If this is not called before fetching the parameters,
 | |
|     /// the results may not accurately reflect what is in the `world`.
 | |
|     ///
 | |
|     /// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
 | |
|     /// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
 | |
|     /// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
 | |
|     #[inline]
 | |
|     pub fn update_archetypes(&mut self, world: &World) {
 | |
|         self.update_archetypes_unsafe_world_cell(world.as_unsafe_world_cell_readonly());
 | |
|     }
 | |
| 
 | |
|     /// Updates the state's internal view of the `world`'s archetypes. If this is not called before fetching the parameters,
 | |
|     /// the results may not accurately reflect what is in the `world`.
 | |
|     ///
 | |
|     /// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
 | |
|     /// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
 | |
|     /// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
 | |
|     ///
 | |
|     /// # Note
 | |
|     ///
 | |
|     /// This method only accesses world metadata.
 | |
|     #[inline]
 | |
|     pub fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell) {
 | |
|         let archetypes = world.archetypes();
 | |
|         let old_generation =
 | |
|             std::mem::replace(&mut self.archetype_generation, archetypes.generation());
 | |
| 
 | |
|         for archetype in &archetypes[old_generation..] {
 | |
|             Param::new_archetype(&mut self.param_state, archetype, &mut self.meta);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
 | |
|     /// This will not update the state's view of the world's archetypes automatically nor increment the
 | |
|     /// world's change tick.
 | |
|     ///
 | |
|     /// For this to return accurate results, ensure [`SystemState::update_archetypes`] is called before this
 | |
|     /// function.
 | |
|     ///
 | |
|     /// Users should strongly prefer to use [`SystemState::get`] over this function.
 | |
|     #[inline]
 | |
|     pub fn get_manual<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
 | |
|     where
 | |
|         Param: ReadOnlySystemParam,
 | |
|     {
 | |
|         self.validate_world(world.id());
 | |
|         let change_tick = world.read_change_tick();
 | |
|         // SAFETY: Param is read-only and doesn't allow mutable access to World.
 | |
|         // It also matches the World this SystemState was created with.
 | |
|         unsafe { self.fetch(world.as_unsafe_world_cell_readonly(), change_tick) }
 | |
|     }
 | |
| 
 | |
|     /// Retrieve the mutable [`SystemParam`] values.  This will not update the state's view of the world's archetypes
 | |
|     /// automatically nor increment the world's change tick.
 | |
|     ///
 | |
|     /// For this to return accurate results, ensure [`SystemState::update_archetypes`] is called before this
 | |
|     /// function.
 | |
|     ///
 | |
|     /// Users should strongly prefer to use [`SystemState::get_mut`] over this function.
 | |
|     #[inline]
 | |
|     pub fn get_manual_mut<'w, 's>(
 | |
|         &'s mut self,
 | |
|         world: &'w mut World,
 | |
|     ) -> SystemParamItem<'w, 's, Param> {
 | |
|         self.validate_world(world.id());
 | |
|         let change_tick = world.change_tick();
 | |
|         // SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
 | |
|         unsafe { self.fetch(world.as_unsafe_world_cell(), change_tick) }
 | |
|     }
 | |
| 
 | |
|     /// Retrieve the [`SystemParam`] values. This will not update archetypes automatically.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
 | |
|     /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
 | |
|     /// created with.
 | |
|     #[inline]
 | |
|     pub unsafe fn get_unchecked_manual<'w, 's>(
 | |
|         &'s mut self,
 | |
|         world: UnsafeWorldCell<'w>,
 | |
|     ) -> SystemParamItem<'w, 's, Param> {
 | |
|         let change_tick = world.increment_change_tick();
 | |
|         self.fetch(world, change_tick)
 | |
|     }
 | |
| 
 | |
|     /// # Safety
 | |
|     /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
 | |
|     /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
 | |
|     /// created with.
 | |
|     #[inline]
 | |
|     unsafe fn fetch<'w, 's>(
 | |
|         &'s mut self,
 | |
|         world: UnsafeWorldCell<'w>,
 | |
|         change_tick: Tick,
 | |
|     ) -> SystemParamItem<'w, 's, Param> {
 | |
|         let param = Param::get_param(&mut self.param_state, &self.meta, world, change_tick);
 | |
|         self.meta.last_run = change_tick;
 | |
|         param
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<Param: SystemParam> FromWorld for SystemState<Param> {
 | |
|     fn from_world(world: &mut World) -> Self {
 | |
|         Self::new(world)
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// The [`System`] counter part of an ordinary function.
 | |
| ///
 | |
| /// You get this by calling [`IntoSystem::into_system`]  on a function that only accepts
 | |
| /// [`SystemParam`]s. The output of the system becomes the functions return type, while the input
 | |
| /// becomes the functions [`In`] tagged parameter or `()` if no such parameter exists.
 | |
| ///
 | |
| /// [`FunctionSystem`] must be `.initialized` before they can be run.
 | |
| ///
 | |
| /// The [`Clone`] implementation for [`FunctionSystem`] returns a new instance which
 | |
| /// is NOT initialized. The cloned system must also be `.initialized` before it can be run.
 | |
| pub struct FunctionSystem<Marker, F>
 | |
| where
 | |
|     F: SystemParamFunction<Marker>,
 | |
| {
 | |
|     func: F,
 | |
|     param_state: Option<<F::Param as SystemParam>::State>,
 | |
|     system_meta: SystemMeta,
 | |
|     world_id: Option<WorldId>,
 | |
|     archetype_generation: ArchetypeGeneration,
 | |
|     // NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls
 | |
|     marker: PhantomData<fn() -> Marker>,
 | |
| }
 | |
| 
 | |
| // De-initializes the cloned system.
 | |
| impl<Marker, F> Clone for FunctionSystem<Marker, F>
 | |
| where
 | |
|     F: SystemParamFunction<Marker> + Clone,
 | |
| {
 | |
|     fn clone(&self) -> Self {
 | |
|         Self {
 | |
|             func: self.func.clone(),
 | |
|             param_state: None,
 | |
|             system_meta: SystemMeta::new::<F>(),
 | |
|             world_id: None,
 | |
|             archetype_generation: ArchetypeGeneration::initial(),
 | |
|             marker: PhantomData,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// A marker type used to distinguish regular function systems from exclusive function systems.
 | |
| #[doc(hidden)]
 | |
| pub struct IsFunctionSystem;
 | |
| 
 | |
| impl<Marker, F> IntoSystem<F::In, F::Out, (IsFunctionSystem, Marker)> for F
 | |
| where
 | |
|     Marker: 'static,
 | |
|     F: SystemParamFunction<Marker>,
 | |
| {
 | |
|     type System = FunctionSystem<Marker, F>;
 | |
|     fn into_system(func: Self) -> Self::System {
 | |
|         FunctionSystem {
 | |
|             func,
 | |
|             param_state: None,
 | |
|             system_meta: SystemMeta::new::<F>(),
 | |
|             world_id: None,
 | |
|             archetype_generation: ArchetypeGeneration::initial(),
 | |
|             marker: PhantomData,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<Marker, F> FunctionSystem<Marker, F>
 | |
| where
 | |
|     F: SystemParamFunction<Marker>,
 | |
| {
 | |
|     /// Message shown when a system isn't initialised
 | |
|     // When lines get too long, rustfmt can sometimes refuse to format them.
 | |
|     // Work around this by storing the message separately.
 | |
|     const PARAM_MESSAGE: &'static str = "System's param_state was not found. Did you forget to initialize this system before running it?";
 | |
| }
 | |
| 
 | |
| impl<Marker, F> System for FunctionSystem<Marker, F>
 | |
| where
 | |
|     Marker: 'static,
 | |
|     F: SystemParamFunction<Marker>,
 | |
| {
 | |
|     type In = F::In;
 | |
|     type Out = F::Out;
 | |
| 
 | |
|     #[inline]
 | |
|     fn name(&self) -> Cow<'static, str> {
 | |
|         self.system_meta.name.clone()
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn component_access(&self) -> &Access<ComponentId> {
 | |
|         self.system_meta.component_access_set.combined_access()
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
 | |
|         &self.system_meta.archetype_component_access
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn is_send(&self) -> bool {
 | |
|         self.system_meta.is_send
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn is_exclusive(&self) -> bool {
 | |
|         false
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn has_deferred(&self) -> bool {
 | |
|         self.system_meta.has_deferred
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     unsafe fn run_unsafe(&mut self, input: Self::In, world: UnsafeWorldCell) -> Self::Out {
 | |
|         #[cfg(feature = "trace")]
 | |
|         let _span_guard = self.system_meta.system_span.enter();
 | |
| 
 | |
|         let change_tick = world.increment_change_tick();
 | |
| 
 | |
|         // SAFETY:
 | |
|         // - The caller has invoked `update_archetype_component_access`, which will panic
 | |
|         //   if the world does not match.
 | |
|         // - All world accesses used by `F::Param` have been registered, so the caller
 | |
|         //   will ensure that there are no data access conflicts.
 | |
|         let params = F::Param::get_param(
 | |
|             self.param_state.as_mut().expect(Self::PARAM_MESSAGE),
 | |
|             &self.system_meta,
 | |
|             world,
 | |
|             change_tick,
 | |
|         );
 | |
|         let out = self.func.run(input, params);
 | |
|         self.system_meta.last_run = change_tick;
 | |
|         out
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn apply_deferred(&mut self, world: &mut World) {
 | |
|         let param_state = self.param_state.as_mut().expect(Self::PARAM_MESSAGE);
 | |
|         F::Param::apply(param_state, &self.system_meta, world);
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn initialize(&mut self, world: &mut World) {
 | |
|         self.world_id = Some(world.id());
 | |
|         self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);
 | |
|         self.param_state = Some(F::Param::init_state(world, &mut self.system_meta));
 | |
|     }
 | |
| 
 | |
|     fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
 | |
|         assert_eq!(self.world_id, Some(world.id()), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");
 | |
|         let archetypes = world.archetypes();
 | |
|         let old_generation =
 | |
|             std::mem::replace(&mut self.archetype_generation, archetypes.generation());
 | |
| 
 | |
|         for archetype in &archetypes[old_generation..] {
 | |
|             let param_state = self.param_state.as_mut().unwrap();
 | |
|             F::Param::new_archetype(param_state, archetype, &mut self.system_meta);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #[inline]
 | |
|     fn check_change_tick(&mut self, change_tick: Tick) {
 | |
|         check_system_change_tick(
 | |
|             &mut self.system_meta.last_run,
 | |
|             change_tick,
 | |
|             self.system_meta.name.as_ref(),
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     fn default_system_sets(&self) -> Vec<InternedSystemSet> {
 | |
|         let set = crate::schedule::SystemTypeSet::<F>::new();
 | |
|         vec![set.intern()]
 | |
|     }
 | |
| 
 | |
|     fn get_last_run(&self) -> Tick {
 | |
|         self.system_meta.last_run
 | |
|     }
 | |
| 
 | |
|     fn set_last_run(&mut self, last_run: Tick) {
 | |
|         self.system_meta.last_run = last_run;
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// SAFETY: `F`'s param is [`ReadOnlySystemParam`], so this system will only read from the world.
 | |
| unsafe impl<Marker, F> ReadOnlySystem for FunctionSystem<Marker, F>
 | |
| where
 | |
|     Marker: 'static,
 | |
|     F: SystemParamFunction<Marker>,
 | |
|     F::Param: ReadOnlySystemParam,
 | |
| {
 | |
| }
 | |
| 
 | |
| /// A trait implemented for all functions that can be used as [`System`]s.
 | |
| ///
 | |
| /// This trait can be useful for making your own systems which accept other systems,
 | |
| /// sometimes called higher order systems.
 | |
| ///
 | |
| /// This should be used in combination with [`ParamSet`] when calling other systems
 | |
| /// within your system.
 | |
| /// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.
 | |
| ///
 | |
| /// # Example
 | |
| ///
 | |
| /// To create something like [`PipeSystem`], but in entirely safe code.
 | |
| ///
 | |
| /// ```
 | |
| /// use std::num::ParseIntError;
 | |
| ///
 | |
| /// use bevy_ecs::prelude::*;
 | |
| ///
 | |
| /// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`
 | |
| /// pub fn pipe<A, B, AMarker, BMarker>(
 | |
| ///     mut a: A,
 | |
| ///     mut b: B,
 | |
| /// ) -> impl FnMut(In<A::In>, ParamSet<(A::Param, B::Param)>) -> B::Out
 | |
| /// where
 | |
| ///     // We need A and B to be systems, add those bounds
 | |
| ///     A: SystemParamFunction<AMarker>,
 | |
| ///     B: SystemParamFunction<BMarker, In = A::Out>,
 | |
| /// {
 | |
| ///     // The type of `params` is inferred based on the return of this function above
 | |
| ///     move |In(a_in), mut params| {
 | |
| ///         let shared = a.run(a_in, params.p0());
 | |
| ///         b.run(shared, params.p1())
 | |
| ///     }
 | |
| /// }
 | |
| ///
 | |
| /// // Usage example for `pipe`:
 | |
| /// fn main() {
 | |
| ///     let mut world = World::default();
 | |
| ///     world.insert_resource(Message("42".to_string()));
 | |
| ///
 | |
| ///     // pipe the `parse_message_system`'s output into the `filter_system`s input
 | |
| ///     let mut piped_system = IntoSystem::into_system(pipe(parse_message, filter));
 | |
| ///     piped_system.initialize(&mut world);
 | |
| ///     assert_eq!(piped_system.run((), &mut world), Some(42));
 | |
| /// }
 | |
| ///
 | |
| /// #[derive(Resource)]
 | |
| /// struct Message(String);
 | |
| ///
 | |
| /// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {
 | |
| ///     message.0.parse::<usize>()
 | |
| /// }
 | |
| ///
 | |
| /// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {
 | |
| ///     result.ok().filter(|&n| n < 100)
 | |
| /// }
 | |
| /// ```
 | |
| /// [`PipeSystem`]: crate::system::PipeSystem
 | |
| /// [`ParamSet`]: crate::system::ParamSet
 | |
| pub trait SystemParamFunction<Marker>: Send + Sync + 'static {
 | |
|     /// The input type to this system. See [`System::In`].
 | |
|     type In;
 | |
| 
 | |
|     /// The return type of this system. See [`System::Out`].
 | |
|     type Out;
 | |
| 
 | |
|     /// The [`SystemParam`]/s used by this system to access the [`World`].
 | |
|     type Param: SystemParam;
 | |
| 
 | |
|     /// Executes this system once. See [`System::run`] or [`System::run_unsafe`].
 | |
|     fn run(&mut self, input: Self::In, param_value: SystemParamItem<Self::Param>) -> Self::Out;
 | |
| }
 | |
| 
 | |
| macro_rules! impl_system_function {
 | |
|     ($($param: ident),*) => {
 | |
|         #[allow(non_snake_case)]
 | |
|         impl<Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*) -> Out> for Func
 | |
|         where
 | |
|         for <'a> &'a mut Func:
 | |
|                 FnMut($($param),*) -> Out +
 | |
|                 FnMut($(SystemParamItem<$param>),*) -> Out, Out: 'static
 | |
|         {
 | |
|             type In = ();
 | |
|             type Out = Out;
 | |
|             type Param = ($($param,)*);
 | |
|             #[inline]
 | |
|             fn run(&mut self, _input: (), param_value: SystemParamItem< ($($param,)*)>) -> Out {
 | |
|                 // Yes, this is strange, but `rustc` fails to compile this impl
 | |
|                 // without using this function. It fails to recognize that `func`
 | |
|                 // is a function, potentially because of the multiple impls of `FnMut`
 | |
|                 #[allow(clippy::too_many_arguments)]
 | |
|                 fn call_inner<Out, $($param,)*>(
 | |
|                     mut f: impl FnMut($($param,)*)->Out,
 | |
|                     $($param: $param,)*
 | |
|                 )->Out{
 | |
|                     f($($param,)*)
 | |
|                 }
 | |
|                 let ($($param,)*) = param_value;
 | |
|                 call_inner(self, $($param),*)
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         #[allow(non_snake_case)]
 | |
|         impl<Input, Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn(In<Input>, $($param,)*) -> Out> for Func
 | |
|         where
 | |
|         for <'a> &'a mut Func:
 | |
|                 FnMut(In<Input>, $($param),*) -> Out +
 | |
|                 FnMut(In<Input>, $(SystemParamItem<$param>),*) -> Out, Out: 'static
 | |
|         {
 | |
|             type In = Input;
 | |
|             type Out = Out;
 | |
|             type Param = ($($param,)*);
 | |
|             #[inline]
 | |
|             fn run(&mut self, input: Input, param_value: SystemParamItem< ($($param,)*)>) -> Out {
 | |
|                 #[allow(clippy::too_many_arguments)]
 | |
|                 fn call_inner<Input, Out, $($param,)*>(
 | |
|                     mut f: impl FnMut(In<Input>, $($param,)*)->Out,
 | |
|                     input: In<Input>,
 | |
|                     $($param: $param,)*
 | |
|                 )->Out{
 | |
|                     f(input, $($param,)*)
 | |
|                 }
 | |
|                 let ($($param,)*) = param_value;
 | |
|                 call_inner(self, In(input), $($param),*)
 | |
|             }
 | |
|         }
 | |
|     };
 | |
| }
 | |
| 
 | |
| // Note that we rely on the highest impl to be <= the highest order of the tuple impls
 | |
| // of `SystemParam` created.
 | |
| all_tuples!(impl_system_function, 0, 16, F);
 | |
| 
 | |
| #[cfg(test)]
 | |
| mod tests {
 | |
|     use super::*;
 | |
| 
 | |
|     #[test]
 | |
|     fn into_system_type_id_consistency() {
 | |
|         fn test<T, In, Out, Marker>(function: T)
 | |
|         where
 | |
|             T: IntoSystem<In, Out, Marker> + Copy,
 | |
|         {
 | |
|             fn reference_system() {}
 | |
| 
 | |
|             use std::any::TypeId;
 | |
| 
 | |
|             let system = IntoSystem::into_system(function);
 | |
| 
 | |
|             assert_eq!(
 | |
|                 system.type_id(),
 | |
|                 function.system_type_id(),
 | |
|                 "System::type_id should be consistent with IntoSystem::system_type_id"
 | |
|             );
 | |
| 
 | |
|             assert_eq!(
 | |
|                 system.type_id(),
 | |
|                 TypeId::of::<T::System>(),
 | |
|                 "System::type_id should be consistent with TypeId::of::<T::System>()"
 | |
|             );
 | |
| 
 | |
|             assert_ne!(
 | |
|                 system.type_id(),
 | |
|                 IntoSystem::into_system(reference_system).type_id(),
 | |
|                 "Different systems should have different TypeIds"
 | |
|             );
 | |
|         }
 | |
| 
 | |
|         fn function_system() {}
 | |
| 
 | |
|         test(function_system);
 | |
|     }
 | |
| }
 |