Skip to content

Commit 96663da

Browse files
move unchecked methods from world to InteriorMutableWorld
1 parent b914d59 commit 96663da

File tree

6 files changed

+81
-91
lines changed

6 files changed

+81
-91
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
@@ -521,7 +521,8 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for ResMutState<T> {
521521
change_tick: u32,
522522
) -> Self::Item {
523523
let value = world
524-
.get_resource_unchecked_mut_with_id(state.component_id)
524+
.as_interior_mutable()
525+
.get_resource_mut_with_id(state.component_id)
525526
.unwrap_or_else(|| {
526527
panic!(
527528
"Resource requested by {} does not exist: {}",
@@ -569,7 +570,8 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for OptionResMutState<T> {
569570
change_tick: u32,
570571
) -> Self::Item {
571572
world
572-
.get_resource_unchecked_mut_with_id(state.0.component_id)
573+
.as_interior_mutable()
574+
.get_resource_mut_with_id(state.0.component_id)
573575
.map(|value| ResMut {
574576
value: value.value,
575577
ticks: Ticks {

crates/bevy_ecs/src/world/interior_mutable_world.rs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl<'w> InteriorMutableWorld<'w> {
156156
// - component_id is of type `R`
157157
// - caller ensures aliasing rules
158158
// - `R` is Send + Sync
159-
unsafe { self.0.get_resource_unchecked_mut_with_id(component_id) }
159+
unsafe { self.get_resource_mut_with_id(component_id) }
160160
}
161161

162162
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
@@ -195,19 +195,52 @@ impl<'w> InteriorMutableWorld<'w> {
195195
ticks,
196196
})
197197
}
198+
}
198199

199-
/// Gets a reference to the non-send resource of the given type, if it exists.
200-
/// Otherwise returns [None]
200+
impl<'w> InteriorMutableWorld<'w> {
201+
/// # Safety
202+
/// - `component_id` must be assigned to a component of type `R`
203+
/// - Caller must ensure this doesn't violate Rust mutability rules for the given resource.
204+
/// - resource is either Send+Sync or the main thread is validated
205+
///
206+
/// All [`InteriorMutableWorld`] methods take `&self` and thus do not check that there is only one unique reference or multiple shared ones.
207+
/// It is the callers responsibility to make sure that there will never be a mutable reference to a value that has other references pointing to it,
208+
/// and that no arbitrary safe code can access a `&World` while some value is mutably borrowed.
201209
#[inline]
202-
pub unsafe fn get_non_send_resource<R: 'static>(&self) -> Option<&R> {
203-
self.0.get_non_send_resource::<R>()
210+
pub(crate) unsafe fn get_resource_mut_with_id<R>(
211+
&self,
212+
component_id: ComponentId,
213+
) -> Option<Mut<'w, R>> {
214+
let (ptr, ticks) = self.0.get_resource_with_ticks(component_id)?;
215+
216+
// SAFETY:
217+
// - This caller ensures that nothing aliases `ticks`.
218+
// - index is in-bounds because the column is initialized and non-empty
219+
let ticks = unsafe {
220+
Ticks::from_tick_cells(ticks, self.0.last_change_tick(), self.0.read_change_tick())
221+
};
222+
223+
Some(Mut {
224+
// SAFETY: caller ensures aliasing rules, ptr is of type `R`
225+
value: unsafe { ptr.assert_unique().deref_mut() },
226+
ticks,
227+
})
204228
}
205-
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
206-
/// Otherwise returns [None]
229+
230+
/// # Safety
231+
/// - `component_id` must be assigned to a component of type `R`.
232+
/// - Caller must ensure this doesn't violate Rust mutability rules for the given resource.
233+
///
234+
/// All [`InteriorMutableWorld`] methods take `&self` and thus do not check that there is only one unique reference or multiple shared ones.
235+
/// It is the callers responsibility to make sure that there will never be a mutable reference to a value that has other references pointing to it,
236+
/// and that no arbitrary safe code can access a `&World` while some value is mutably borrowed.
207237
#[inline]
208-
pub unsafe fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'w, R>> {
209-
let component_id = self.0.components.get_resource_id(TypeId::of::<R>())?;
210-
// SAFETY: safety requirement is deferred to the caller
211-
unsafe { self.0.get_non_send_unchecked_mut_with_id(component_id) }
238+
pub(crate) unsafe fn get_non_send_mut_with_id<R: 'static>(
239+
&self,
240+
component_id: ComponentId,
241+
) -> Option<Mut<'w, R>> {
242+
self.0.validate_non_send_access::<R>();
243+
// SAFETY: we validated nonsend access, the rest of the requirements are deferred to caller
244+
unsafe { self.get_resource_mut_with_id(component_id) }
212245
}
213246
}

crates/bevy_ecs/src/world/mod.rs

Lines changed: 14 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ impl World {
913913
#[inline]
914914
pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
915915
// SAFETY: unique world access
916-
unsafe { self.get_resource_unchecked_mut() }
916+
unsafe { self.as_interior_mutable().get_resource_mut() }
917917
}
918918

919919
// PERF: optimize this to avoid redundant lookups
@@ -930,18 +930,6 @@ impl World {
930930
self.resource_mut()
931931
}
932932

933-
/// Gets a mutable reference to the resource of the given type, if it exists
934-
/// Otherwise returns [None]
935-
///
936-
/// # Safety
937-
/// This will allow aliased mutable access to the given resource type. The caller must ensure
938-
/// that there is either only one mutable access or multiple immutable accesses at a time.
939-
#[inline]
940-
pub unsafe fn get_resource_unchecked_mut<R: Resource>(&self) -> Option<Mut<'_, R>> {
941-
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
942-
self.get_resource_unchecked_mut_with_id(component_id)
943-
}
944-
945933
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
946934
///
947935
/// # Panics
@@ -995,20 +983,16 @@ impl World {
995983
/// Otherwise returns [None]
996984
#[inline]
997985
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
998-
// SAFETY: unique world access
999-
unsafe { self.get_non_send_resource_unchecked_mut() }
1000-
}
1001-
1002-
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
1003-
/// Otherwise returns [None]
1004-
///
1005-
/// # Safety
1006-
/// This will allow aliased mutable access to the given non-send resource type. The caller must
1007-
/// ensure that there is either only one mutable access or multiple immutable accesses at a time.
1008-
#[inline]
1009-
pub unsafe fn get_non_send_resource_unchecked_mut<R: 'static>(&self) -> Option<Mut<'_, R>> {
986+
self.validate_non_send_access::<R>();
1010987
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
1011-
self.get_non_send_unchecked_mut_with_id(component_id)
988+
// SAFETY:
989+
// - `component_id` is type `R`
990+
// - we have unique access
991+
// - main thread is validated
992+
unsafe {
993+
self.as_interior_mutable()
994+
.get_resource_mut_with_id(component_id)
995+
}
1012996
}
1013997

1014998
// Shorthand helper function for getting the data and change ticks for a resource.
@@ -1278,21 +1262,6 @@ impl World {
12781262
.map(|ptr| ptr.deref())
12791263
}
12801264

1281-
/// # Safety
1282-
/// `component_id` must be assigned to a component of type `R`
1283-
/// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
1284-
#[inline]
1285-
pub(crate) unsafe fn get_resource_unchecked_mut_with_id<R>(
1286-
&self,
1287-
component_id: ComponentId,
1288-
) -> Option<Mut<'_, R>> {
1289-
let (ptr, ticks) = self.get_resource_with_ticks(component_id)?;
1290-
Some(Mut {
1291-
value: ptr.assert_unique().deref_mut(),
1292-
ticks: Ticks::from_tick_cells(ticks, self.last_change_tick(), self.read_change_tick()),
1293-
})
1294-
}
1295-
12961265
/// # Safety
12971266
/// `component_id` must be assigned to a component of type `R`
12981267
#[inline]
@@ -1304,18 +1273,6 @@ impl World {
13041273
self.get_resource_with_id(component_id)
13051274
}
13061275

1307-
/// # Safety
1308-
/// `component_id` must be assigned to a component of type `R`.
1309-
/// Caller must ensure this doesn't violate Rust mutability rules for the given resource.
1310-
#[inline]
1311-
pub(crate) unsafe fn get_non_send_unchecked_mut_with_id<R: 'static>(
1312-
&self,
1313-
component_id: ComponentId,
1314-
) -> Option<Mut<'_, R>> {
1315-
self.validate_non_send_access::<R>();
1316-
self.get_resource_unchecked_mut_with_id(component_id)
1317-
}
1318-
13191276
/// Inserts a new resource with the given `value`. Will replace the value if it already existed.
13201277
///
13211278
/// **You should prefer to use the typed API [`World::insert_resource`] where possible and only
@@ -1470,25 +1427,11 @@ impl World {
14701427
/// use this in cases where the actual types are not known at compile time.**
14711428
#[inline]
14721429
pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
1473-
let info = self.components.get_info(component_id)?;
1474-
if !info.is_send_and_sync() {
1475-
self.validate_non_send_access_untyped(info.name());
1430+
// SAFETY: unique world access
1431+
unsafe {
1432+
self.as_interior_mutable()
1433+
.get_resource_mut_by_id(component_id)
14761434
}
1477-
1478-
let change_tick = self.change_tick();
1479-
1480-
let (ptr, ticks) = self.get_resource_with_ticks(component_id)?;
1481-
1482-
// SAFETY: This function has exclusive access to the world so nothing aliases `ticks`.
1483-
// - index is in-bounds because the column is initialized and non-empty
1484-
// - no other reference to the ticks of the same row can exist at the same time
1485-
let ticks = unsafe { Ticks::from_tick_cells(ticks, self.last_change_tick(), change_tick) };
1486-
1487-
Some(MutUntyped {
1488-
// SAFETY: This function has exclusive access to the world so nothing aliases `ptr`.
1489-
value: unsafe { ptr.assert_unique() },
1490-
ticks,
1491-
})
14921435
}
14931436

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

crates/bevy_ecs/src/world/world_cell.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ impl<'w> WorldCell<'w> {
226226
.get_resource_archetype_component_id(component_id)?;
227227
WorldBorrowMut::try_new(
228228
// SAFETY: ComponentId matches TypeId and access is checked by WorldBorrowMut
229-
|| unsafe { self.world.get_resource_unchecked_mut_with_id(component_id) },
229+
|| unsafe {
230+
self.world
231+
.as_interior_mutable()
232+
.get_resource_mut_with_id(component_id)
233+
},
230234
archetype_component_id,
231235
self.access.clone(),
232236
)
@@ -292,7 +296,11 @@ impl<'w> WorldCell<'w> {
292296
.get_resource_archetype_component_id(component_id)?;
293297
WorldBorrowMut::try_new(
294298
// SAFETY: ComponentId matches TypeId and access is checked by WorldBorrowMut
295-
|| unsafe { self.world.get_non_send_unchecked_mut_with_id(component_id) },
299+
|| unsafe {
300+
self.world
301+
.as_interior_mutable()
302+
.get_non_send_mut_with_id(component_id)
303+
},
296304
archetype_component_id,
297305
self.access.clone(),
298306
)

0 commit comments

Comments
 (0)