From c2bbe3df551c4416cfbf9ffbafc2ae05a6c0eed9 Mon Sep 17 00:00:00 2001 From: rosefarts Date: Sat, 27 Jan 2024 14:42:35 +0100 Subject: [PATCH 1/5] add `get_resource_ref` to `UnsafeWorldCell` --- .../bevy_ecs/src/world/unsafe_world_cell.rs | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index 428a1c1157650..096a96faf32ba 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -14,7 +14,7 @@ use crate::{ prelude::Component, removal_detection::RemovedComponentEvents, storage::{Column, ComponentSparseSet, Storages}, - system::Resource, + system::{Res, Resource}, }; use bevy_ptr::Ptr; use std::{any::TypeId, cell::UnsafeCell, fmt::Debug, marker::PhantomData}; @@ -342,6 +342,30 @@ impl<'w> UnsafeWorldCell<'w> { } } + /// Gets a reference to the resource of the given type if it exists + /// + /// # Safety + /// It is the callers responsibility to ensure that + /// - the [`UnsafeWorldCell`] has permission to access the resource + /// - no mutable reference to the resource exists at the same time + #[inline] + pub unsafe fn get_resource_ref(self) -> Option> { + let component_id = self.components().get_resource_id(TypeId::of::())?; + + // SAFETY: caller ensures `self` has permission to access the resource + // caller also ensure that no mutable reference to the resource exists + let (ptr, ticks) = unsafe { self.get_resource_with_ticks(component_id)? }; + + // SAFETY: `component_id` was obtained from the type ID of `R` + let value = unsafe { ptr.deref::() }; + + // SAFETY: caller ensures that no mutable reference to the resource exists + let ticks = + unsafe { Ticks::from_tick_cells(ticks, self.last_change_tick(), self.change_tick()) }; + + Some(Res { value, ticks }) + } + /// Gets a pointer to the resource with the id [`ComponentId`] if it exists. /// The returned pointer must not be used to modify the resource, and must not be /// dereferenced after the borrow of the [`World`] ends. From 9edd2503f7566cf41b74b5863eea0d09bbc702e0 Mon Sep 17 00:00:00 2001 From: rosefarts Date: Sat, 27 Jan 2024 14:43:14 +0100 Subject: [PATCH 2/5] add `get_resource_ref` and `resource_ref` to `World` --- crates/bevy_ecs/src/world/mod.rs | 35 +++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 346e2244872e6..92dfff8499e13 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -28,7 +28,7 @@ use crate::{ removal_detection::RemovedComponentEvents, schedule::{Schedule, ScheduleLabel, Schedules}, storage::{ResourceData, Storages}, - system::Resource, + system::{Res, Resource}, world::error::TryRunScheduleError, }; use bevy_ptr::{OwningPtr, Ptr}; @@ -1302,6 +1302,30 @@ impl World { } } + /// Gets a reference to the resource of the given type + /// + /// # Panics + /// + /// Panics if the resource does not exist. + /// Use [`get_resource`](World::get_resource) instead if you want to handle this case. + /// + /// If you want to instead insert a value if the resource does not exist, + /// use [`get_resource_or_insert_with`](World::get_resource_or_insert_with). + #[inline] + #[track_caller] + pub fn resource_ref(&self) -> Res { + match self.get_resource_ref() { + Some(x) => x, + None => panic!( + "Requested resource {} does not exist in the `World`. + Did you forget to add it using `app.insert_resource` / `app.init_resource`? + Resources are also implicitly added via `app.add_event`, + and can be added by plugins.", + std::any::type_name::() + ), + } + } + /// Gets a mutable reference to the resource of the given type /// /// # Panics @@ -1335,6 +1359,15 @@ impl World { unsafe { self.as_unsafe_world_cell_readonly().get_resource() } } + /// Gets a reference to the resource of the given type if it exists + #[inline] + pub fn get_resource_ref(&self) -> Option> { + // SAFETY: + // - `as_unsafe_world_cell_readonly` gives permission to access everything immutably + // - `&self` ensures nothing in world is borrowed mutably + unsafe { self.as_unsafe_world_cell_readonly().get_resource_ref() } + } + /// Gets a mutable reference to the resource of the given type if it exists #[inline] pub fn get_resource_mut(&mut self) -> Option> { From 5f60bb4eba57f23765ff7bfeee9a2290c31bf04a Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 27 Jan 2024 14:27:07 -0500 Subject: [PATCH 3/5] Doc nits Co-authored-by: Mike --- crates/bevy_ecs/src/world/mod.rs | 2 +- crates/bevy_ecs/src/world/unsafe_world_cell.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 92dfff8499e13..ea034998bab7d 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1359,7 +1359,7 @@ impl World { unsafe { self.as_unsafe_world_cell_readonly().get_resource() } } - /// Gets a reference to the resource of the given type if it exists + /// Gets a reference including change detection to the resource of the given type if it exists. #[inline] pub fn get_resource_ref(&self) -> Option> { // SAFETY: diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index 096a96faf32ba..a851024a701e4 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -342,7 +342,7 @@ impl<'w> UnsafeWorldCell<'w> { } } - /// Gets a reference to the resource of the given type if it exists + /// Gets a reference including change detection to the resource of the given type if it exists. /// /// # Safety /// It is the callers responsibility to ensure that @@ -353,7 +353,7 @@ impl<'w> UnsafeWorldCell<'w> { let component_id = self.components().get_resource_id(TypeId::of::())?; // SAFETY: caller ensures `self` has permission to access the resource - // caller also ensure that no mutable reference to the resource exists + // caller also ensure that no mutable reference to the resource exists let (ptr, ticks) = unsafe { self.get_resource_with_ticks(component_id)? }; // SAFETY: `component_id` was obtained from the type ID of `R` From dbe82611828111f53d4e1a227b5679fc83db6f04 Mon Sep 17 00:00:00 2001 From: rosefarts Date: Sat, 27 Jan 2024 23:22:48 +0100 Subject: [PATCH 4/5] hopefully fixed docs test failure --- crates/bevy_ecs/src/world/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 92dfff8499e13..c09561f2f5553 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1908,7 +1908,7 @@ impl World { } /// Runs both [`clear_entities`](Self::clear_entities) and [`clear_resources`](Self::clear_resources), - /// invalidating all [`Entity`] and resource fetches such as [`Res`](crate::system::Res), [`ResMut`](crate::system::ResMut) + /// invalidating all [`Entity`] and resource fetches such as [`Res`], [`ResMut`](crate::system::ResMut) pub fn clear_all(&mut self) { self.clear_entities(); self.clear_resources(); From 3c51ec380db49df0196189cda2303a435ef86162 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 27 Jan 2024 20:26:26 -0500 Subject: [PATCH 5/5] Doc fix Co-authored-by: MinerSebas <66798382+MinerSebas@users.noreply.github.com> --- crates/bevy_ecs/src/world/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 9e8df69cafcb3..fb9a3f89243c3 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1307,7 +1307,7 @@ impl World { /// # Panics /// /// Panics if the resource does not exist. - /// Use [`get_resource`](World::get_resource) instead if you want to handle this case. + /// Use [`get_resource_ref`](World::get_resource_ref) instead if you want to handle this case. /// /// If you want to instead insert a value if the resource does not exist, /// use [`get_resource_or_insert_with`](World::get_resource_or_insert_with).