Skip to content

Commit 2597f0d

Browse files
migrate WorldCell to InteriorMutableWorld
1 parent 913a272 commit 2597f0d

File tree

2 files changed

+39
-49
lines changed

2 files changed

+39
-49
lines changed

crates/bevy_ecs/src/world/mod.rs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use bevy_ptr::{OwningPtr, Ptr};
2525
use bevy_utils::tracing::warn;
2626
use std::{
2727
any::TypeId,
28+
cell::UnsafeCell,
2829
fmt,
2930
sync::atomic::{AtomicU32, Ordering},
3031
};
@@ -61,8 +62,8 @@ pub struct World {
6162
pub(crate) storages: Storages,
6263
pub(crate) bundles: Bundles,
6364
pub(crate) removed_components: SparseSet<ComponentId, Vec<Entity>>,
64-
/// Access cache used by [WorldCell].
65-
pub(crate) archetype_component_access: ArchetypeComponentAccess,
65+
/// Access cache used by [WorldCell]. Is only accessed in the `Drop` impl of `WorldCell`.
66+
pub(crate) archetype_component_access: UnsafeCell<ArchetypeComponentAccess>,
6667
main_thread_validator: MainThreadValidator,
6768
pub(crate) change_tick: AtomicU32,
6869
pub(crate) last_change_tick: u32,
@@ -995,16 +996,8 @@ impl World {
995996
/// Otherwise returns [None]
996997
#[inline]
997998
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
998-
self.validate_non_send_access::<R>();
999-
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
1000-
// SAFETY:
1001-
// - `component_id` is type `R`
1002-
// - we have unique access
1003-
// - main thread is validated
1004-
unsafe {
1005-
self.as_interior_mutable()
1006-
.get_resource_mut_with_id(component_id)
1007-
}
999+
// SAFETY: unique access
1000+
unsafe { self.as_interior_mutable().get_non_send_resource_mut() }
10081001
}
10091002

10101003
// Shorthand helper function for getting the data and change ticks for a resource.

crates/bevy_ecs/src/world/world_cell.rs

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ use std::{
1414
rc::Rc,
1515
};
1616

17+
use super::interior_mutable_world::InteriorMutableWorld;
18+
1719
/// Exposes safe mutable access to multiple resources at a time in a World. Attempting to access
1820
/// World in a way that violates Rust's mutability rules will panic thanks to runtime checks.
1921
pub struct WorldCell<'w> {
20-
pub(crate) world: &'w mut World,
22+
pub(crate) world: InteriorMutableWorld<'w>,
2123
pub(crate) access: Rc<RefCell<ArchetypeComponentAccess>>,
2224
}
2325

@@ -76,8 +78,16 @@ impl ArchetypeComponentAccess {
7678
impl<'w> Drop for WorldCell<'w> {
7779
fn drop(&mut self) {
7880
let mut access = self.access.borrow_mut();
79-
// give world ArchetypeComponentAccess back to reuse allocations
80-
std::mem::swap(&mut self.world.archetype_component_access, &mut *access);
81+
82+
{
83+
// SAFETY: we only swap `archetype_component_access`
84+
let world = unsafe { self.world.world() };
85+
// SAFETY: the WorldCell has exclusive world access
86+
let world_cached_access = unsafe { &mut *world.archetype_component_access.get() };
87+
88+
// give world ArchetypeComponentAccess back to reuse allocations
89+
std::mem::swap(world_cached_access, &mut *access);
90+
}
8191
}
8292
}
8393

@@ -175,25 +185,25 @@ impl<'w> WorldCell<'w> {
175185
pub(crate) fn new(world: &'w mut World) -> Self {
176186
// this is cheap because ArchetypeComponentAccess::new() is const / allocation free
177187
let access = std::mem::replace(
178-
&mut world.archetype_component_access,
188+
world.archetype_component_access.get_mut(),
179189
ArchetypeComponentAccess::new(),
180190
);
181191
// world's ArchetypeComponentAccess is recycled to cut down on allocations
182192
Self {
183-
world,
193+
world: world.as_interior_mutable(),
184194
access: Rc::new(RefCell::new(access)),
185195
}
186196
}
187197

188198
/// Gets a reference to the resource of the given type
189199
pub fn get_resource<T: Resource>(&self) -> Option<WorldBorrow<'_, T>> {
190-
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
191-
let archetype_component_id = self
192-
.world
193-
.get_resource_archetype_component_id(component_id)?;
200+
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
201+
202+
let archetype_component_id = self.world.storages().resources.get(component_id)?.id();
203+
194204
WorldBorrow::try_new(
195-
// SAFETY: ComponentId matches TypeId
196-
|| unsafe { self.world.get_resource_with_id(component_id) },
205+
// SAFETY: access is checked by WorldBorrow
206+
|| unsafe { self.world.get_resource::<T>() },
197207
archetype_component_id,
198208
self.access.clone(),
199209
)
@@ -220,17 +230,11 @@ impl<'w> WorldCell<'w> {
220230

221231
/// Gets a mutable reference to the resource of the given type
222232
pub fn get_resource_mut<T: Resource>(&self) -> Option<WorldBorrowMut<'_, T>> {
223-
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
224-
let archetype_component_id = self
225-
.world
226-
.get_resource_archetype_component_id(component_id)?;
233+
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
234+
let archetype_component_id = self.world.storages().resources.get(component_id)?.id();
227235
WorldBorrowMut::try_new(
228-
// SAFETY: ComponentId matches TypeId and access is checked by WorldBorrowMut
229-
|| unsafe {
230-
self.world
231-
.as_interior_mutable_migration_internal()
232-
.get_resource_mut_with_id(component_id)
233-
},
236+
// SAFETY: access is checked by WorldBorrowMut
237+
|| unsafe { self.world.get_resource_mut::<T>() },
234238
archetype_component_id,
235239
self.access.clone(),
236240
)
@@ -257,13 +261,11 @@ impl<'w> WorldCell<'w> {
257261

258262
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
259263
pub fn get_non_send_resource<T: 'static>(&self) -> Option<WorldBorrow<'_, T>> {
260-
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
261-
let archetype_component_id = self
262-
.world
263-
.get_resource_archetype_component_id(component_id)?;
264+
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
265+
let archetype_component_id = self.world.storages().resources.get(component_id)?.id();
264266
WorldBorrow::try_new(
265-
// SAFETY: ComponentId matches TypeId
266-
|| unsafe { self.world.get_non_send_with_id(component_id) },
267+
// SAFETY: access is checked by WorldBorrowMut
268+
|| unsafe { self.world.get_non_send_resource::<T>() },
267269
archetype_component_id,
268270
self.access.clone(),
269271
)
@@ -290,17 +292,11 @@ impl<'w> WorldCell<'w> {
290292

291293
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
292294
pub fn get_non_send_resource_mut<T: 'static>(&self) -> Option<WorldBorrowMut<'_, T>> {
293-
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
294-
let archetype_component_id = self
295-
.world
296-
.get_resource_archetype_component_id(component_id)?;
295+
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
296+
let archetype_component_id = self.world.storages().resources.get(component_id)?.id();
297297
WorldBorrowMut::try_new(
298298
// SAFETY: access is checked by WorldBorrowMut
299-
|| unsafe {
300-
self.world
301-
.as_interior_mutable_migration_internal()
302-
.get_non_send_resource_mut::<T>()
303-
},
299+
|| unsafe { self.world.get_non_send_resource_mut::<T>() },
304300
archetype_component_id,
305301
self.access.clone(),
306302
)
@@ -416,10 +412,11 @@ mod tests {
416412
let u32_archetype_component_id = world
417413
.get_resource_archetype_component_id(u32_component_id)
418414
.unwrap();
419-
assert_eq!(world.archetype_component_access.access.len(), 1);
415+
assert_eq!(world.archetype_component_access.get_mut().access.len(), 1);
420416
assert_eq!(
421417
world
422418
.archetype_component_access
419+
.get_mut()
423420
.access
424421
.get(u32_archetype_component_id),
425422
Some(&BASE_ACCESS),

0 commit comments

Comments
 (0)