mirror of
https://github.com/bevyengine/bevy
synced 2024-12-20 01:53:12 +00:00
Add World::try_resource_scope
(#16707)
# Objective Fixes #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 }); ```
This commit is contained in:
parent
0707c0717b
commit
4aed2ca74c
2 changed files with 30 additions and 25 deletions
|
@ -1484,6 +1484,7 @@ mod tests {
|
|||
#[test]
|
||||
fn resource_scope() {
|
||||
let mut world = World::default();
|
||||
assert!(world.try_resource_scope::<A, _>(|_, _| {}).is_none());
|
||||
world.insert_resource(A(0));
|
||||
world.resource_scope(|world: &mut World, mut value: Mut<A>| {
|
||||
value.0 += 1;
|
||||
|
|
|
@ -2874,21 +2874,34 @@ impl World {
|
|||
/// });
|
||||
/// assert_eq!(world.get_resource::<A>().unwrap().0, 2);
|
||||
/// ```
|
||||
///
|
||||
/// See also [`try_resource_scope`](Self::try_resource_scope).
|
||||
#[track_caller]
|
||||
pub fn resource_scope<R: Resource, U>(&mut self, f: impl FnOnce(&mut World, Mut<R>) -> U) -> U {
|
||||
self.try_resource_scope(f)
|
||||
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()))
|
||||
}
|
||||
|
||||
/// Temporarily removes the requested resource from this [`World`] if it exists, runs custom user code,
|
||||
/// then re-adds the resource before returning. Returns `None` if the resource does not exist in this [`World`].
|
||||
///
|
||||
/// This enables safe simultaneous mutable access to both a resource and the rest of the [`World`].
|
||||
/// For more complex access patterns, consider using [`SystemState`](crate::system::SystemState).
|
||||
///
|
||||
/// See also [`resource_scope`](Self::resource_scope).
|
||||
pub fn try_resource_scope<R: Resource, U>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut World, Mut<R>) -> U,
|
||||
) -> Option<U> {
|
||||
let last_change_tick = self.last_change_tick();
|
||||
let change_tick = self.change_tick();
|
||||
|
||||
let component_id = self
|
||||
.components
|
||||
.get_resource_id(TypeId::of::<R>())
|
||||
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()));
|
||||
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
|
||||
let (ptr, mut ticks, mut _caller) = self
|
||||
.storages
|
||||
.resources
|
||||
.get_mut(component_id)
|
||||
.and_then(ResourceData::remove)
|
||||
.unwrap_or_else(|| panic!("resource does not exist: {}", core::any::type_name::<R>()));
|
||||
.and_then(ResourceData::remove)?;
|
||||
// Read the value onto the stack to avoid potential mut aliasing.
|
||||
// SAFETY: `ptr` was obtained from the TypeId of `R`.
|
||||
let mut value = unsafe { ptr.read::<R>() };
|
||||
|
@ -2912,27 +2925,18 @@ impl World {
|
|||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: pointer is of type R
|
||||
unsafe {
|
||||
self.storages
|
||||
.resources
|
||||
.get_mut(component_id)
|
||||
.map(|info| {
|
||||
info.insert_with_ticks(
|
||||
ptr,
|
||||
ticks,
|
||||
#[cfg(feature = "track_change_detection")]
|
||||
_caller,
|
||||
);
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"No resource of type {} exists in the World.",
|
||||
core::any::type_name::<R>()
|
||||
)
|
||||
});
|
||||
self.storages.resources.get_mut(component_id).map(|info| {
|
||||
info.insert_with_ticks(
|
||||
ptr,
|
||||
ticks,
|
||||
#[cfg(feature = "track_change_detection")]
|
||||
_caller,
|
||||
);
|
||||
})
|
||||
}
|
||||
});
|
||||
})?;
|
||||
|
||||
result
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// Sends an [`Event`].
|
||||
|
|
Loading…
Reference in a new issue