Skip to main content

bevy_ecs/world/entity_access/
entity_ref.rs

1use crate::{
2    archetype::Archetype,
3    change_detection::{ComponentTicks, MaybeLocation, Tick},
4    component::{Component, ComponentId},
5    entity::{ContainsEntity, Entity, EntityEquivalent, EntityLocation},
6    query::{
7        Access, QueryAccessError, ReadOnlyQueryData, ReleaseStateQueryData, SingleEntityQueryData,
8    },
9    world::{
10        error::EntityComponentError, unsafe_world_cell::UnsafeEntityCell, DynamicComponentFetch,
11        FilteredEntityRef, Ref,
12    },
13};
14
15use core::{
16    any::TypeId,
17    cmp::Ordering,
18    hash::{Hash, Hasher},
19};
20
21/// A read-only reference to a particular [`Entity`] and all of its components.
22///
23/// # Examples
24///
25/// Read-only access disjoint with mutable access.
26///
27/// ```
28/// # use bevy_ecs::prelude::*;
29/// # #[derive(Component)] pub struct A;
30/// # #[derive(Component)] pub struct B;
31/// fn disjoint_system(
32///     query1: Query<&mut A>,
33///     query2: Query<EntityRef, Without<A>>,
34/// ) {
35///     // ...
36/// }
37/// # bevy_ecs::system::assert_is_system(disjoint_system);
38/// ```
39#[derive(Copy, Clone)]
40pub struct EntityRef<'w> {
41    cell: UnsafeEntityCell<'w>,
42}
43
44impl<'w> EntityRef<'w> {
45    /// # Safety
46    /// - `cell` must have permission to read every component of the entity.
47    /// - No mutable accesses to any of the entity's components may exist
48    ///   at the same time as the returned [`EntityRef`].
49    #[inline]
50    pub(crate) unsafe fn new(cell: UnsafeEntityCell<'w>) -> Self {
51        Self { cell }
52    }
53
54    /// Consumes `self` and returns a [`FilteredEntityRef`] which has read-only
55    /// access to all of the entity's components, with the world `'w` lifetime.
56    #[inline]
57    pub fn into_filtered(self) -> FilteredEntityRef<'w, 'static> {
58        // SAFETY:
59        // - `EntityRef` guarantees exclusive access to all components in the new `FilteredEntityRef`.
60        unsafe { FilteredEntityRef::new(self.cell, const { &Access::new_read_all() }) }
61    }
62
63    /// Returns the [ID](Entity) of the current entity.
64    #[inline]
65    #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
66    pub fn id(&self) -> Entity {
67        self.cell.id()
68    }
69
70    /// Gets metadata indicating the location where the current entity is stored.
71    #[inline]
72    pub fn location(&self) -> EntityLocation {
73        self.cell.location()
74    }
75
76    /// Returns the archetype that the current entity belongs to.
77    #[inline]
78    pub fn archetype(&self) -> &Archetype {
79        self.cell.archetype()
80    }
81
82    /// Returns `true` if the current entity has a component of type `T`.
83    /// Otherwise, this returns `false`.
84    ///
85    /// ## Notes
86    ///
87    /// If you do not know the concrete type of a component, consider using
88    /// [`Self::contains_id`] or [`Self::contains_type_id`].
89    #[inline]
90    pub fn contains<T: Component>(&self) -> bool {
91        self.contains_type_id(TypeId::of::<T>())
92    }
93
94    /// Returns `true` if the current entity has a component identified by `component_id`.
95    /// Otherwise, this returns false.
96    ///
97    /// ## Notes
98    ///
99    /// - If you know the concrete type of the component, you should prefer [`Self::contains`].
100    /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
101    ///   [`Self::contains_type_id`].
102    #[inline]
103    pub fn contains_id(&self, component_id: ComponentId) -> bool {
104        self.cell.contains_id(component_id)
105    }
106
107    /// Returns `true` if the current entity has a component with the type identified by `type_id`.
108    /// Otherwise, this returns false.
109    ///
110    /// ## Notes
111    ///
112    /// - If you know the concrete type of the component, you should prefer [`Self::contains`].
113    /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
114    #[inline]
115    pub fn contains_type_id(&self, type_id: TypeId) -> bool {
116        self.cell.contains_type_id(type_id)
117    }
118
119    /// Gets access to the component of type `T` for the current entity.
120    /// Returns `None` if the entity does not have a component of type `T`.
121    #[inline]
122    pub fn get<T: Component>(&self) -> Option<&'w T> {
123        // SAFETY: We have read-only access to all components of this entity.
124        unsafe { self.cell.get::<T>() }
125    }
126
127    /// Gets access to the component of type `T` for the current entity,
128    /// including change detection information as a [`Ref`].
129    ///
130    /// Returns `None` if the entity does not have a component of type `T`.
131    #[inline]
132    pub fn get_ref<T: Component>(&self) -> Option<Ref<'w, T>> {
133        // SAFETY: We have read-only access to all components of this entity.
134        unsafe { self.cell.get_ref::<T>() }
135    }
136
137    /// Retrieves the change ticks for the given component. This can be useful for implementing change
138    /// detection in custom runtimes.
139    #[inline]
140    pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
141        // SAFETY: We have read-only access to all components of this entity.
142        unsafe { self.cell.get_change_ticks::<T>() }
143    }
144
145    /// Get the [`MaybeLocation`] from where the given [`Component`] was last changed from.
146    /// This contains information regarding the last place (in code) that changed this component and can be useful for debugging.
147    /// For more information, see [`Location`](https://doc.rust-lang.org/nightly/core/panic/struct.Location.html), and enable the `track_location` feature.
148    pub fn get_changed_by<T: Component>(&self) -> Option<MaybeLocation> {
149        // SAFETY: We have read-only access to all components of this entity.
150        unsafe { self.cell.get_changed_by::<T>() }
151    }
152
153    /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
154    /// detection in custom runtimes.
155    ///
156    /// **You should prefer to use the typed API [`EntityRef::get_change_ticks`] where possible and only
157    /// use this in cases where the actual component types are not known at
158    /// compile time.**
159    #[inline]
160    pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
161        // SAFETY: We have read-only access to all components of this entity.
162        unsafe { self.cell.get_change_ticks_by_id(component_id) }
163    }
164
165    /// Returns untyped read-only reference(s) to component(s) for the
166    /// current entity, based on the given [`ComponentId`]s.
167    ///
168    /// **You should prefer to use the typed API [`EntityRef::get`] where
169    /// possible and only use this in cases where the actual component types
170    /// are not known at compile time.**
171    ///
172    /// Unlike [`EntityRef::get`], this returns untyped reference(s) to
173    /// component(s), and it's the job of the caller to ensure the correct
174    /// type(s) are dereferenced (if necessary).
175    ///
176    /// # Errors
177    ///
178    /// Returns [`EntityComponentError::MissingComponent`] if the entity does
179    /// not have a component.
180    ///
181    /// # Examples
182    ///
183    /// ## Single [`ComponentId`]
184    ///
185    /// ```
186    /// # use bevy_ecs::prelude::*;
187    /// #
188    /// # #[derive(Component, PartialEq, Debug)]
189    /// # pub struct Foo(i32);
190    /// # let mut world = World::new();
191    /// let entity = world.spawn(Foo(42)).id();
192    ///
193    /// // Grab the component ID for `Foo` in whatever way you like.
194    /// let component_id = world.register_component::<Foo>();
195    ///
196    /// // Then, get the component by ID.
197    /// let ptr = world.entity(entity).get_by_id(component_id);
198    /// # assert_eq!(unsafe { ptr.unwrap().deref::<Foo>() }, &Foo(42));
199    /// ```
200    ///
201    /// ## Array of [`ComponentId`]s
202    ///
203    /// ```
204    /// # use bevy_ecs::prelude::*;
205    /// #
206    /// # #[derive(Component, PartialEq, Debug)]
207    /// # pub struct X(i32);
208    /// # #[derive(Component, PartialEq, Debug)]
209    /// # pub struct Y(i32);
210    /// # let mut world = World::new();
211    /// let entity = world.spawn((X(42), Y(10))).id();
212    ///
213    /// // Grab the component IDs for `X` and `Y` in whatever way you like.
214    /// let x_id = world.register_component::<X>();
215    /// let y_id = world.register_component::<Y>();
216    ///
217    /// // Then, get the components by ID. You'll receive a same-sized array.
218    /// let Ok([x_ptr, y_ptr]) = world.entity(entity).get_by_id([x_id, y_id]) else {
219    ///     // Up to you to handle if a component is missing from the entity.
220    /// #   unreachable!();
221    /// };
222    /// # assert_eq!((unsafe { x_ptr.deref::<X>() }, unsafe { y_ptr.deref::<Y>() }), (&X(42), &Y(10)));
223    /// ```
224    ///
225    /// ## Slice of [`ComponentId`]s
226    ///
227    /// ```
228    /// # use bevy_ecs::{prelude::*, component::ComponentId};
229    /// #
230    /// # #[derive(Component, PartialEq, Debug)]
231    /// # pub struct X(i32);
232    /// # #[derive(Component, PartialEq, Debug)]
233    /// # pub struct Y(i32);
234    /// # let mut world = World::new();
235    /// let entity = world.spawn((X(42), Y(10))).id();
236    ///
237    /// // Grab the component IDs for `X` and `Y` in whatever way you like.
238    /// let x_id = world.register_component::<X>();
239    /// let y_id = world.register_component::<Y>();
240    ///
241    /// // Then, get the components by ID. You'll receive a vec of ptrs.
242    /// let ptrs = world.entity(entity).get_by_id(&[x_id, y_id] as &[ComponentId]);
243    /// # let ptrs = ptrs.unwrap();
244    /// # assert_eq!((unsafe { ptrs[0].deref::<X>() }, unsafe { ptrs[1].deref::<Y>() }), (&X(42), &Y(10)));
245    /// ```
246    ///
247    /// ## `HashSet` of [`ComponentId`]s
248    ///
249    /// ```
250    /// # use bevy_platform::collections::HashSet;
251    /// # use bevy_ecs::{prelude::*, component::ComponentId};
252    /// #
253    /// # #[derive(Component, PartialEq, Debug)]
254    /// # pub struct X(i32);
255    /// # #[derive(Component, PartialEq, Debug)]
256    /// # pub struct Y(i32);
257    /// # let mut world = World::new();
258    /// let entity = world.spawn((X(42), Y(10))).id();
259    ///
260    /// // Grab the component IDs for `X` and `Y` in whatever way you like.
261    /// let x_id = world.register_component::<X>();
262    /// let y_id = world.register_component::<Y>();
263    ///
264    /// // Then, get the components by ID. You'll receive a vec of ptrs.
265    /// let ptrs = world.entity(entity).get_by_id(&HashSet::from_iter([x_id, y_id]));
266    /// # let ptrs = ptrs.unwrap();
267    /// # assert_eq!((unsafe { ptrs[&x_id].deref::<X>() }, unsafe { ptrs[&y_id].deref::<Y>() }), (&X(42), &Y(10)));
268    /// ```
269    #[inline]
270    pub fn get_by_id<F: DynamicComponentFetch>(
271        &self,
272        component_ids: F,
273    ) -> Result<F::Ref<'w>, EntityComponentError> {
274        // SAFETY: We have read-only access to all components of this entity.
275        unsafe { component_ids.fetch_ref(self.cell) }
276    }
277
278    /// Returns read-only components for the current entity that match the query `Q`.
279    ///
280    /// # Panics
281    ///
282    /// If the entity does not have the components required by the query `Q`.
283    pub fn components<Q: ReadOnlyQueryData + ReleaseStateQueryData + SingleEntityQueryData>(
284        &self,
285    ) -> Q::Item<'w, 'static> {
286        self.get_components::<Q>()
287            .expect("Query does not match the current entity")
288    }
289
290    /// Returns read-only components for the current entity that match the query `Q`,
291    /// or `None` if the entity does not have the components required by the query `Q`.
292    pub fn get_components<Q: ReadOnlyQueryData + ReleaseStateQueryData + SingleEntityQueryData>(
293        &self,
294    ) -> Result<Q::Item<'w, 'static>, QueryAccessError> {
295        // SAFETY:
296        // - We have read-only access to all components of this entity.
297        // - The query is read-only, and read-only references cannot have conflicts.
298        unsafe { self.cell.get_components::<Q>() }
299    }
300
301    /// Returns the source code location from which this entity has been spawned.
302    pub fn spawned_by(&self) -> MaybeLocation {
303        self.cell.spawned_by()
304    }
305
306    /// Returns the [`Tick`] at which this entity has been spawned.
307    pub fn spawn_tick(&self) -> Tick {
308        self.cell.spawn_tick()
309    }
310}
311
312impl<'a> From<EntityRef<'a>> for FilteredEntityRef<'a, 'static> {
313    #[inline]
314    fn from(entity: EntityRef<'a>) -> Self {
315        entity.into_filtered()
316    }
317}
318
319impl<'a> From<&EntityRef<'a>> for FilteredEntityRef<'a, 'static> {
320    #[inline]
321    fn from(entity: &EntityRef<'a>) -> Self {
322        entity.into_filtered()
323    }
324}
325
326impl PartialEq for EntityRef<'_> {
327    fn eq(&self, other: &Self) -> bool {
328        self.entity() == other.entity()
329    }
330}
331
332impl Eq for EntityRef<'_> {}
333
334impl PartialOrd for EntityRef<'_> {
335    /// [`EntityRef`]'s comparison trait implementations match the underlying [`Entity`],
336    /// and cannot discern between different worlds.
337    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
338        Some(self.cmp(other))
339    }
340}
341
342impl Ord for EntityRef<'_> {
343    fn cmp(&self, other: &Self) -> Ordering {
344        self.entity().cmp(&other.entity())
345    }
346}
347
348impl Hash for EntityRef<'_> {
349    fn hash<H: Hasher>(&self, state: &mut H) {
350        self.entity().hash(state);
351    }
352}
353
354impl ContainsEntity for EntityRef<'_> {
355    fn entity(&self) -> Entity {
356        self.id()
357    }
358}
359
360// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
361unsafe impl EntityEquivalent for EntityRef<'_> {}