Skip to content

Commit 019432a

Browse files
nicopapjames7132
andauthored
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>
1 parent 001b3eb commit 019432a

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

crates/bevy_ecs/src/world/entity_ref.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use bevy_ptr::{OwningPtr, Ptr};
1212
use bevy_utils::tracing::debug;
1313
use std::any::TypeId;
1414

15-
use super::unsafe_world_cell::UnsafeEntityCell;
15+
use super::{unsafe_world_cell::UnsafeEntityCell, Ref};
1616

1717
/// A read-only reference to a particular [`Entity`] and all of its components
1818
#[derive(Copy, Clone)]
@@ -121,6 +121,16 @@ impl<'w> EntityRef<'w> {
121121
unsafe { self.as_unsafe_world_cell_readonly().get::<T>() }
122122
}
123123

124+
/// Gets access to the component of type `T` for the current entity,
125+
/// including change detection information as a [`Ref`].
126+
///
127+
/// Returns `None` if the entity does not have a component of type `T`.
128+
#[inline]
129+
pub fn get_ref<T: Component>(&self) -> Option<Ref<'w, T>> {
130+
// SAFETY: &self implies shared access for duration of returned value
131+
unsafe { self.as_unsafe_world_cell_readonly().get_ref::<T>() }
132+
}
133+
124134
/// Retrieves the change ticks for the given component. This can be useful for implementing change
125135
/// detection in custom runtimes.
126136
#[inline]

crates/bevy_ecs/src/world/unsafe_world_cell.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
33
#![warn(unsafe_op_in_unsafe_fn)]
44

5-
use super::{Mut, World, WorldId};
5+
use super::{Mut, Ref, World, WorldId};
66
use crate::{
77
archetype::{Archetype, ArchetypeComponentId, Archetypes},
88
bundle::Bundles,
9-
change_detection::{MutUntyped, TicksMut},
9+
change_detection::{MutUntyped, Ticks, TicksMut},
1010
component::{
1111
ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, Tick, TickCells,
1212
},
@@ -652,10 +652,10 @@ impl<'w> UnsafeEntityCell<'w> {
652652
#[inline]
653653
pub unsafe fn get<T: Component>(self) -> Option<&'w T> {
654654
let component_id = self.world.components().get_id(TypeId::of::<T>())?;
655-
656655
// SAFETY:
657-
// - entity location is valid
658-
// - proper world access is promised by caller
656+
// - `storage_type` is correct (T component_id + T::STORAGE_TYPE)
657+
// - `location` is valid
658+
// - proper aliasing is promised by caller
659659
unsafe {
660660
get_component(
661661
self.world,
@@ -669,6 +669,36 @@ impl<'w> UnsafeEntityCell<'w> {
669669
}
670670
}
671671

672+
/// # Safety
673+
/// It is the callers responsibility to ensure that
674+
/// - the [`UnsafeEntityCell`] has permission to access the component
675+
/// - no other mutable references to the component exist at the same time
676+
#[inline]
677+
pub unsafe fn get_ref<T: Component>(self) -> Option<Ref<'w, T>> {
678+
let last_change_tick = self.world.last_change_tick();
679+
let change_tick = self.world.change_tick();
680+
let component_id = self.world.components().get_id(TypeId::of::<T>())?;
681+
682+
// SAFETY:
683+
// - `storage_type` is correct (T component_id + T::STORAGE_TYPE)
684+
// - `location` is valid
685+
// - proper aliasing is promised by caller
686+
unsafe {
687+
get_component_and_ticks(
688+
self.world,
689+
component_id,
690+
T::Storage::STORAGE_TYPE,
691+
self.entity,
692+
self.location,
693+
)
694+
.map(|(value, cells)| Ref {
695+
// SAFETY: returned component is of type T
696+
value: value.deref::<T>(),
697+
ticks: Ticks::from_tick_cells(cells, last_change_tick, change_tick),
698+
})
699+
}
700+
}
701+
672702
/// Retrieves the change ticks for the given component. This can be useful for implementing change
673703
/// detection in custom runtimes.
674704
///
@@ -761,6 +791,7 @@ impl<'w> UnsafeEntityCell<'w> {
761791
self.location,
762792
)
763793
.map(|(value, cells)| Mut {
794+
// SAFETY: returned component is of type T
764795
value: value.assert_unique().deref_mut::<T>(),
765796
ticks: TicksMut::from_tick_cells(cells, last_change_tick, change_tick),
766797
})

0 commit comments

Comments
 (0)