Skip to content

Commit 695d3d8

Browse files
move unchecked methods from world to InteriorMutableWorld
1 parent 5475281 commit 695d3d8

File tree

6 files changed

+63
-90
lines changed

6 files changed

+63
-90
lines changed

crates/bevy_asset/src/reflect.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
148148
get_unchecked_mut: |world, handle| {
149149
let assets = unsafe {
150150
world
151-
.get_resource_unchecked_mut::<Assets<A>>()
151+
.as_interior_mutable()
152+
.get_resource_mut::<Assets<A>>()
152153
.unwrap()
153154
.into_inner()
154155
};

crates/bevy_ecs/src/reflect.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,13 @@ impl<C: Resource + Reflect + FromWorld> FromType<C> for ReflectResource {
385385
// SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
386386
// reference or multiple immutable ones alive at any given point
387387
unsafe {
388-
world.get_resource_unchecked_mut::<C>().map(|res| Mut {
389-
value: res.value as &mut dyn Reflect,
390-
ticks: res.ticks,
391-
})
388+
world
389+
.as_interior_mutable()
390+
.get_resource_mut::<C>()
391+
.map(|res| Mut {
392+
value: res.value as &mut dyn Reflect,
393+
ticks: res.ticks,
394+
})
392395
}
393396
},
394397
copy: |source_world, destination_world| {

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,8 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for ResMutState<T> {
515515
change_tick: u32,
516516
) -> Self::Item {
517517
let value = world
518-
.get_resource_unchecked_mut_with_id(state.component_id)
518+
.as_interior_mutable()
519+
.get_resource_mut_with_id(state.component_id)
519520
.unwrap_or_else(|| {
520521
panic!(
521522
"Resource requested by {} does not exist: {}",
@@ -562,7 +563,8 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for OptionResMutState<T> {
562563
change_tick: u32,
563564
) -> Self::Item {
564565
world
565-
.get_resource_unchecked_mut_with_id(state.0.component_id)
566+
.as_interior_mutable()
567+
.get_resource_mut_with_id(state.0.component_id)
566568
.map(|value| ResMut {
567569
value: value.value,
568570
ticks: Ticks {

crates/bevy_ecs/src/world/interior_mutable_world.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl<'w> InteriorMutableWorld<'w> {
102102
#[inline]
103103
pub unsafe fn get_resource_mut<R: Resource>(&self) -> Option<Mut<'w, R>> {
104104
let component_id = self.0.components.get_resource_id(TypeId::of::<R>())?;
105-
unsafe { self.0.get_resource_unchecked_mut_with_id(component_id) }
105+
unsafe { self.get_resource_mut_with_id(component_id) }
106106
}
107107

108108
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
@@ -152,6 +152,43 @@ impl<'w> InteriorMutableWorld<'w> {
152152
pub unsafe fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'w, R>> {
153153
let component_id = self.0.components.get_resource_id(TypeId::of::<R>())?;
154154
// SAFETY: safety requirement is deferred to the caller
155-
unsafe { self.0.get_non_send_unchecked_mut_with_id(component_id) }
155+
unsafe { self.get_non_send_mut_with_id(component_id) }
156+
}
157+
}
158+
159+
impl<'w> InteriorMutableWorld<'w> {
160+
/// # Safety
161+
/// - `component_id` must be assigned to a component of type `R`
162+
/// - Caller must ensure this doesn't violate Rust mutability rules for the given resource.
163+
/// - resource is either Send+Sync or the main thread is validated
164+
#[inline]
165+
pub(crate) unsafe fn get_resource_mut_with_id<R>(
166+
&self,
167+
component_id: ComponentId,
168+
) -> Option<Mut<'w, R>> {
169+
let (ptr, ticks) = self.0.get_resource_with_ticks(component_id)?;
170+
Some(Mut {
171+
// caller ensures aliasing rules, ptr is of type `R`
172+
value: unsafe { ptr.assert_unique().deref_mut() },
173+
ticks: Ticks {
174+
// caller ensures aliasing rules
175+
component_ticks: unsafe { ticks.deref_mut() },
176+
last_change_tick: self.0.last_change_tick(),
177+
change_tick: self.0.read_change_tick(),
178+
},
179+
})
180+
}
181+
182+
/// # Safety
183+
/// - `component_id` must be assigned to a component of type `R`.
184+
/// - Caller must ensure this doesn't violate Rust mutability rules for the given resource.
185+
#[inline]
186+
pub(crate) unsafe fn get_non_send_mut_with_id<R: 'static>(
187+
&self,
188+
component_id: ComponentId,
189+
) -> Option<Mut<'w, R>> {
190+
self.0.validate_non_send_access::<R>();
191+
// SAFETY: we validated nonsend access, the rest of the requirements are deferred to caller
192+
unsafe { self.get_resource_mut_with_id(component_id) }
156193
}
157194
}

crates/bevy_ecs/src/world/mod.rs

Lines changed: 7 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::{
2020
storage::{ResourceData, SparseSet, Storages},
2121
system::Resource,
2222
};
23-
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
23+
use bevy_ptr::{OwningPtr, Ptr};
2424
use bevy_utils::tracing::warn;
2525
use std::{
2626
any::TypeId,
@@ -907,7 +907,7 @@ impl World {
907907
#[inline]
908908
pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
909909
// SAFETY: unique world access
910-
unsafe { self.get_resource_unchecked_mut() }
910+
unsafe { self.as_interior_mutable().get_resource_mut() }
911911
}
912912

913913
// PERF: optimize this to avoid redundant lookups
@@ -924,18 +924,6 @@ impl World {
924924
self.resource_mut()
925925
}
926926

927-
/// Gets a mutable reference to the resource of the given type, if it exists
928-
/// Otherwise returns [None]
929-
///
930-
/// # Safety
931-
/// This will allow aliased mutable access to the given resource type. The caller must ensure
932-
/// that there is either only one mutable access or multiple immutable accesses at a time.
933-
#[inline]
934-
pub unsafe fn get_resource_unchecked_mut<R: Resource>(&self) -> Option<Mut<'_, R>> {
935-
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
936-
self.get_resource_unchecked_mut_with_id(component_id)
937-
}
938-
939927
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
940928
///
941929
/// # Panics
@@ -990,19 +978,7 @@ impl World {
990978
#[inline]
991979
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
992980
// SAFETY: unique world access
993-
unsafe { self.get_non_send_resource_unchecked_mut() }
994-
}
995-
996-
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
997-
/// Otherwise returns [None]
998-
///
999-
/// # Safety
1000-
/// This will allow aliased mutable access to the given non-send resource type. The caller must
1001-
/// ensure that there is either only one mutable access or multiple immutable accesses at a time.
1002-
#[inline]
1003-
pub unsafe fn get_non_send_resource_unchecked_mut<R: 'static>(&self) -> Option<Mut<'_, R>> {
1004-
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
1005-
self.get_non_send_unchecked_mut_with_id(component_id)
981+
unsafe { self.as_interior_mutable().get_non_send_resource_mut() }
1006982
}
1007983

1008984
// Shorthand helper function for getting the data and change ticks for a resource.
@@ -1271,25 +1247,6 @@ impl World {
12711247
.map(|ptr| ptr.deref())
12721248
}
12731249

1274-
/// # Safety
1275-
/// `component_id` must be assigned to a component of type `R`
1276-
/// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
1277-
#[inline]
1278-
pub(crate) unsafe fn get_resource_unchecked_mut_with_id<R>(
1279-
&self,
1280-
component_id: ComponentId,
1281-
) -> Option<Mut<'_, R>> {
1282-
let (ptr, ticks) = self.get_resource_with_ticks(component_id)?;
1283-
Some(Mut {
1284-
value: ptr.assert_unique().deref_mut(),
1285-
ticks: Ticks {
1286-
component_ticks: ticks.deref_mut(),
1287-
last_change_tick: self.last_change_tick(),
1288-
change_tick: self.read_change_tick(),
1289-
},
1290-
})
1291-
}
1292-
12931250
/// # Safety
12941251
/// `component_id` must be assigned to a component of type `R`
12951252
#[inline]
@@ -1301,18 +1258,6 @@ impl World {
13011258
self.get_resource_with_id(component_id)
13021259
}
13031260

1304-
/// # Safety
1305-
/// `component_id` must be assigned to a component of type `R`.
1306-
/// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
1307-
#[inline]
1308-
pub(crate) unsafe fn get_non_send_unchecked_mut_with_id<R: 'static>(
1309-
&self,
1310-
component_id: ComponentId,
1311-
) -> Option<Mut<'_, R>> {
1312-
self.validate_non_send_access::<R>();
1313-
self.get_resource_unchecked_mut_with_id(component_id)
1314-
}
1315-
13161261
/// Inserts a new resource with the given `value`. Will replace the value if it already existed.
13171262
///
13181263
/// **You should prefer to use the typed API [`World::insert_resource`] where possible and only
@@ -1459,28 +1404,11 @@ impl World {
14591404
/// use this in cases where the actual types are not known at compile time.**
14601405
#[inline]
14611406
pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
1462-
let info = self.components.get_info(component_id)?;
1463-
if !info.is_send_and_sync() {
1464-
self.validate_non_send_access_untyped(info.name());
1407+
// SAFETY: unique world access
1408+
unsafe {
1409+
self.as_interior_mutable()
1410+
.get_resource_mut_by_id(component_id)
14651411
}
1466-
1467-
let (ptr, ticks) = self.get_resource_with_ticks(component_id)?;
1468-
1469-
// SAFE: This function has exclusive access to the world so nothing aliases `ticks`.
1470-
let ticks = Ticks {
1471-
// SAFETY:
1472-
// - index is in-bounds because the column is initialized and non-empty
1473-
// - no other reference to the ticks of the same row can exist at the same time
1474-
component_ticks: unsafe { ticks.deref_mut() },
1475-
last_change_tick: self.last_change_tick(),
1476-
change_tick: self.read_change_tick(),
1477-
};
1478-
1479-
Some(MutUntyped {
1480-
// SAFETY: This function has exclusive access to the world so nothing aliases `ptr`.
1481-
value: unsafe { ptr.assert_unique() },
1482-
ticks,
1483-
})
14841412
}
14851413

14861414
/// Removes the resource of a given type, if it exists. Otherwise returns [None].

crates/bevy_ecs/src/world/world_cell.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ impl<'w> WorldCell<'w> {
226226
// SAFETY: ComponentId matches TypeId and access is checked by WorldBorrowMut
227227
unsafe {
228228
self.world
229-
.get_resource_unchecked_mut_with_id(component_id)?
229+
.as_interior_mutable()
230+
.get_resource_mut_with_id(component_id)?
230231
},
231232
archetype_component_id,
232233
self.access.clone(),
@@ -295,7 +296,8 @@ impl<'w> WorldCell<'w> {
295296
// SAFETY: ComponentId matches TypeId and access is checked by WorldBorrowMut
296297
unsafe {
297298
self.world
298-
.get_non_send_unchecked_mut_with_id(component_id)?
299+
.as_interior_mutable()
300+
.get_non_send_mut_with_id(component_id)?
299301
},
300302
archetype_component_id,
301303
self.access.clone(),

0 commit comments

Comments
 (0)