Skip to content

Commit 3a5aa56

Browse files
use InteriorMutableWorld for
ReflectComponent/ReflectResource/ReflectAsset
1 parent 50bf489 commit 3a5aa56

File tree

2 files changed

+32
-40
lines changed

2 files changed

+32
-40
lines changed

crates/bevy_asset/src/reflect.rs

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::any::{Any, TypeId};
22

3-
use bevy_ecs::world::World;
3+
use bevy_ecs::world::{interior_mutable_world::InteriorMutableWorld, World};
44
use bevy_reflect::{FromReflect, FromType, Reflect, Uuid};
55

66
use crate::{Asset, Assets, Handle, HandleId, HandleUntyped};
@@ -18,8 +18,11 @@ pub struct ReflectAsset {
1818
assets_resource_type_id: TypeId,
1919

2020
get: fn(&World, HandleUntyped) -> Option<&dyn Reflect>,
21-
get_mut: fn(&mut World, HandleUntyped) -> Option<&mut dyn Reflect>,
22-
get_unchecked_mut: unsafe fn(&World, HandleUntyped) -> Option<&mut dyn Reflect>,
21+
// SAFETY:
22+
// - may only be called with a [`IteriorMutableWorld`] which can be used to access the corresponding `Assets<T>` resource mutably
23+
// - may only be used to access **at most one** access at once
24+
get_unchecked_mut:
25+
unsafe fn(InteriorMutableWorld<'_>, HandleUntyped) -> Option<&mut dyn Reflect>,
2326
add: fn(&mut World, &dyn Reflect) -> HandleUntyped,
2427
set: fn(&mut World, HandleUntyped, &dyn Reflect) -> HandleUntyped,
2528
len: fn(&World) -> usize,
@@ -54,10 +57,11 @@ impl ReflectAsset {
5457
world: &'w mut World,
5558
handle: HandleUntyped,
5659
) -> Option<&'w mut dyn Reflect> {
57-
(self.get_mut)(world, handle)
60+
// SAFETY: unique world access
61+
unsafe { (self.get_unchecked_mut)(world.as_interior_mutable(), handle) }
5862
}
5963

60-
/// Equivalent of [`Assets::get_mut`], but does not require a mutable reference to the world.
64+
/// Equivalent of [`Assets::get_mut`], but works with a [`InteriorMutableWorld`].
6165
///
6266
/// Only use this method when you have ensured that you are the *only* one with access to the [`Assets`] resource of the asset type.
6367
/// Furthermore, this does *not* allow you to have look up two distinct handles,
@@ -81,12 +85,11 @@ impl ReflectAsset {
8185
/// # Safety
8286
/// This method does not prevent you from having two mutable pointers to the same data,
8387
/// violating Rust's aliasing rules. To avoid this:
84-
/// * Only call this method when you have exclusive access to the world
85-
/// (or use a scheduler that enforces unique access to the `Assets` resource).
88+
/// * Only call this method if you know that the [`InteriorMutableWorld`] may be used to access the corresponding `Assets<T>`
8689
/// * Don't call this method more than once in the same scope.
8790
pub unsafe fn get_unchecked_mut<'w>(
8891
&self,
89-
world: &'w World,
92+
world: InteriorMutableWorld<'w>,
9093
handle: HandleUntyped,
9194
) -> Option<&'w mut dyn Reflect> {
9295
// SAFETY: requirements are deferred to the caller
@@ -140,19 +143,8 @@ impl<A: Asset + FromReflect> FromType<A> for ReflectAsset {
140143
let asset = assets.get(&handle.typed());
141144
asset.map(|asset| asset as &dyn Reflect)
142145
},
143-
get_mut: |world, handle| {
144-
let assets = world.resource_mut::<Assets<A>>().into_inner();
145-
let asset = assets.get_mut(&handle.typed());
146-
asset.map(|asset| asset as &mut dyn Reflect)
147-
},
148146
get_unchecked_mut: |world, handle| {
149-
let assets = unsafe {
150-
world
151-
.as_interior_mutable()
152-
.get_resource_mut::<Assets<A>>()
153-
.unwrap()
154-
.into_inner()
155-
};
147+
let assets = unsafe { world.get_resource_mut::<Assets<A>>().unwrap().into_inner() };
156148
let asset = assets.get_mut(&handle.typed());
157149
asset.map(|asset| asset as &mut dyn Reflect)
158150
},

crates/bevy_ecs/src/reflect.rs

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
component::Component,
66
entity::{Entity, EntityMap, MapEntities, MapEntitiesError},
77
system::Resource,
8-
world::{FromWorld, World},
8+
world::{interior_mutable_world::InteriorMutableWorld, FromWorld, World},
99
};
1010
use bevy_reflect::{
1111
impl_from_reflect_value, impl_reflect_value, FromType, Reflect, ReflectDeserialize,
@@ -52,7 +52,8 @@ pub struct ReflectComponentFns {
5252
/// Function pointer implementing [`ReflectComponent::reflect()`].
5353
pub reflect: fn(&World, Entity) -> Option<&dyn Reflect>,
5454
/// Function pointer implementing [`ReflectComponent::reflect_mut()`].
55-
pub reflect_mut: unsafe fn(&World, Entity) -> Option<Mut<dyn Reflect>>,
55+
/// The function may only be called with a InteriorMutableWorld that can be used to access the relevant component on the given entity
56+
pub reflect_mut: unsafe fn(InteriorMutableWorld<'_>, Entity) -> Option<Mut<'_, dyn Reflect>>,
5657
/// Function pointer implementing [`ReflectComponent::copy()`].
5758
pub copy: fn(&World, &mut World, Entity, Entity),
5859
}
@@ -117,20 +118,20 @@ impl ReflectComponent {
117118
entity: Entity,
118119
) -> Option<Mut<'a, dyn Reflect>> {
119120
// SAFETY: unique world access
120-
unsafe { (self.0.reflect_mut)(world, entity) }
121+
unsafe { (self.0.reflect_mut)(world.as_interior_mutable(), entity) }
121122
}
122123

123124
/// # Safety
124125
/// This method does not prevent you from having two mutable pointers to the same data,
125126
/// violating Rust's aliasing rules. To avoid this:
126-
/// * Only call this method in an exclusive system to avoid sharing across threads (or use a
127-
/// scheduler that enforces safe memory access).
127+
/// * Only call this method with a [`InteriorMutableWorld`] that may be used to access the component on the entity `entity`
128128
/// * Don't call this method more than once in the same scope for a given [`Component`].
129129
pub unsafe fn reflect_unchecked_mut<'a>(
130130
&self,
131-
world: &'a World,
131+
world: InteriorMutableWorld<'a>,
132132
entity: Entity,
133133
) -> Option<Mut<'a, dyn Reflect>> {
134+
// SAFETY: safety requirements deferred to caller
134135
(self.0.reflect_mut)(world, entity)
135136
}
136137

@@ -212,6 +213,9 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
212213
// SAFETY: reflect_mut is an unsafe function pointer used by `reflect_unchecked_mut` which promises to never
213214
// produce aliasing mutable references, and reflect_mut, which has mutable world access
214215
unsafe {
216+
// SAFETY: entity access through the InteriorMutableWorld is not implemented yet.
217+
// The following code only accesses the component `C` through the entity `entity`
218+
let world = world.world();
215219
world
216220
.get_entity(entity)?
217221
.get_unchecked_mut::<C>(world.last_change_tick(), world.read_change_tick())
@@ -265,7 +269,7 @@ pub struct ReflectResourceFns {
265269
/// Function pointer implementing [`ReflectResource::reflect()`].
266270
pub reflect: fn(&World) -> Option<&dyn Reflect>,
267271
/// Function pointer implementing [`ReflectResource::reflect_unchecked_mut()`].
268-
pub reflect_unchecked_mut: unsafe fn(&World) -> Option<Mut<dyn Reflect>>,
272+
pub reflect_unchecked_mut: unsafe fn(InteriorMutableWorld<'_>) -> Option<Mut<'_, dyn Reflect>>,
269273
/// Function pointer implementing [`ReflectResource::copy()`].
270274
pub copy: fn(&World, &mut World),
271275
}
@@ -314,19 +318,18 @@ impl ReflectResource {
314318
/// Gets the value of this [`Resource`] type from the world as a mutable reflected reference.
315319
pub fn reflect_mut<'a>(&self, world: &'a mut World) -> Option<Mut<'a, dyn Reflect>> {
316320
// SAFETY: unique world access
317-
unsafe { (self.0.reflect_unchecked_mut)(world) }
321+
unsafe { (self.0.reflect_unchecked_mut)(world.as_interior_mutable()) }
318322
}
319323

320324
/// # Safety
321325
/// This method does not prevent you from having two mutable pointers to the same data,
322326
/// violating Rust's aliasing rules. To avoid this:
323-
/// * Only call this method in an exclusive system to avoid sharing across threads (or use a
324-
/// scheduler that enforces safe memory access).
327+
/// * Only call this method with a [`InteriorMutableWorld`] which can be used to access the resource.
325328
/// * Don't call this method more than once in the same scope for a given [`Resource`].
326-
pub unsafe fn reflect_unchecked_mut<'a>(
329+
pub unsafe fn reflect_unchecked_mut<'w>(
327330
&self,
328-
world: &'a World,
329-
) -> Option<Mut<'a, dyn Reflect>> {
331+
world: InteriorMutableWorld<'w>,
332+
) -> Option<Mut<'w, dyn Reflect>> {
330333
// SAFETY: caller promises to uphold uniqueness guarantees
331334
(self.0.reflect_unchecked_mut)(world)
332335
}
@@ -385,13 +388,10 @@ impl<C: Resource + Reflect + FromWorld> FromType<C> for ReflectResource {
385388
// SAFETY: all usages of `reflect_unchecked_mut` guarantee that there is either a single mutable
386389
// reference or multiple immutable ones alive at any given point
387390
unsafe {
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-
})
391+
world.get_resource_mut::<C>().map(|res| Mut {
392+
value: res.value as &mut dyn Reflect,
393+
ticks: res.ticks,
394+
})
395395
}
396396
},
397397
copy: |source_world, destination_world| {

0 commit comments

Comments
 (0)