Path: blob/main/crates/bevy_ecs/src/system/exclusive_system_param.rs
6604 views
use crate::{1prelude::{FromWorld, QueryState},2query::{QueryData, QueryFilter},3system::{Local, SystemMeta, SystemParam, SystemState},4world::World,5};6use bevy_platform::cell::SyncCell;7use core::marker::PhantomData;8use variadics_please::all_tuples;910/// A parameter that can be used in an exclusive system (a system with an `&mut World` parameter).11/// Any parameters implementing this trait must come after the `&mut World` parameter.12#[diagnostic::on_unimplemented(13message = "`{Self}` can not be used as a parameter for an exclusive system",14label = "invalid system parameter"15)]16pub trait ExclusiveSystemParam: Sized {17/// Used to store data which persists across invocations of a system.18type State: Send + Sync + 'static;19/// The item type returned when constructing this system param.20/// See [`SystemParam::Item`].21type Item<'s>: ExclusiveSystemParam<State = Self::State>;2223/// Creates a new instance of this param's [`State`](Self::State).24fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self::State;2526/// Creates a parameter to be passed into an [`ExclusiveSystemParamFunction`].27///28/// [`ExclusiveSystemParamFunction`]: super::ExclusiveSystemParamFunction29fn get_param<'s>(state: &'s mut Self::State, system_meta: &SystemMeta) -> Self::Item<'s>;30}3132/// Shorthand way of accessing the associated type [`ExclusiveSystemParam::Item`]33/// for a given [`ExclusiveSystemParam`].34pub type ExclusiveSystemParamItem<'s, P> = <P as ExclusiveSystemParam>::Item<'s>;3536impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> ExclusiveSystemParam37for &'a mut QueryState<D, F>38{39type State = QueryState<D, F>;40type Item<'s> = &'s mut QueryState<D, F>;4142fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {43QueryState::new(world)44}4546fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {47state48}49}5051impl<'a, P: SystemParam + 'static> ExclusiveSystemParam for &'a mut SystemState<P> {52type State = SystemState<P>;53type Item<'s> = &'s mut SystemState<P>;5455fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {56SystemState::new(world)57}5859fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {60state61}62}6364impl<'_s, T: FromWorld + Send + 'static> ExclusiveSystemParam for Local<'_s, T> {65type State = SyncCell<T>;66type Item<'s> = Local<'s, T>;6768fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {69SyncCell::new(T::from_world(world))70}7172fn get_param<'s>(state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {73Local(state.get())74}75}7677impl<S: ?Sized> ExclusiveSystemParam for PhantomData<S> {78type State = ();79type Item<'s> = PhantomData<S>;8081fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {}8283fn get_param<'s>(_state: &'s mut Self::State, _system_meta: &SystemMeta) -> Self::Item<'s> {84PhantomData85}86}8788macro_rules! impl_exclusive_system_param_tuple {89($(#[$meta:meta])* $($param: ident),*) => {90#[expect(91clippy::allow_attributes,92reason = "This is within a macro, and as such, the below lints may not always apply."93)]94#[allow(95non_snake_case,96reason = "Certain variable names are provided by the caller, not by us."97)]98#[allow(99unused_variables,100reason = "Zero-length tuples won't use any of the parameters."101)]102$(#[$meta])*103impl<$($param: ExclusiveSystemParam),*> ExclusiveSystemParam for ($($param,)*) {104type State = ($($param::State,)*);105type Item<'s> = ($($param::Item<'s>,)*);106107#[inline]108fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {109(($($param::init(world, system_meta),)*))110}111112#[inline]113fn get_param<'s>(114state: &'s mut Self::State,115system_meta: &SystemMeta,116) -> Self::Item<'s> {117let ($($param,)*) = state;118#[allow(119clippy::unused_unit,120reason = "Zero-length tuples won't have any params to get."121)]122($($param::get_param($param, system_meta),)*)123}124}125};126}127128all_tuples!(129#[doc(fake_variadic)]130impl_exclusive_system_param_tuple,1310,13216,133P134);135136#[cfg(test)]137mod tests {138use crate::{schedule::Schedule, system::Local, world::World};139use alloc::vec::Vec;140use bevy_ecs_macros::Resource;141use core::marker::PhantomData;142143#[test]144fn test_exclusive_system_params() {145#[derive(Resource, Default)]146struct Res {147test_value: u32,148}149150fn my_system(world: &mut World, mut local: Local<u32>, _phantom: PhantomData<Vec<u32>>) {151assert_eq!(world.resource::<Res>().test_value, *local);152*local += 1;153world.resource_mut::<Res>().test_value += 1;154}155156let mut schedule = Schedule::default();157schedule.add_systems(my_system);158159let mut world = World::default();160world.init_resource::<Res>();161162schedule.run(&mut world);163schedule.run(&mut world);164165assert_eq!(2, world.get_resource::<Res>().unwrap().test_value);166}167}168169170