Skip to content

Commit cbbacfa

Browse files
migrate WorldCell to InteriorMutableWorld
1 parent 9d4cc02 commit cbbacfa

File tree

2 files changed

+44
-40
lines changed

2 files changed

+44
-40
lines changed

crates/bevy_ecs/src/world/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use bevy_ptr::{OwningPtr, Ptr};
2626
use bevy_utils::tracing::warn;
2727
use std::{
2828
any::TypeId,
29+
cell::UnsafeCell,
2930
fmt,
3031
sync::atomic::{AtomicU32, Ordering},
3132
};
@@ -62,8 +63,8 @@ pub struct World {
6263
pub(crate) storages: Storages,
6364
pub(crate) bundles: Bundles,
6465
pub(crate) removed_components: SparseSet<ComponentId, Vec<Entity>>,
65-
/// Access cache used by [WorldCell].
66-
pub(crate) archetype_component_access: ArchetypeComponentAccess,
66+
/// Access cache used by [WorldCell]. Is only accessed in the `Drop` impl of `WorldCell`.
67+
pub(crate) archetype_component_access: UnsafeCell<ArchetypeComponentAccess>,
6768
pub(crate) change_tick: AtomicU32,
6869
pub(crate) last_change_tick: u32,
6970
}
@@ -1096,11 +1097,7 @@ impl World {
10961097
#[inline]
10971098
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
10981099
// SAFETY: unique world access
1099-
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
1100-
unsafe {
1101-
self.as_interior_mutable()
1102-
.get_non_send_mut_with_id::<R>(component_id)
1103-
}
1100+
unsafe { self.as_interior_mutable().get_non_send_resource_mut() }
11041101
}
11051102

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

crates/bevy_ecs/src/world/world_cell.rs

Lines changed: 40 additions & 33 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,16 @@ 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>())?;
264+
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
261265
let archetype_component_id = self
262266
.world
263-
.get_non_send_archetype_component_id(component_id)?;
267+
.storages()
268+
.non_send_resources
269+
.get(component_id)?
270+
.id();
264271
WorldBorrow::try_new(
265-
// SAFETY: ComponentId matches TypeId
266-
|| unsafe { self.world.get_non_send_with_id(component_id) },
272+
// SAFETY: access is checked by WorldBorrowMut
273+
|| unsafe { self.world.get_non_send_resource::<T>() },
267274
archetype_component_id,
268275
self.access.clone(),
269276
)
@@ -290,17 +297,16 @@ impl<'w> WorldCell<'w> {
290297

291298
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
292299
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>())?;
300+
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
294301
let archetype_component_id = self
295302
.world
296-
.get_non_send_archetype_component_id(component_id)?;
303+
.storages()
304+
.non_send_resources
305+
.get(component_id)?
306+
.id();
297307
WorldBorrowMut::try_new(
298308
// 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-
},
309+
|| unsafe { self.world.get_non_send_resource_mut::<T>() },
304310
archetype_component_id,
305311
self.access.clone(),
306312
)
@@ -416,10 +422,11 @@ mod tests {
416422
let u32_archetype_component_id = world
417423
.get_resource_archetype_component_id(u32_component_id)
418424
.unwrap();
419-
assert_eq!(world.archetype_component_access.access.len(), 1);
425+
assert_eq!(world.archetype_component_access.get_mut().access.len(), 1);
420426
assert_eq!(
421427
world
422428
.archetype_component_access
429+
.get_mut()
423430
.access
424431
.get(u32_archetype_component_id),
425432
Some(&BASE_ACCESS),

0 commit comments

Comments
 (0)