Skip to content

Commit 4aed2ca

Browse files
authored
Add World::try_resource_scope (bevyengine#16707)
# Objective Fixes bevyengine#16706 ## Solution - Added new method: `try_resource_scope` which returns `None` if the requested resource doesn't exist. - Changed the `resource_scope` test to use `try_resource_scope` as well to test for the `None` case. --- ## Showcase ```rust world.try_resource_scope::<MyResource, _>(|world, mut my_resource| { // do something with the resource if it exists }); ```
1 parent 0707c07 commit 4aed2ca

File tree

2 files changed

+30
-25
lines changed

2 files changed

+30
-25
lines changed

crates/bevy_ecs/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,7 @@ mod tests {
14841484
#[test]
14851485
fn resource_scope() {
14861486
let mut world = World::default();
1487+
assert!(world.try_resource_scope::<A, _>(|_, _| {}).is_none());
14871488
world.insert_resource(A(0));
14881489
world.resource_scope(|world: &mut World, mut value: Mut<A>| {
14891490
value.0 += 1;

crates/bevy_ecs/src/world/mod.rs

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2874,21 +2874,34 @@ impl World {
28742874
/// });
28752875
/// assert_eq!(world.get_resource::<A>().unwrap().0, 2);
28762876
/// ```
2877+
///
2878+
/// See also [`try_resource_scope`](Self::try_resource_scope).
28772879
#[track_caller]
28782880
pub fn resource_scope<R: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<R>) -> U) -> U {
2881+
self.try_resource_scope(f)
2882+
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()))
2883+
}
2884+
2885+
/// Temporarily removes the requested resource from this [`World`] if it exists, runs custom user code,
2886+
/// then re-adds the resource before returning. Returns `None` if the resource does not exist in this [`World`].
2887+
///
2888+
/// This enables safe simultaneous mutable access to both a resource and the rest of the [`World`].
2889+
/// For more complex access patterns, consider using [`SystemState`](crate::system::SystemState).
2890+
///
2891+
/// See also [`resource_scope`](Self::resource_scope).
2892+
pub fn try_resource_scope<R: Resource, U>(
2893+
&mut self,
2894+
f: impl FnOnce(&mut World, Mut<R>) -> U,
2895+
) -> Option<U> {
28792896
let last_change_tick = self.last_change_tick();
28802897
let change_tick = self.change_tick();
28812898

2882-
let component_id = self
2883-
.components
2884-
.get_resource_id(TypeId::of::<R>())
2885-
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()));
2899+
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
28862900
let (ptr, mut ticks, mut _caller) = self
28872901
.storages
28882902
.resources
28892903
.get_mut(component_id)
2890-
.and_then(ResourceData::remove)
2891-
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()));
2904+
.and_then(ResourceData::remove)?;
28922905
// Read the value onto the stack to avoid potential mut aliasing.
28932906
// SAFETY: `ptr` was obtained from the TypeId of `R`.
28942907
let mut value = unsafe { ptr.read::<R>() };
@@ -2912,27 +2925,18 @@ impl World {
29122925
OwningPtr::make(value, |ptr| {
29132926
// SAFETY: pointer is of type R
29142927
unsafe {
2915-
self.storages
2916-
.resources
2917-
.get_mut(component_id)
2918-
.map(|info| {
2919-
info.insert_with_ticks(
2920-
ptr,
2921-
ticks,
2922-
#[cfg(feature = "track_change_detection")]
2923-
_caller,
2924-
);
2925-
})
2926-
.unwrap_or_else(|| {
2927-
panic!(
2928-
"No resource of type {} exists in the World.",
2929-
core::any::type_name::<R>()
2930-
)
2931-
});
2928+
self.storages.resources.get_mut(component_id).map(|info| {
2929+
info.insert_with_ticks(
2930+
ptr,
2931+
ticks,
2932+
#[cfg(feature = "track_change_detection")]
2933+
_caller,
2934+
);
2935+
})
29322936
}
2933-
});
2937+
})?;
29342938

2935-
result
2939+
Some(result)
29362940
}
29372941

29382942
/// Sends an [`Event`].

0 commit comments

Comments
 (0)