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}