bevy_ecs/world/entity_access/
except.rs

1use crate::{
2    bundle::Bundle,
3    change_detection::{ComponentTicks, MaybeLocation, MutUntyped, Tick},
4    component::{Component, ComponentId, Components, Mutable},
5    entity::{ContainsEntity, Entity, EntityEquivalent},
6    query::Access,
7    world::{
8        unsafe_world_cell::UnsafeEntityCell, DynamicComponentFetch, FilteredEntityMut,
9        FilteredEntityRef, Mut, Ref,
10    },
11};
12
13use bevy_ptr::Ptr;
14use core::{
15    any::TypeId,
16    cmp::Ordering,
17    hash::{Hash, Hasher},
18    marker::PhantomData,
19};
20
21/// Provides read-only access to a single entity and all its components, save
22/// for an explicitly-enumerated set.
23pub struct EntityRefExcept<'w, 's, B>
24where
25    B: Bundle,
26{
27    entity: UnsafeEntityCell<'w>,
28    access: &'s Access,
29    phantom: PhantomData<B>,
30}
31
32impl<'w, 's, B> EntityRefExcept<'w, 's, B>
33where
34    B: Bundle,
35{
36    /// # Safety
37    /// Other users of `UnsafeEntityCell` must only have mutable access to the components in `B`.
38    pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: &'s Access) -> Self {
39        Self {
40            entity,
41            access,
42            phantom: PhantomData,
43        }
44    }
45
46    /// Returns the [ID](Entity) of the current entity.
47    #[inline]
48    #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
49    pub fn id(&self) -> Entity {
50        self.entity.id()
51    }
52
53    /// Gets access to the component of type `C` for the current entity. Returns
54    /// `None` if the component doesn't have a component of that type or if the
55    /// type is one of the excluded components.
56    #[inline]
57    pub fn get<C>(&self) -> Option<&'w C>
58    where
59        C: Component,
60    {
61        let components = self.entity.world().components();
62        let id = components.valid_component_id::<C>()?;
63        if bundle_contains_component::<B>(components, id) {
64            None
65        } else {
66            // SAFETY: We have read access for all components that weren't
67            // covered by the `contains` check above.
68            unsafe { self.entity.get() }
69        }
70    }
71
72    /// Gets access to the component of type `C` for the current entity,
73    /// including change detection information. Returns `None` if the component
74    /// doesn't have a component of that type or if the type is one of the
75    /// excluded components.
76    #[inline]
77    pub fn get_ref<C>(&self) -> Option<Ref<'w, C>>
78    where
79        C: Component,
80    {
81        let components = self.entity.world().components();
82        let id = components.valid_component_id::<C>()?;
83        if bundle_contains_component::<B>(components, id) {
84            None
85        } else {
86            // SAFETY: We have read access for all components that weren't
87            // covered by the `contains` check above.
88            unsafe { self.entity.get_ref() }
89        }
90    }
91
92    /// Returns the source code location from which this entity has been spawned.
93    pub fn spawned_by(&self) -> MaybeLocation {
94        self.entity.spawned_by()
95    }
96
97    /// Returns the [`Tick`] at which this entity has been spawned.
98    pub fn spawn_tick(&self) -> Tick {
99        self.entity.spawn_tick()
100    }
101
102    /// Gets the component of the given [`ComponentId`] from the entity.
103    ///
104    /// **You should prefer to use the typed API [`Self::get`] where possible and only
105    /// use this in cases where the actual component types are not known at
106    /// compile time.**
107    ///
108    /// Unlike [`EntityRefExcept::get`], this returns a raw pointer to the component,
109    /// which is only valid while the [`EntityRefExcept`] is alive.
110    #[inline]
111    pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'w>> {
112        let components = self.entity.world().components();
113        (!bundle_contains_component::<B>(components, component_id))
114            .then(|| {
115                // SAFETY: We have read access for this component
116                unsafe { self.entity.get_by_id(component_id) }
117            })
118            .flatten()
119    }
120
121    /// Returns `true` if the current entity has a component of type `T`.
122    /// Otherwise, this returns `false`.
123    ///
124    /// ## Notes
125    ///
126    /// If you do not know the concrete type of a component, consider using
127    /// [`Self::contains_id`] or [`Self::contains_type_id`].
128    #[inline]
129    pub fn contains<T: Component>(&self) -> bool {
130        self.contains_type_id(TypeId::of::<T>())
131    }
132
133    /// Returns `true` if the current entity has a component identified by `component_id`.
134    /// Otherwise, this returns false.
135    ///
136    /// ## Notes
137    ///
138    /// - If you know the concrete type of the component, you should prefer [`Self::contains`].
139    /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
140    ///   [`Self::contains_type_id`].
141    #[inline]
142    pub fn contains_id(&self, component_id: ComponentId) -> bool {
143        self.entity.contains_id(component_id)
144    }
145
146    /// Returns `true` if the current entity has a component with the type identified by `type_id`.
147    /// Otherwise, this returns false.
148    ///
149    /// ## Notes
150    ///
151    /// - If you know the concrete type of the component, you should prefer [`Self::contains`].
152    /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
153    #[inline]
154    pub fn contains_type_id(&self, type_id: TypeId) -> bool {
155        self.entity.contains_type_id(type_id)
156    }
157
158    /// Retrieves the change ticks for the given component. This can be useful for implementing change
159    /// detection in custom runtimes.
160    #[inline]
161    pub fn get_change_ticks<T: Component>(&self) -> Option<ComponentTicks> {
162        let component_id = self
163            .entity
164            .world()
165            .components()
166            .get_valid_id(TypeId::of::<T>())?;
167        let components = self.entity.world().components();
168        (!bundle_contains_component::<B>(components, component_id))
169            .then(|| {
170                // SAFETY: We have read access
171                unsafe { self.entity.get_change_ticks::<T>() }
172            })
173            .flatten()
174    }
175
176    /// Retrieves the change ticks for the given [`ComponentId`]. This can be useful for implementing change
177    /// detection in custom runtimes.
178    ///
179    /// **You should prefer to use the typed API [`Self::get_change_ticks`] where possible and only
180    /// use this in cases where the actual component types are not known at
181    /// compile time.**
182    #[inline]
183    pub fn get_change_ticks_by_id(&self, component_id: ComponentId) -> Option<ComponentTicks> {
184        let components = self.entity.world().components();
185        (!bundle_contains_component::<B>(components, component_id))
186            .then(|| {
187                // SAFETY: We have read access
188                unsafe { self.entity.get_change_ticks_by_id(component_id) }
189            })
190            .flatten()
191    }
192}
193
194impl<'w, 's, B: Bundle> From<&'w EntityRefExcept<'_, 's, B>> for FilteredEntityRef<'w, 's> {
195    fn from(value: &'w EntityRefExcept<'_, 's, B>) -> Self {
196        // SAFETY:
197        // - The FilteredEntityRef has the same component access as the given EntityRefExcept.
198        unsafe { FilteredEntityRef::new(value.entity, value.access) }
199    }
200}
201
202impl<B: Bundle> Clone for EntityRefExcept<'_, '_, B> {
203    fn clone(&self) -> Self {
204        *self
205    }
206}
207
208impl<B: Bundle> Copy for EntityRefExcept<'_, '_, B> {}
209
210impl<B: Bundle> PartialEq for EntityRefExcept<'_, '_, B> {
211    fn eq(&self, other: &Self) -> bool {
212        self.entity() == other.entity()
213    }
214}
215
216impl<B: Bundle> Eq for EntityRefExcept<'_, '_, B> {}
217
218impl<B: Bundle> PartialOrd for EntityRefExcept<'_, '_, B> {
219    /// [`EntityRefExcept`]'s comparison trait implementations match the underlying [`Entity`],
220    /// and cannot discern between different worlds.
221    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
222        Some(self.cmp(other))
223    }
224}
225
226impl<B: Bundle> Ord for EntityRefExcept<'_, '_, B> {
227    fn cmp(&self, other: &Self) -> Ordering {
228        self.entity().cmp(&other.entity())
229    }
230}
231
232impl<B: Bundle> Hash for EntityRefExcept<'_, '_, B> {
233    fn hash<H: Hasher>(&self, state: &mut H) {
234        self.entity().hash(state);
235    }
236}
237
238impl<B: Bundle> ContainsEntity for EntityRefExcept<'_, '_, B> {
239    fn entity(&self) -> Entity {
240        self.id()
241    }
242}
243
244// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
245unsafe impl<B: Bundle> EntityEquivalent for EntityRefExcept<'_, '_, B> {}
246
247/// Provides mutable access to all components of an entity, with the exception
248/// of an explicit set.
249///
250/// This is a rather niche type that should only be used if you need access to
251/// *all* components of an entity, while still allowing you to consult other
252/// queries that might match entities that this query also matches. If you don't
253/// need access to all components, prefer a standard query with a
254/// [`Without`](`crate::query::Without`) filter.
255pub struct EntityMutExcept<'w, 's, B>
256where
257    B: Bundle,
258{
259    entity: UnsafeEntityCell<'w>,
260    access: &'s Access,
261    phantom: PhantomData<B>,
262}
263
264impl<'w, 's, B> EntityMutExcept<'w, 's, B>
265where
266    B: Bundle,
267{
268    /// # Safety
269    /// Other users of `UnsafeEntityCell` must not have access to any components not in `B`.
270    pub(crate) unsafe fn new(entity: UnsafeEntityCell<'w>, access: &'s Access) -> Self {
271        Self {
272            entity,
273            access,
274            phantom: PhantomData,
275        }
276    }
277
278    /// Returns the [ID](Entity) of the current entity.
279    #[inline]
280    #[must_use = "Omit the .id() call if you do not need to store the `Entity` identifier."]
281    pub fn id(&self) -> Entity {
282        self.entity.id()
283    }
284
285    /// Returns a new instance with a shorter lifetime.
286    ///
287    /// This is useful if you have `&mut EntityMutExcept`, but you need
288    /// `EntityMutExcept`.
289    pub fn reborrow(&mut self) -> EntityMutExcept<'_, 's, B> {
290        // SAFETY: We have exclusive access to the entire entity and the
291        // applicable components.
292        unsafe { Self::new(self.entity, self.access) }
293    }
294
295    /// Gets read-only access to all of the entity's components, except for the
296    /// ones in `CL`.
297    #[inline]
298    pub fn as_readonly(&self) -> EntityRefExcept<'_, 's, B> {
299        EntityRefExcept::from(self)
300    }
301
302    /// Get access to the underlying [`UnsafeEntityCell`]
303    pub fn as_unsafe_entity_cell(&mut self) -> UnsafeEntityCell<'_> {
304        self.entity
305    }
306
307    /// Gets access to the component of type `C` for the current entity. Returns
308    /// `None` if the component doesn't have a component of that type or if the
309    /// type is one of the excluded components.
310    #[inline]
311    pub fn get<C>(&self) -> Option<&'_ C>
312    where
313        C: Component,
314    {
315        self.as_readonly().get()
316    }
317
318    /// Gets access to the component of type `C` for the current entity,
319    /// including change detection information. Returns `None` if the component
320    /// doesn't have a component of that type or if the type is one of the
321    /// excluded components.
322    #[inline]
323    pub fn get_ref<C>(&self) -> Option<Ref<'_, C>>
324    where
325        C: Component,
326    {
327        self.as_readonly().get_ref()
328    }
329
330    /// Gets mutable access to the component of type `C` for the current entity.
331    /// Returns `None` if the component doesn't have a component of that type or
332    /// if the type is one of the excluded components.
333    #[inline]
334    pub fn get_mut<C>(&mut self) -> Option<Mut<'_, C>>
335    where
336        C: Component<Mutability = Mutable>,
337    {
338        let components = self.entity.world().components();
339        let id = components.valid_component_id::<C>()?;
340        if bundle_contains_component::<B>(components, id) {
341            None
342        } else {
343            // SAFETY: We have write access for all components that weren't
344            // covered by the `contains` check above.
345            unsafe { self.entity.get_mut() }
346        }
347    }
348
349    /// Returns the source code location from which this entity has been spawned.
350    pub fn spawned_by(&self) -> MaybeLocation {
351        self.entity.spawned_by()
352    }
353
354    /// Returns the [`Tick`] at which this entity has been spawned.
355    pub fn spawn_tick(&self) -> Tick {
356        self.entity.spawn_tick()
357    }
358
359    /// Returns `true` if the current entity has a component of type `T`.
360    /// Otherwise, this returns `false`.
361    ///
362    /// ## Notes
363    ///
364    /// If you do not know the concrete type of a component, consider using
365    /// [`Self::contains_id`] or [`Self::contains_type_id`].
366    #[inline]
367    pub fn contains<T: Component>(&self) -> bool {
368        self.contains_type_id(TypeId::of::<T>())
369    }
370
371    /// Returns `true` if the current entity has a component identified by `component_id`.
372    /// Otherwise, this returns false.
373    ///
374    /// ## Notes
375    ///
376    /// - If you know the concrete type of the component, you should prefer [`Self::contains`].
377    /// - If you know the component's [`TypeId`] but not its [`ComponentId`], consider using
378    ///   [`Self::contains_type_id`].
379    #[inline]
380    pub fn contains_id(&self, component_id: ComponentId) -> bool {
381        self.entity.contains_id(component_id)
382    }
383
384    /// Returns `true` if the current entity has a component with the type identified by `type_id`.
385    /// Otherwise, this returns false.
386    ///
387    /// ## Notes
388    ///
389    /// - If you know the concrete type of the component, you should prefer [`Self::contains`].
390    /// - If you have a [`ComponentId`] instead of a [`TypeId`], consider using [`Self::contains_id`].
391    #[inline]
392    pub fn contains_type_id(&self, type_id: TypeId) -> bool {
393        self.entity.contains_type_id(type_id)
394    }
395
396    /// Gets the component of the given [`ComponentId`] from the entity.
397    ///
398    /// **You should prefer to use the typed API [`Self::get`] where possible and only
399    /// use this in cases where the actual component types are not known at
400    /// compile time.**
401    ///
402    /// Unlike [`EntityMutExcept::get`], this returns a raw pointer to the component,
403    /// which is only valid while the [`EntityMutExcept`] is alive.
404    #[inline]
405    pub fn get_by_id(&'w self, component_id: ComponentId) -> Option<Ptr<'w>> {
406        self.as_readonly().get_by_id(component_id)
407    }
408
409    /// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity.
410    ///
411    /// **You should prefer to use the typed API [`Self::get_mut`] where possible and only
412    /// use this in cases where the actual component types are not known at
413    /// compile time.**
414    ///
415    /// Unlike [`EntityMutExcept::get_mut`], this returns a raw pointer to the component,
416    /// which is only valid while the [`EntityMutExcept`] is alive.
417    #[inline]
418    pub fn get_mut_by_id<F: DynamicComponentFetch>(
419        &mut self,
420        component_id: ComponentId,
421    ) -> Option<MutUntyped<'_>> {
422        let components = self.entity.world().components();
423        (!bundle_contains_component::<B>(components, component_id))
424            .then(|| {
425                // SAFETY: We have write access
426                unsafe { self.entity.get_mut_by_id(component_id).ok() }
427            })
428            .flatten()
429    }
430}
431
432impl<'w, 's, B: Bundle> From<&'w mut EntityMutExcept<'_, 's, B>> for FilteredEntityMut<'w, 's> {
433    fn from(value: &'w mut EntityMutExcept<'_, 's, B>) -> Self {
434        // SAFETY:
435        // - The FilteredEntityMut has the same component access as the given EntityMutExcept.
436        unsafe { FilteredEntityMut::new(value.entity, value.access) }
437    }
438}
439
440impl<'w, 's, B> From<&'w EntityMutExcept<'_, 's, B>> for EntityRefExcept<'w, 's, B>
441where
442    B: Bundle,
443{
444    fn from(entity: &'w EntityMutExcept<'_, 's, B>) -> Self {
445        // SAFETY: All accesses that `EntityRefExcept` provides are also
446        // accesses that `EntityMutExcept` provides.
447        unsafe { EntityRefExcept::new(entity.entity, entity.access) }
448    }
449}
450
451impl<B: Bundle> PartialEq for EntityMutExcept<'_, '_, B> {
452    fn eq(&self, other: &Self) -> bool {
453        self.entity() == other.entity()
454    }
455}
456
457impl<B: Bundle> Eq for EntityMutExcept<'_, '_, B> {}
458
459impl<B: Bundle> PartialOrd for EntityMutExcept<'_, '_, B> {
460    /// [`EntityMutExcept`]'s comparison trait implementations match the underlying [`Entity`],
461    /// and cannot discern between different worlds.
462    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
463        Some(self.cmp(other))
464    }
465}
466
467impl<B: Bundle> Ord for EntityMutExcept<'_, '_, B> {
468    fn cmp(&self, other: &Self) -> Ordering {
469        self.entity().cmp(&other.entity())
470    }
471}
472
473impl<B: Bundle> Hash for EntityMutExcept<'_, '_, B> {
474    fn hash<H: Hasher>(&self, state: &mut H) {
475        self.entity().hash(state);
476    }
477}
478
479impl<B: Bundle> ContainsEntity for EntityMutExcept<'_, '_, B> {
480    fn entity(&self) -> Entity {
481        self.id()
482    }
483}
484
485// SAFETY: This type represents one Entity. We implement the comparison traits based on that Entity.
486unsafe impl<B: Bundle> EntityEquivalent for EntityMutExcept<'_, '_, B> {}
487
488fn bundle_contains_component<B>(components: &Components, query_id: ComponentId) -> bool
489where
490    B: Bundle,
491{
492    let mut found = false;
493    for id in B::get_component_ids(components).flatten() {
494        found = found || id == query_id;
495    }
496    found
497}