diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index c2c411a8de..f3de68ccf5 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -229,7 +229,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { unsafe fn get_param<'w, 's>( state: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { ParamSet { @@ -407,7 +407,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { unsafe fn get_param<'w, 's>( state: &'s mut Self::State, system_meta: &#path::system::SystemMeta, - world: &'w #path::world::World, + world: #path::world::unsafe_world_cell::UnsafeWorldCell<'w>, change_tick: #path::component::Tick, ) -> Self::Item<'w, 's> { let (#(#tuple_patterns,)*) = < diff --git a/crates/bevy_ecs/src/removal_detection.rs b/crates/bevy_ecs/src/removal_detection.rs index 139c092bb8..f2c91d97dd 100644 --- a/crates/bevy_ecs/src/removal_detection.rs +++ b/crates/bevy_ecs/src/removal_detection.rs @@ -8,7 +8,7 @@ use crate::{ prelude::Local, storage::SparseSet, system::{ReadOnlySystemParam, SystemMeta, SystemParam}, - world::World, + world::{unsafe_world_cell::UnsafeWorldCell, World}, }; use std::{ @@ -264,9 +264,9 @@ unsafe impl<'a> SystemParam for &'a RemovedComponentEvents { unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, _system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { - world.removed_components() + world.world_metadata().removed_components() } } diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 1809b251cf..8bda168b78 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -291,7 +291,12 @@ impl SystemState { world: &'w World, change_tick: Tick, ) -> SystemParamItem<'w, 's, Param> { - let param = Param::get_param(&mut self.param_state, &self.meta, world, change_tick); + let param = Param::get_param( + &mut self.param_state, + &self.meta, + world.as_unsafe_world_cell_migration_internal(), + change_tick, + ); self.meta.last_run = change_tick; param } @@ -481,7 +486,7 @@ where let params = F::Param::get_param( self.param_state.as_mut().expect(Self::PARAM_MESSAGE), &self.system_meta, - world, + world.as_unsafe_world_cell_migration_internal(), change_tick, ); let out = self.func.run(input, params); diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 9ea7f5ed3f..ea35eb06c8 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -9,7 +9,7 @@ use crate::{ Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQuery, WorldQuery, }, system::{Query, SystemMeta}, - world::{FromWorld, World}, + world::{unsafe_world_cell::UnsafeWorldCell, FromWorld, World}, }; use bevy_ecs_macros::impl_param_set; pub use bevy_ecs_macros::Resource; @@ -127,14 +127,13 @@ pub unsafe trait SystemParam: Sized { /// # Safety /// - /// This call might use any of the [`World`] accesses that were registered in [`Self::init_state`]. - /// - None of those accesses may conflict with any other [`SystemParam`]s - /// that exist at the same time, including those on other threads. + /// - The passed [`UnsafeWorldCell`] must have access to any world data + /// registered in [`init_state`](SystemParam::init_state). /// - `world` must be the same `World` that was used to initialize [`state`](SystemParam::init_state). unsafe fn get_param<'world, 'state>( state: &'state mut Self::State, system_meta: &SystemMeta, - world: &'world World, + world: UnsafeWorldCell<'world>, change_tick: Tick, ) -> Self::Item<'world, 'state>; } @@ -192,10 +191,19 @@ unsafe impl SystemPara unsafe fn get_param<'w, 's>( state: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { - Query::new(world, state, system_meta.last_run, change_tick, false) + Query::new( + // SAFETY: We have registered all of the query's world accesses, + // so the caller ensures that `world` has permission to access any + // world data that the query needs. + world.unsafe_world(), + state, + system_meta.last_run, + change_tick, + false, + ) } } @@ -329,7 +337,7 @@ fn assert_component_access_compatibility( /// ``` pub struct ParamSet<'w, 's, T: SystemParam> { param_states: &'s mut T::State, - world: &'w World, + world: UnsafeWorldCell<'w>, system_meta: SystemMeta, change_tick: Tick, } @@ -435,11 +443,10 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { let (ptr, ticks) = world - .as_unsafe_world_cell_migration_internal() .get_resource_with_ticks(component_id) .unwrap_or_else(|| { panic!( @@ -476,11 +483,10 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { world - .as_unsafe_world_cell_migration_internal() .get_resource_with_ticks(component_id) .map(|(ptr, ticks)| Res { value: ptr.deref(), @@ -530,11 +536,10 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { let value = world - .as_unsafe_world_cell_migration_internal() .get_resource_mut_by_id(component_id) .unwrap_or_else(|| { panic!( @@ -568,11 +573,10 @@ unsafe impl<'a, T: Resource> SystemParam for Option> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { world - .as_unsafe_world_cell_migration_internal() .get_resource_mut_by_id(component_id) .map(|value| ResMut { value: value.value.deref_mut::(), @@ -621,10 +625,11 @@ unsafe impl SystemParam for &'_ World { unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, _system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { - world + // SAFETY: Read-only access to the entire world was registerd in `init_state`. + world.world() } } @@ -742,7 +747,7 @@ unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> { unsafe fn get_param<'w, 's>( state: &'s mut Self::State, _system_meta: &SystemMeta, - _world: &'w World, + _world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { Local(state.get()) @@ -916,7 +921,7 @@ unsafe impl SystemParam for Deferred<'_, T> { unsafe fn get_param<'w, 's>( state: &'s mut Self::State, _system_meta: &SystemMeta, - _world: &'w World, + _world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { Deferred(state.get()) @@ -1022,11 +1027,10 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { let (ptr, ticks) = world - .as_unsafe_world_cell_migration_internal() .get_non_send_with_ticks(component_id) .unwrap_or_else(|| { panic!( @@ -1061,11 +1065,10 @@ unsafe impl SystemParam for Option> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { world - .as_unsafe_world_cell_migration_internal() .get_non_send_with_ticks(component_id) .map(|(ptr, ticks)| NonSend { value: ptr.deref(), @@ -1114,11 +1117,10 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { let (ptr, ticks) = world - .as_unsafe_world_cell_migration_internal() .get_non_send_with_ticks(component_id) .unwrap_or_else(|| { panic!( @@ -1147,11 +1149,10 @@ unsafe impl<'a, T: 'static> SystemParam for Option> { unsafe fn get_param<'w, 's>( &mut component_id: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { world - .as_unsafe_world_cell_migration_internal() .get_non_send_with_ticks(component_id) .map(|(ptr, ticks)| NonSendMut { value: ptr.assert_unique().deref_mut(), @@ -1174,7 +1175,7 @@ unsafe impl<'a> SystemParam for &'a Archetypes { unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, _system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { world.archetypes() @@ -1195,7 +1196,7 @@ unsafe impl<'a> SystemParam for &'a Components { unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, _system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { world.components() @@ -1216,7 +1217,7 @@ unsafe impl<'a> SystemParam for &'a Entities { unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, _system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { world.entities() @@ -1237,7 +1238,7 @@ unsafe impl<'a> SystemParam for &'a Bundles { unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, _system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { world.bundles() @@ -1286,7 +1287,7 @@ unsafe impl SystemParam for SystemChangeTick { unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, system_meta: &SystemMeta, - _world: &'w World, + _world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { SystemChangeTick { @@ -1356,7 +1357,7 @@ unsafe impl SystemParam for SystemName<'_> { unsafe fn get_param<'w, 's>( name: &'s mut Self::State, _system_meta: &SystemMeta, - _world: &'w World, + _world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { SystemName { name } @@ -1398,7 +1399,7 @@ macro_rules! impl_system_param_tuple { unsafe fn get_param<'w, 's>( state: &'s mut Self::State, _system_meta: &SystemMeta, - _world: &'w World, + _world: UnsafeWorldCell<'w>, _change_tick: Tick, ) -> Self::Item<'w, 's> { @@ -1521,7 +1522,7 @@ unsafe impl SystemParam for StaticSystemParam<'_, '_, unsafe fn get_param<'world, 'state>( state: &'state mut Self::State, system_meta: &SystemMeta, - world: &'world World, + world: UnsafeWorldCell<'world>, change_tick: Tick, ) -> Self::Item<'world, 'state> { // SAFETY: Defer to the safety of P::SystemParam @@ -1539,7 +1540,7 @@ unsafe impl SystemParam for PhantomData { unsafe fn get_param<'world, 'state>( _state: &'state mut Self::State, _system_meta: &SystemMeta, - _world: &'world World, + _world: UnsafeWorldCell<'world>, _change_tick: Tick, ) -> Self::Item<'world, 'state> { PhantomData diff --git a/crates/bevy_ecs/src/world/identifier.rs b/crates/bevy_ecs/src/world/identifier.rs index 55e2b6a5fa..952f65e6be 100644 --- a/crates/bevy_ecs/src/world/identifier.rs +++ b/crates/bevy_ecs/src/world/identifier.rs @@ -6,6 +6,8 @@ use crate::{ }; use std::sync::atomic::{AtomicUsize, Ordering}; +use super::unsafe_world_cell::UnsafeWorldCell; + #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] // We use usize here because that is the largest `Atomic` we want to require /// A unique identifier for a [`World`]. @@ -56,10 +58,10 @@ unsafe impl SystemParam for WorldId { unsafe fn get_param<'world, 'state>( _: &'state mut Self::State, _: &crate::system::SystemMeta, - world: &'world super::World, + world: UnsafeWorldCell<'world>, _: Tick, ) -> Self::Item<'world, 'state> { - world.id + world.world_metadata().id() } } diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index 99231fe3f3..54afd95f73 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -144,7 +144,7 @@ impl<'w> UnsafeWorldCell<'w> { /// # Safety /// - must not be used in a way that would conflict with any /// live exclusive borrows on world data - unsafe fn unsafe_world(self) -> &'w World { + pub(crate) unsafe fn unsafe_world(self) -> &'w World { // SAFETY: // - caller ensures that the returned `&World` is not used in a way that would conflict // with any existing mutable borrows of world data diff --git a/crates/bevy_render/src/extract_param.rs b/crates/bevy_render/src/extract_param.rs index 898dfe0e28..57a1267ce5 100644 --- a/crates/bevy_render/src/extract_param.rs +++ b/crates/bevy_render/src/extract_param.rs @@ -3,6 +3,7 @@ use bevy_ecs::{ component::Tick, prelude::*, system::{ReadOnlySystemParam, SystemMeta, SystemParam, SystemParamItem, SystemState}, + world::unsafe_world_cell::UnsafeWorldCell, }; use std::ops::{Deref, DerefMut}; @@ -76,7 +77,7 @@ where unsafe fn get_param<'w, 's>( state: &'s mut Self::State, system_meta: &SystemMeta, - world: &'w World, + world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Self::Item<'w, 's> { // SAFETY: