Add get_ref to EntityRef (#8818)
# Objective To mirror the `Ref` added as `WorldQuery`, and the `Mut` in `EntityMut::get_mut`, we add `EntityRef::get_ref`, which retrieves `T` with tick information, but *immutably*. ## Solution - Add the method in question, also add it to`UnsafeEntityCell` since this seems to be the best way of getting that information. Also update/add safety comments to neighboring code. --- ## Changelog - Add `EntityRef::get_ref` to get an `Option<Ref<T>>` from `EntityRef` --------- Co-authored-by: James Liu <contact@jamessliu.com>
This commit is contained in:
		
							parent
							
								
									001b3eb97c
								
							
						
					
					
						commit
						019432af2e
					
				| @ -12,7 +12,7 @@ use bevy_ptr::{OwningPtr, Ptr}; | |||||||
| use bevy_utils::tracing::debug; | use bevy_utils::tracing::debug; | ||||||
| use std::any::TypeId; | use std::any::TypeId; | ||||||
| 
 | 
 | ||||||
| use super::unsafe_world_cell::UnsafeEntityCell; | use super::{unsafe_world_cell::UnsafeEntityCell, Ref}; | ||||||
| 
 | 
 | ||||||
| /// A read-only reference to a particular [`Entity`] and all of its components
 | /// A read-only reference to a particular [`Entity`] and all of its components
 | ||||||
| #[derive(Copy, Clone)] | #[derive(Copy, Clone)] | ||||||
| @ -121,6 +121,16 @@ impl<'w> EntityRef<'w> { | |||||||
|         unsafe { self.as_unsafe_world_cell_readonly().get::<T>() } |         unsafe { self.as_unsafe_world_cell_readonly().get::<T>() } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Gets access to the component of type `T` for the current entity,
 | ||||||
|  |     /// including change detection information as a [`Ref`].
 | ||||||
|  |     ///
 | ||||||
|  |     /// Returns `None` if the entity does not have a component of type `T`.
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn get_ref<T: Component>(&self) -> Option<Ref<'w, T>> { | ||||||
|  |         // SAFETY: &self implies shared access for duration of returned value
 | ||||||
|  |         unsafe { self.as_unsafe_world_cell_readonly().get_ref::<T>() } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Retrieves the change ticks for the given component. This can be useful for implementing change
 |     /// Retrieves the change ticks for the given component. This can be useful for implementing change
 | ||||||
|     /// detection in custom runtimes.
 |     /// detection in custom runtimes.
 | ||||||
|     #[inline] |     #[inline] | ||||||
|  | |||||||
| @ -2,11 +2,11 @@ | |||||||
| 
 | 
 | ||||||
| #![warn(unsafe_op_in_unsafe_fn)] | #![warn(unsafe_op_in_unsafe_fn)] | ||||||
| 
 | 
 | ||||||
| use super::{Mut, World, WorldId}; | use super::{Mut, Ref, World, WorldId}; | ||||||
| use crate::{ | use crate::{ | ||||||
|     archetype::{Archetype, ArchetypeComponentId, Archetypes}, |     archetype::{Archetype, ArchetypeComponentId, Archetypes}, | ||||||
|     bundle::Bundles, |     bundle::Bundles, | ||||||
|     change_detection::{MutUntyped, TicksMut}, |     change_detection::{MutUntyped, Ticks, TicksMut}, | ||||||
|     component::{ |     component::{ | ||||||
|         ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, Tick, TickCells, |         ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, Tick, TickCells, | ||||||
|     }, |     }, | ||||||
| @ -652,10 +652,10 @@ impl<'w> UnsafeEntityCell<'w> { | |||||||
|     #[inline] |     #[inline] | ||||||
|     pub unsafe fn get<T: Component>(self) -> Option<&'w T> { |     pub unsafe fn get<T: Component>(self) -> Option<&'w T> { | ||||||
|         let component_id = self.world.components().get_id(TypeId::of::<T>())?; |         let component_id = self.world.components().get_id(TypeId::of::<T>())?; | ||||||
| 
 |  | ||||||
|         // SAFETY:
 |         // SAFETY:
 | ||||||
|         // - entity location is valid
 |         // - `storage_type` is correct (T component_id + T::STORAGE_TYPE)
 | ||||||
|         // - proper world access is promised by caller
 |         // - `location` is valid
 | ||||||
|  |         // - proper aliasing is promised by caller
 | ||||||
|         unsafe { |         unsafe { | ||||||
|             get_component( |             get_component( | ||||||
|                 self.world, |                 self.world, | ||||||
| @ -669,6 +669,36 @@ impl<'w> UnsafeEntityCell<'w> { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// # Safety
 | ||||||
|  |     /// It is the callers responsibility to ensure that
 | ||||||
|  |     /// - the [`UnsafeEntityCell`] has permission to access the component
 | ||||||
|  |     /// - no other mutable references to the component exist at the same time
 | ||||||
|  |     #[inline] | ||||||
|  |     pub unsafe fn get_ref<T: Component>(self) -> Option<Ref<'w, T>> { | ||||||
|  |         let last_change_tick = self.world.last_change_tick(); | ||||||
|  |         let change_tick = self.world.change_tick(); | ||||||
|  |         let component_id = self.world.components().get_id(TypeId::of::<T>())?; | ||||||
|  | 
 | ||||||
|  |         // SAFETY:
 | ||||||
|  |         // - `storage_type` is correct (T component_id + T::STORAGE_TYPE)
 | ||||||
|  |         // - `location` is valid
 | ||||||
|  |         // - proper aliasing is promised by caller
 | ||||||
|  |         unsafe { | ||||||
|  |             get_component_and_ticks( | ||||||
|  |                 self.world, | ||||||
|  |                 component_id, | ||||||
|  |                 T::Storage::STORAGE_TYPE, | ||||||
|  |                 self.entity, | ||||||
|  |                 self.location, | ||||||
|  |             ) | ||||||
|  |             .map(|(value, cells)| Ref { | ||||||
|  |                 // SAFETY: returned component is of type T
 | ||||||
|  |                 value: value.deref::<T>(), | ||||||
|  |                 ticks: Ticks::from_tick_cells(cells, last_change_tick, change_tick), | ||||||
|  |             }) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /// Retrieves the change ticks for the given component. This can be useful for implementing change
 |     /// Retrieves the change ticks for the given component. This can be useful for implementing change
 | ||||||
|     /// detection in custom runtimes.
 |     /// detection in custom runtimes.
 | ||||||
|     ///
 |     ///
 | ||||||
| @ -761,6 +791,7 @@ impl<'w> UnsafeEntityCell<'w> { | |||||||
|                 self.location, |                 self.location, | ||||||
|             ) |             ) | ||||||
|             .map(|(value, cells)| Mut { |             .map(|(value, cells)| Mut { | ||||||
|  |                 // SAFETY: returned component is of type T
 | ||||||
|                 value: value.assert_unique().deref_mut::<T>(), |                 value: value.assert_unique().deref_mut::<T>(), | ||||||
|                 ticks: TicksMut::from_tick_cells(cells, last_change_tick, change_tick), |                 ticks: TicksMut::from_tick_cells(cells, last_change_tick, change_tick), | ||||||
|             }) |             }) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Nicola Papale
						Nicola Papale