bevy_ecs/entity/
mod.rs

1//! Entity handling types.
2//!
3//! An **entity** exclusively owns zero or more [component] instances, all of different types, and can dynamically acquire or lose them over its lifetime.
4//!
5//! **empty entity**: Entity with zero components.
6//! **pending entity**: Entity reserved, but not flushed yet (see [`Entities::flush`] docs for reference).
7//! **reserved entity**: same as **pending entity**.
8//! **invalid entity**: **pending entity** flushed with invalid (see [`Entities::flush_as_invalid`] docs for reference).
9//!
10//! See [`Entity`] to learn more.
11//!
12//! [component]: crate::component::Component
13//!
14//! # Usage
15//!
16//! Operations involving entities and their components are performed either from a system by submitting commands,
17//! or from the outside (or from an exclusive system) by directly using [`World`] methods:
18//!
19//! |Operation|Command|Method|
20//! |:---:|:---:|:---:|
21//! |Spawn an entity with components|[`Commands::spawn`]|[`World::spawn`]|
22//! |Spawn an entity without components|[`Commands::spawn_empty`]|[`World::spawn_empty`]|
23//! |Despawn an entity|[`EntityCommands::despawn`]|[`World::despawn`]|
24//! |Insert a component, bundle, or tuple of components and bundles to an entity|[`EntityCommands::insert`]|[`EntityWorldMut::insert`]|
25//! |Remove a component, bundle, or tuple of components and bundles from an entity|[`EntityCommands::remove`]|[`EntityWorldMut::remove`]|
26//!
27//! [`World`]: crate::world::World
28//! [`Commands::spawn`]: crate::system::Commands::spawn
29//! [`Commands::spawn_empty`]: crate::system::Commands::spawn_empty
30//! [`EntityCommands::despawn`]: crate::system::EntityCommands::despawn
31//! [`EntityCommands::insert`]: crate::system::EntityCommands::insert
32//! [`EntityCommands::remove`]: crate::system::EntityCommands::remove
33//! [`World::spawn`]: crate::world::World::spawn
34//! [`World::spawn_empty`]: crate::world::World::spawn_empty
35//! [`World::despawn`]: crate::world::World::despawn
36//! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert
37//! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove
38
39mod clone_entities;
40mod entity_set;
41mod map_entities;
42#[cfg(feature = "bevy_reflect")]
43use bevy_reflect::Reflect;
44#[cfg(all(feature = "bevy_reflect", feature = "serialize"))]
45use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
46
47pub use clone_entities::*;
48pub use entity_set::*;
49pub use map_entities::*;
50
51mod hash;
52pub use hash::*;
53
54pub mod hash_map;
55pub mod hash_set;
56
57pub use hash_map::EntityHashMap;
58pub use hash_set::EntityHashSet;
59
60pub mod index_map;
61pub mod index_set;
62
63pub use index_map::EntityIndexMap;
64pub use index_set::EntityIndexSet;
65
66pub mod unique_array;
67pub mod unique_slice;
68pub mod unique_vec;
69
70pub use unique_array::{UniqueEntityArray, UniqueEntityEquivalentArray};
71pub use unique_slice::{UniqueEntityEquivalentSlice, UniqueEntitySlice};
72pub use unique_vec::{UniqueEntityEquivalentVec, UniqueEntityVec};
73
74use crate::{
75    archetype::{ArchetypeId, ArchetypeRow},
76    change_detection::MaybeLocation,
77    identifier::{
78        error::IdentifierError,
79        kinds::IdKind,
80        masks::{IdentifierMask, HIGH_MASK},
81        Identifier,
82    },
83    storage::{SparseSetIndex, TableId, TableRow},
84};
85use alloc::vec::Vec;
86use bevy_platform::sync::atomic::Ordering;
87use core::{fmt, hash::Hash, mem, num::NonZero, panic::Location};
88use log::warn;
89
90#[cfg(feature = "serialize")]
91use serde::{Deserialize, Serialize};
92
93#[cfg(target_has_atomic = "64")]
94use bevy_platform::sync::atomic::AtomicI64 as AtomicIdCursor;
95#[cfg(target_has_atomic = "64")]
96type IdCursor = i64;
97
98/// Most modern platforms support 64-bit atomics, but some less-common platforms
99/// do not. This fallback allows compilation using a 32-bit cursor instead, with
100/// the caveat that some conversions may fail (and panic) at runtime.
101#[cfg(not(target_has_atomic = "64"))]
102use bevy_platform::sync::atomic::AtomicIsize as AtomicIdCursor;
103#[cfg(not(target_has_atomic = "64"))]
104type IdCursor = isize;
105
106/// Lightweight identifier of an [entity](crate::entity).
107///
108/// The identifier is implemented using a [generational index]: a combination of an index and a generation.
109/// This allows fast insertion after data removal in an array while minimizing loss of spatial locality.
110///
111/// These identifiers are only valid on the [`World`] it's sourced from. Attempting to use an `Entity` to
112/// fetch entity components or metadata from a different world will either fail or return unexpected results.
113///
114/// [generational index]: https://lucassardois.medium.com/generational-indices-guide-8e3c5f7fd594
115///
116/// # Stability warning
117/// For all intents and purposes, `Entity` should be treated as an opaque identifier. The internal bit
118/// representation is liable to change from release to release as are the behaviors or performance
119/// characteristics of any of its trait implementations (i.e. `Ord`, `Hash`, etc.). This means that changes in
120/// `Entity`'s representation, though made readable through various functions on the type, are not considered
121/// breaking changes under [SemVer].
122///
123/// In particular, directly serializing with `Serialize` and `Deserialize` make zero guarantee of long
124/// term wire format compatibility. Changes in behavior will cause serialized `Entity` values persisted
125/// to long term storage (i.e. disk, databases, etc.) will fail to deserialize upon being updated.
126///
127/// # Usage
128///
129/// This data type is returned by iterating a `Query` that has `Entity` as part of its query fetch type parameter ([learn more]).
130/// It can also be obtained by calling [`EntityCommands::id`] or [`EntityWorldMut::id`].
131///
132/// ```
133/// # use bevy_ecs::prelude::*;
134/// # #[derive(Component)]
135/// # struct SomeComponent;
136/// fn setup(mut commands: Commands) {
137///     // Calling `spawn` returns `EntityCommands`.
138///     let entity = commands.spawn(SomeComponent).id();
139/// }
140///
141/// fn exclusive_system(world: &mut World) {
142///     // Calling `spawn` returns `EntityWorldMut`.
143///     let entity = world.spawn(SomeComponent).id();
144/// }
145/// #
146/// # bevy_ecs::system::assert_is_system(setup);
147/// # bevy_ecs::system::assert_is_system(exclusive_system);
148/// ```
149///
150/// It can be used to refer to a specific entity to apply [`EntityCommands`], or to call [`Query::get`] (or similar methods) to access its components.
151///
152/// ```
153/// # use bevy_ecs::prelude::*;
154/// #
155/// # #[derive(Component)]
156/// # struct Expired;
157/// #
158/// fn dispose_expired_food(mut commands: Commands, query: Query<Entity, With<Expired>>) {
159///     for food_entity in &query {
160///         commands.entity(food_entity).despawn();
161///     }
162/// }
163/// #
164/// # bevy_ecs::system::assert_is_system(dispose_expired_food);
165/// ```
166///
167/// [learn more]: crate::system::Query#entity-id-access
168/// [`EntityCommands::id`]: crate::system::EntityCommands::id
169/// [`EntityWorldMut::id`]: crate::world::EntityWorldMut::id
170/// [`EntityCommands`]: crate::system::EntityCommands
171/// [`Query::get`]: crate::system::Query::get
172/// [`World`]: crate::world::World
173/// [SemVer]: https://semver.org/
174#[derive(Clone, Copy)]
175#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
176#[cfg_attr(feature = "bevy_reflect", reflect(opaque))]
177#[cfg_attr(feature = "bevy_reflect", reflect(Hash, PartialEq, Debug, Clone))]
178#[cfg_attr(
179    all(feature = "bevy_reflect", feature = "serialize"),
180    reflect(Serialize, Deserialize)
181)]
182// Alignment repr necessary to allow LLVM to better output
183// optimized codegen for `to_bits`, `PartialEq` and `Ord`.
184#[repr(C, align(8))]
185pub struct Entity {
186    // Do not reorder the fields here. The ordering is explicitly used by repr(C)
187    // to make this struct equivalent to a u64.
188    #[cfg(target_endian = "little")]
189    index: u32,
190    generation: NonZero<u32>,
191    #[cfg(target_endian = "big")]
192    index: u32,
193}
194
195// By not short-circuiting in comparisons, we get better codegen.
196// See <https://github.com/rust-lang/rust/issues/117800>
197impl PartialEq for Entity {
198    #[inline]
199    fn eq(&self, other: &Entity) -> bool {
200        // By using `to_bits`, the codegen can be optimized out even
201        // further potentially. Relies on the correct alignment/field
202        // order of `Entity`.
203        self.to_bits() == other.to_bits()
204    }
205}
206
207impl Eq for Entity {}
208
209// The derive macro codegen output is not optimal and can't be optimized as well
210// by the compiler. This impl resolves the issue of non-optimal codegen by relying
211// on comparing against the bit representation of `Entity` instead of comparing
212// the fields. The result is then LLVM is able to optimize the codegen for Entity
213// far beyond what the derive macro can.
214// See <https://github.com/rust-lang/rust/issues/106107>
215impl PartialOrd for Entity {
216    #[inline]
217    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
218        // Make use of our `Ord` impl to ensure optimal codegen output
219        Some(self.cmp(other))
220    }
221}
222
223// The derive macro codegen output is not optimal and can't be optimized as well
224// by the compiler. This impl resolves the issue of non-optimal codegen by relying
225// on comparing against the bit representation of `Entity` instead of comparing
226// the fields. The result is then LLVM is able to optimize the codegen for Entity
227// far beyond what the derive macro can.
228// See <https://github.com/rust-lang/rust/issues/106107>
229impl Ord for Entity {
230    #[inline]
231    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
232        // This will result in better codegen for ordering comparisons, plus
233        // avoids pitfalls with regards to macro codegen relying on property
234        // position when we want to compare against the bit representation.
235        self.to_bits().cmp(&other.to_bits())
236    }
237}
238
239impl Hash for Entity {
240    #[inline]
241    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
242        self.to_bits().hash(state);
243    }
244}
245
246#[deprecated(
247    since = "0.16.0",
248    note = "This is exclusively used with the now deprecated `Entities::alloc_at_without_replacement`."
249)]
250pub(crate) enum AllocAtWithoutReplacement {
251    Exists(EntityLocation),
252    DidNotExist,
253    ExistsWithWrongGeneration,
254}
255
256impl Entity {
257    /// Construct an [`Entity`] from a raw `index` value and a non-zero `generation` value.
258    /// Ensure that the generation value is never greater than `0x7FFF_FFFF`.
259    #[inline(always)]
260    pub(crate) const fn from_raw_and_generation(index: u32, generation: NonZero<u32>) -> Entity {
261        debug_assert!(generation.get() <= HIGH_MASK);
262
263        Self { index, generation }
264    }
265
266    /// An entity ID with a placeholder value. This may or may not correspond to an actual entity,
267    /// and should be overwritten by a new value before being used.
268    ///
269    /// ## Examples
270    ///
271    /// Initializing a collection (e.g. `array` or `Vec`) with a known size:
272    ///
273    /// ```no_run
274    /// # use bevy_ecs::prelude::*;
275    /// // Create a new array of size 10 filled with invalid entity ids.
276    /// let mut entities: [Entity; 10] = [Entity::PLACEHOLDER; 10];
277    ///
278    /// // ... replace the entities with valid ones.
279    /// ```
280    ///
281    /// Deriving [`Reflect`] for a component that has an `Entity` field:
282    ///
283    /// ```no_run
284    /// # use bevy_ecs::{prelude::*, component::*};
285    /// # use bevy_reflect::Reflect;
286    /// #[derive(Reflect, Component)]
287    /// #[reflect(Component)]
288    /// pub struct MyStruct {
289    ///     pub entity: Entity,
290    /// }
291    ///
292    /// impl FromWorld for MyStruct {
293    ///     fn from_world(_world: &mut World) -> Self {
294    ///         Self {
295    ///             entity: Entity::PLACEHOLDER,
296    ///         }
297    ///     }
298    /// }
299    /// ```
300    pub const PLACEHOLDER: Self = Self::from_raw(u32::MAX);
301
302    /// Creates a new entity ID with the specified `index` and a generation of 1.
303    ///
304    /// # Note
305    ///
306    /// Spawning a specific `entity` value is __rarely the right choice__. Most apps should favor
307    /// [`Commands::spawn`](crate::system::Commands::spawn). This method should generally
308    /// only be used for sharing entities across apps, and only when they have a scheme
309    /// worked out to share an index space (which doesn't happen by default).
310    ///
311    /// In general, one should not try to synchronize the ECS by attempting to ensure that
312    /// `Entity` lines up between instances, but instead insert a secondary identifier as
313    /// a component.
314    #[inline(always)]
315    pub const fn from_raw(index: u32) -> Entity {
316        Self::from_raw_and_generation(index, NonZero::<u32>::MIN)
317    }
318
319    /// Convert to a form convenient for passing outside of rust.
320    ///
321    /// Only useful for identifying entities within the same instance of an application. Do not use
322    /// for serialization between runs.
323    ///
324    /// No particular structure is guaranteed for the returned bits.
325    #[inline(always)]
326    pub const fn to_bits(self) -> u64 {
327        IdentifierMask::pack_into_u64(self.index, self.generation.get())
328    }
329
330    /// Reconstruct an `Entity` previously destructured with [`Entity::to_bits`].
331    ///
332    /// Only useful when applied to results from `to_bits` in the same instance of an application.
333    ///
334    /// # Panics
335    ///
336    /// This method will likely panic if given `u64` values that did not come from [`Entity::to_bits`].
337    #[inline]
338    pub const fn from_bits(bits: u64) -> Self {
339        // Construct an Identifier initially to extract the kind from.
340        let id = Self::try_from_bits(bits);
341
342        match id {
343            Ok(entity) => entity,
344            Err(_) => panic!("Attempted to initialize invalid bits as an entity"),
345        }
346    }
347
348    /// Reconstruct an `Entity` previously destructured with [`Entity::to_bits`].
349    ///
350    /// Only useful when applied to results from `to_bits` in the same instance of an application.
351    ///
352    /// This method is the fallible counterpart to [`Entity::from_bits`].
353    #[inline(always)]
354    pub const fn try_from_bits(bits: u64) -> Result<Self, IdentifierError> {
355        if let Ok(id) = Identifier::try_from_bits(bits) {
356            let kind = id.kind() as u8;
357
358            if kind == (IdKind::Entity as u8) {
359                return Ok(Self {
360                    index: id.low(),
361                    generation: id.high(),
362                });
363            }
364        }
365
366        Err(IdentifierError::InvalidEntityId(bits))
367    }
368
369    /// Return a transiently unique identifier.
370    ///
371    /// No two simultaneously-live entities share the same index, but dead entities' indices may collide
372    /// with both live and dead entities. Useful for compactly representing entities within a
373    /// specific snapshot of the world, such as when serializing.
374    #[inline]
375    pub const fn index(self) -> u32 {
376        self.index
377    }
378
379    /// Returns the generation of this Entity's index. The generation is incremented each time an
380    /// entity with a given index is despawned. This serves as a "count" of the number of times a
381    /// given index has been reused (index, generation) pairs uniquely identify a given Entity.
382    #[inline]
383    pub const fn generation(self) -> u32 {
384        // Mask so not to expose any flags
385        IdentifierMask::extract_value_from_high(self.generation.get())
386    }
387}
388
389impl TryFrom<Identifier> for Entity {
390    type Error = IdentifierError;
391
392    #[inline]
393    fn try_from(value: Identifier) -> Result<Self, Self::Error> {
394        Self::try_from_bits(value.to_bits())
395    }
396}
397
398impl From<Entity> for Identifier {
399    #[inline]
400    fn from(value: Entity) -> Self {
401        Identifier::from_bits(value.to_bits())
402    }
403}
404
405#[cfg(feature = "serialize")]
406impl Serialize for Entity {
407    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
408    where
409        S: serde::Serializer,
410    {
411        serializer.serialize_u64(self.to_bits())
412    }
413}
414
415#[cfg(feature = "serialize")]
416impl<'de> Deserialize<'de> for Entity {
417    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
418    where
419        D: serde::Deserializer<'de>,
420    {
421        use serde::de::Error;
422        let id: u64 = Deserialize::deserialize(deserializer)?;
423        Entity::try_from_bits(id).map_err(D::Error::custom)
424    }
425}
426
427/// Outputs the full entity identifier, including the index, generation, and the raw bits.
428///
429/// This takes the format: `{index}v{generation}#{bits}`.
430///
431/// For [`Entity::PLACEHOLDER`], this outputs `PLACEHOLDER`.
432///
433/// # Usage
434///
435/// Prefer to use this format for debugging and logging purposes. Because the output contains
436/// the raw bits, it is easy to check it against serialized scene data.
437///
438/// Example serialized scene data:
439/// ```text
440/// (
441///   ...
442///   entities: {
443///     4294967297: (  <--- Raw Bits
444///       components: {
445///         ...
446///       ),
447///   ...
448/// )
449/// ```
450impl fmt::Debug for Entity {
451    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452        if self == &Self::PLACEHOLDER {
453            write!(f, "PLACEHOLDER")
454        } else {
455            write!(
456                f,
457                "{}v{}#{}",
458                self.index(),
459                self.generation(),
460                self.to_bits()
461            )
462        }
463    }
464}
465
466/// Outputs the short entity identifier, including the index and generation.
467///
468/// This takes the format: `{index}v{generation}`.
469///
470/// For [`Entity::PLACEHOLDER`], this outputs `PLACEHOLDER`.
471impl fmt::Display for Entity {
472    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473        if self == &Self::PLACEHOLDER {
474            write!(f, "PLACEHOLDER")
475        } else {
476            write!(f, "{}v{}", self.index(), self.generation())
477        }
478    }
479}
480
481impl SparseSetIndex for Entity {
482    #[inline]
483    fn sparse_set_index(&self) -> usize {
484        self.index() as usize
485    }
486
487    #[inline]
488    fn get_sparse_set_index(value: usize) -> Self {
489        Entity::from_raw(value as u32)
490    }
491}
492
493/// An [`Iterator`] returning a sequence of [`Entity`] values from
494pub struct ReserveEntitiesIterator<'a> {
495    // Metas, so we can recover the current generation for anything in the freelist.
496    meta: &'a [EntityMeta],
497
498    // Reserved indices formerly in the freelist to hand out.
499    freelist_indices: core::slice::Iter<'a, u32>,
500
501    // New Entity indices to hand out, outside the range of meta.len().
502    new_indices: core::ops::Range<u32>,
503}
504
505impl<'a> Iterator for ReserveEntitiesIterator<'a> {
506    type Item = Entity;
507
508    fn next(&mut self) -> Option<Self::Item> {
509        self.freelist_indices
510            .next()
511            .map(|&index| {
512                Entity::from_raw_and_generation(index, self.meta[index as usize].generation)
513            })
514            .or_else(|| self.new_indices.next().map(Entity::from_raw))
515    }
516
517    fn size_hint(&self) -> (usize, Option<usize>) {
518        let len = self.freelist_indices.len() + self.new_indices.len();
519        (len, Some(len))
520    }
521}
522
523impl<'a> ExactSizeIterator for ReserveEntitiesIterator<'a> {}
524impl<'a> core::iter::FusedIterator for ReserveEntitiesIterator<'a> {}
525
526// SAFETY: Newly reserved entity values are unique.
527unsafe impl EntitySetIterator for ReserveEntitiesIterator<'_> {}
528
529/// A [`World`]'s internal metadata store on all of its entities.
530///
531/// Contains metadata on:
532///  - The generation of every entity.
533///  - The alive/dead status of a particular entity. (i.e. "has entity 3 been despawned?")
534///  - The location of the entity's components in memory (via [`EntityLocation`])
535///
536/// [`World`]: crate::world::World
537#[derive(Debug)]
538pub struct Entities {
539    meta: Vec<EntityMeta>,
540
541    /// The `pending` and `free_cursor` fields describe three sets of Entity IDs
542    /// that have been freed or are in the process of being allocated:
543    ///
544    /// - The `freelist` IDs, previously freed by `free()`. These IDs are available to any of
545    ///   [`alloc`], [`reserve_entity`] or [`reserve_entities`]. Allocation will always prefer
546    ///   these over brand new IDs.
547    ///
548    /// - The `reserved` list of IDs that were once in the freelist, but got reserved by
549    ///   [`reserve_entities`] or [`reserve_entity`]. They are now waiting for [`flush`] to make them
550    ///   fully allocated.
551    ///
552    /// - The count of new IDs that do not yet exist in `self.meta`, but which we have handed out
553    ///   and reserved. [`flush`] will allocate room for them in `self.meta`.
554    ///
555    /// The contents of `pending` look like this:
556    ///
557    /// ```txt
558    /// ----------------------------
559    /// |  freelist  |  reserved   |
560    /// ----------------------------
561    ///              ^             ^
562    ///          free_cursor   pending.len()
563    /// ```
564    ///
565    /// As IDs are allocated, `free_cursor` is atomically decremented, moving
566    /// items from the freelist into the reserved list by sliding over the boundary.
567    ///
568    /// Once the freelist runs out, `free_cursor` starts going negative.
569    /// The more negative it is, the more IDs have been reserved starting exactly at
570    /// the end of `meta.len()`.
571    ///
572    /// This formulation allows us to reserve any number of IDs first from the freelist
573    /// and then from the new IDs, using only a single atomic subtract.
574    ///
575    /// Once [`flush`] is done, `free_cursor` will equal `pending.len()`.
576    ///
577    /// [`alloc`]: Entities::alloc
578    /// [`reserve_entity`]: Entities::reserve_entity
579    /// [`reserve_entities`]: Entities::reserve_entities
580    /// [`flush`]: Entities::flush
581    pending: Vec<u32>,
582    free_cursor: AtomicIdCursor,
583}
584
585impl Entities {
586    pub(crate) const fn new() -> Self {
587        Entities {
588            meta: Vec::new(),
589            pending: Vec::new(),
590            free_cursor: AtomicIdCursor::new(0),
591        }
592    }
593
594    /// Reserve entity IDs concurrently.
595    ///
596    /// Storage for entity generation and location is lazily allocated by calling [`flush`](Entities::flush).
597    #[expect(
598        clippy::allow_attributes,
599        reason = "`clippy::unnecessary_fallible_conversions` may not always lint."
600    )]
601    #[allow(
602        clippy::unnecessary_fallible_conversions,
603        reason = "`IdCursor::try_from` may fail on 32-bit platforms."
604    )]
605    pub fn reserve_entities(&self, count: u32) -> ReserveEntitiesIterator {
606        // Use one atomic subtract to grab a range of new IDs. The range might be
607        // entirely nonnegative, meaning all IDs come from the freelist, or entirely
608        // negative, meaning they are all new IDs to allocate, or a mix of both.
609        let range_end = self.free_cursor.fetch_sub(
610            IdCursor::try_from(count)
611                .expect("64-bit atomic operations are not supported on this platform."),
612            Ordering::Relaxed,
613        );
614        let range_start = range_end
615            - IdCursor::try_from(count)
616                .expect("64-bit atomic operations are not supported on this platform.");
617
618        let freelist_range = range_start.max(0) as usize..range_end.max(0) as usize;
619
620        let (new_id_start, new_id_end) = if range_start >= 0 {
621            // We satisfied all requests from the freelist.
622            (0, 0)
623        } else {
624            // We need to allocate some new Entity IDs outside of the range of self.meta.
625            //
626            // `range_start` covers some negative territory, e.g. `-3..6`.
627            // Since the nonnegative values `0..6` are handled by the freelist, that
628            // means we need to handle the negative range here.
629            //
630            // In this example, we truncate the end to 0, leaving us with `-3..0`.
631            // Then we negate these values to indicate how far beyond the end of `meta.end()`
632            // to go, yielding `meta.len()+0 .. meta.len()+3`.
633            let base = self.meta.len() as IdCursor;
634
635            let new_id_end = u32::try_from(base - range_start).expect("too many entities");
636
637            // `new_id_end` is in range, so no need to check `start`.
638            let new_id_start = (base - range_end.min(0)) as u32;
639
640            (new_id_start, new_id_end)
641        };
642
643        ReserveEntitiesIterator {
644            meta: &self.meta[..],
645            freelist_indices: self.pending[freelist_range].iter(),
646            new_indices: new_id_start..new_id_end,
647        }
648    }
649
650    /// Reserve one entity ID concurrently.
651    ///
652    /// Equivalent to `self.reserve_entities(1).next().unwrap()`, but more efficient.
653    pub fn reserve_entity(&self) -> Entity {
654        let n = self.free_cursor.fetch_sub(1, Ordering::Relaxed);
655        if n > 0 {
656            // Allocate from the freelist.
657            let index = self.pending[(n - 1) as usize];
658            Entity::from_raw_and_generation(index, self.meta[index as usize].generation)
659        } else {
660            // Grab a new ID, outside the range of `meta.len()`. `flush()` must
661            // eventually be called to make it valid.
662            //
663            // As `self.free_cursor` goes more and more negative, we return IDs farther
664            // and farther beyond `meta.len()`.
665            Entity::from_raw(
666                u32::try_from(self.meta.len() as IdCursor - n).expect("too many entities"),
667            )
668        }
669    }
670
671    /// Check that we do not have pending work requiring `flush()` to be called.
672    fn verify_flushed(&mut self) {
673        debug_assert!(
674            !self.needs_flush(),
675            "flush() needs to be called before this operation is legal"
676        );
677    }
678
679    /// Allocate an entity ID directly.
680    pub fn alloc(&mut self) -> Entity {
681        self.verify_flushed();
682        if let Some(index) = self.pending.pop() {
683            let new_free_cursor = self.pending.len() as IdCursor;
684            *self.free_cursor.get_mut() = new_free_cursor;
685            Entity::from_raw_and_generation(index, self.meta[index as usize].generation)
686        } else {
687            let index = u32::try_from(self.meta.len()).expect("too many entities");
688            self.meta.push(EntityMeta::EMPTY);
689            Entity::from_raw(index)
690        }
691    }
692
693    /// Allocate a specific entity ID, overwriting its generation.
694    ///
695    /// Returns the location of the entity currently using the given ID, if any. Location should be
696    /// written immediately.
697    #[deprecated(
698        since = "0.16.0",
699        note = "This can cause extreme performance problems when used after freeing a large number of entities and requesting an arbitrary entity. See #18054 on GitHub."
700    )]
701    pub fn alloc_at(&mut self, entity: Entity) -> Option<EntityLocation> {
702        self.verify_flushed();
703
704        let loc = if entity.index() as usize >= self.meta.len() {
705            self.pending
706                .extend((self.meta.len() as u32)..entity.index());
707            let new_free_cursor = self.pending.len() as IdCursor;
708            *self.free_cursor.get_mut() = new_free_cursor;
709            self.meta
710                .resize(entity.index() as usize + 1, EntityMeta::EMPTY);
711            None
712        } else if let Some(index) = self.pending.iter().position(|item| *item == entity.index()) {
713            self.pending.swap_remove(index);
714            let new_free_cursor = self.pending.len() as IdCursor;
715            *self.free_cursor.get_mut() = new_free_cursor;
716            None
717        } else {
718            Some(mem::replace(
719                &mut self.meta[entity.index() as usize].location,
720                EntityMeta::EMPTY.location,
721            ))
722        };
723
724        self.meta[entity.index() as usize].generation = entity.generation;
725
726        loc
727    }
728
729    /// Allocate a specific entity ID, overwriting its generation.
730    ///
731    /// Returns the location of the entity currently using the given ID, if any.
732    #[deprecated(
733        since = "0.16.0",
734        note = "This can cause extreme performance problems when used after freeing a large number of entities and requesting an arbitrary entity. See #18054 on GitHub."
735    )]
736    #[expect(
737        deprecated,
738        reason = "We need to support `AllocAtWithoutReplacement` for now."
739    )]
740    pub(crate) fn alloc_at_without_replacement(
741        &mut self,
742        entity: Entity,
743    ) -> AllocAtWithoutReplacement {
744        self.verify_flushed();
745
746        let result = if entity.index() as usize >= self.meta.len() {
747            self.pending
748                .extend((self.meta.len() as u32)..entity.index());
749            let new_free_cursor = self.pending.len() as IdCursor;
750            *self.free_cursor.get_mut() = new_free_cursor;
751            self.meta
752                .resize(entity.index() as usize + 1, EntityMeta::EMPTY);
753            AllocAtWithoutReplacement::DidNotExist
754        } else if let Some(index) = self.pending.iter().position(|item| *item == entity.index()) {
755            self.pending.swap_remove(index);
756            let new_free_cursor = self.pending.len() as IdCursor;
757            *self.free_cursor.get_mut() = new_free_cursor;
758            AllocAtWithoutReplacement::DidNotExist
759        } else {
760            let current_meta = &self.meta[entity.index() as usize];
761            if current_meta.location.archetype_id == ArchetypeId::INVALID {
762                AllocAtWithoutReplacement::DidNotExist
763            } else if current_meta.generation == entity.generation {
764                AllocAtWithoutReplacement::Exists(current_meta.location)
765            } else {
766                return AllocAtWithoutReplacement::ExistsWithWrongGeneration;
767            }
768        };
769
770        self.meta[entity.index() as usize].generation = entity.generation;
771        result
772    }
773
774    /// Destroy an entity, allowing it to be reused.
775    ///
776    /// Must not be called while reserved entities are awaiting `flush()`.
777    pub fn free(&mut self, entity: Entity) -> Option<EntityLocation> {
778        self.verify_flushed();
779
780        let meta = &mut self.meta[entity.index() as usize];
781        if meta.generation != entity.generation {
782            return None;
783        }
784
785        meta.generation = IdentifierMask::inc_masked_high_by(meta.generation, 1);
786
787        if meta.generation == NonZero::<u32>::MIN {
788            warn!(
789                "Entity({}) generation wrapped on Entities::free, aliasing may occur",
790                entity.index
791            );
792        }
793
794        let loc = mem::replace(&mut meta.location, EntityMeta::EMPTY.location);
795
796        self.pending.push(entity.index());
797
798        let new_free_cursor = self.pending.len() as IdCursor;
799        *self.free_cursor.get_mut() = new_free_cursor;
800        Some(loc)
801    }
802
803    /// Ensure at least `n` allocations can succeed without reallocating.
804    #[expect(
805        clippy::allow_attributes,
806        reason = "`clippy::unnecessary_fallible_conversions` may not always lint."
807    )]
808    #[allow(
809        clippy::unnecessary_fallible_conversions,
810        reason = "`IdCursor::try_from` may fail on 32-bit platforms."
811    )]
812    pub fn reserve(&mut self, additional: u32) {
813        self.verify_flushed();
814
815        let freelist_size = *self.free_cursor.get_mut();
816        let shortfall = IdCursor::try_from(additional)
817            .expect("64-bit atomic operations are not supported on this platform.")
818            - freelist_size;
819        if shortfall > 0 {
820            self.meta.reserve(shortfall as usize);
821        }
822    }
823
824    /// Returns true if the [`Entities`] contains [`entity`](Entity).
825    // This will return false for entities which have been freed, even if
826    // not reallocated since the generation is incremented in `free`
827    pub fn contains(&self, entity: Entity) -> bool {
828        self.resolve_from_id(entity.index())
829            .is_some_and(|e| e.generation() == entity.generation())
830    }
831
832    /// Clears all [`Entity`] from the World.
833    pub fn clear(&mut self) {
834        self.meta.clear();
835        self.pending.clear();
836        *self.free_cursor.get_mut() = 0;
837    }
838
839    /// Returns the location of an [`Entity`].
840    /// Note: for pending entities, returns `None`.
841    #[inline]
842    pub fn get(&self, entity: Entity) -> Option<EntityLocation> {
843        if let Some(meta) = self.meta.get(entity.index() as usize) {
844            if meta.generation != entity.generation
845                || meta.location.archetype_id == ArchetypeId::INVALID
846            {
847                return None;
848            }
849            Some(meta.location)
850        } else {
851            None
852        }
853    }
854
855    /// Updates the location of an [`Entity`]. This must be called when moving the components of
856    /// the entity around in storage.
857    ///
858    /// # Safety
859    ///  - `index` must be a valid entity index.
860    ///  - `location` must be valid for the entity at `index` or immediately made valid afterwards
861    ///    before handing control to unknown code.
862    #[inline]
863    pub(crate) unsafe fn set(&mut self, index: u32, location: EntityLocation) {
864        // SAFETY: Caller guarantees that `index` a valid entity index
865        let meta = unsafe { self.meta.get_unchecked_mut(index as usize) };
866        meta.location = location;
867    }
868
869    /// Increments the `generation` of a freed [`Entity`]. The next entity ID allocated with this
870    /// `index` will count `generation` starting from the prior `generation` + the specified
871    /// value + 1.
872    ///
873    /// Does nothing if no entity with this `index` has been allocated yet.
874    pub(crate) fn reserve_generations(&mut self, index: u32, generations: u32) -> bool {
875        if (index as usize) >= self.meta.len() {
876            return false;
877        }
878
879        let meta = &mut self.meta[index as usize];
880        if meta.location.archetype_id == ArchetypeId::INVALID {
881            meta.generation = IdentifierMask::inc_masked_high_by(meta.generation, generations);
882            true
883        } else {
884            false
885        }
886    }
887
888    /// Get the [`Entity`] with a given id, if it exists in this [`Entities`] collection
889    /// Returns `None` if this [`Entity`] is outside of the range of currently reserved Entities
890    ///
891    /// Note: This method may return [`Entities`](Entity) which are currently free
892    /// Note that [`contains`](Entities::contains) will correctly return false for freed
893    /// entities, since it checks the generation
894    pub fn resolve_from_id(&self, index: u32) -> Option<Entity> {
895        let idu = index as usize;
896        if let Some(&EntityMeta { generation, .. }) = self.meta.get(idu) {
897            Some(Entity::from_raw_and_generation(index, generation))
898        } else {
899            // `id` is outside of the meta list - check whether it is reserved but not yet flushed.
900            let free_cursor = self.free_cursor.load(Ordering::Relaxed);
901            // If this entity was manually created, then free_cursor might be positive
902            // Returning None handles that case correctly
903            let num_pending = usize::try_from(-free_cursor).ok()?;
904            (idu < self.meta.len() + num_pending).then_some(Entity::from_raw(index))
905        }
906    }
907
908    fn needs_flush(&mut self) -> bool {
909        *self.free_cursor.get_mut() != self.pending.len() as IdCursor
910    }
911
912    /// Allocates space for entities previously reserved with [`reserve_entity`](Entities::reserve_entity) or
913    /// [`reserve_entities`](Entities::reserve_entities), then initializes each one using the supplied function.
914    ///
915    /// # Safety
916    /// Flush _must_ set the entity location to the correct [`ArchetypeId`] for the given [`Entity`]
917    /// each time init is called. This _can_ be [`ArchetypeId::INVALID`], provided the [`Entity`]
918    /// has not been assigned to an [`Archetype`][crate::archetype::Archetype].
919    ///
920    /// Note: freshly-allocated entities (ones which don't come from the pending list) are guaranteed
921    /// to be initialized with the invalid archetype.
922    pub unsafe fn flush(&mut self, mut init: impl FnMut(Entity, &mut EntityLocation)) {
923        let free_cursor = self.free_cursor.get_mut();
924        let current_free_cursor = *free_cursor;
925
926        let new_free_cursor = if current_free_cursor >= 0 {
927            current_free_cursor as usize
928        } else {
929            let old_meta_len = self.meta.len();
930            let new_meta_len = old_meta_len + -current_free_cursor as usize;
931            self.meta.resize(new_meta_len, EntityMeta::EMPTY);
932            for (index, meta) in self.meta.iter_mut().enumerate().skip(old_meta_len) {
933                init(
934                    Entity::from_raw_and_generation(index as u32, meta.generation),
935                    &mut meta.location,
936                );
937            }
938
939            *free_cursor = 0;
940            0
941        };
942
943        for index in self.pending.drain(new_free_cursor..) {
944            let meta = &mut self.meta[index as usize];
945            init(
946                Entity::from_raw_and_generation(index, meta.generation),
947                &mut meta.location,
948            );
949        }
950    }
951
952    /// Flushes all reserved entities to an "invalid" state. Attempting to retrieve them will return `None`
953    /// unless they are later populated with a valid archetype.
954    pub fn flush_as_invalid(&mut self) {
955        // SAFETY: as per `flush` safety docs, the archetype id can be set to [`ArchetypeId::INVALID`] if
956        // the [`Entity`] has not been assigned to an [`Archetype`][crate::archetype::Archetype], which is the case here
957        unsafe {
958            self.flush(|_entity, location| {
959                location.archetype_id = ArchetypeId::INVALID;
960            });
961        }
962    }
963
964    /// The count of all entities in the [`World`] that have ever been allocated
965    /// including the entities that are currently freed.
966    ///
967    /// This does not include entities that have been reserved but have never been
968    /// allocated yet.
969    ///
970    /// [`World`]: crate::world::World
971    #[inline]
972    pub fn total_count(&self) -> usize {
973        self.meta.len()
974    }
975
976    /// The count of all entities in the [`World`] that are used,
977    /// including both those allocated and those reserved, but not those freed.
978    ///
979    /// [`World`]: crate::world::World
980    #[inline]
981    pub fn used_count(&self) -> usize {
982        (self.meta.len() as isize - self.free_cursor.load(Ordering::Relaxed) as isize) as usize
983    }
984
985    /// The count of all entities in the [`World`] that have ever been allocated or reserved, including those that are freed.
986    /// This is the value that [`Self::total_count()`] would return if [`Self::flush()`] were called right now.
987    ///
988    /// [`World`]: crate::world::World
989    #[inline]
990    pub fn total_prospective_count(&self) -> usize {
991        self.meta.len() + (-self.free_cursor.load(Ordering::Relaxed)).min(0) as usize
992    }
993
994    /// The count of currently allocated entities.
995    #[inline]
996    pub fn len(&self) -> u32 {
997        // `pending`, by definition, can't be bigger than `meta`.
998        (self.meta.len() - self.pending.len()) as u32
999    }
1000
1001    /// Checks if any entity is currently active.
1002    #[inline]
1003    pub fn is_empty(&self) -> bool {
1004        self.len() == 0
1005    }
1006
1007    /// Sets the source code location from which this entity has last been spawned
1008    /// or despawned.
1009    #[inline]
1010    pub(crate) fn set_spawned_or_despawned_by(&mut self, index: u32, caller: MaybeLocation) {
1011        caller.map(|caller| {
1012            let meta = self
1013                .meta
1014                .get_mut(index as usize)
1015                .expect("Entity index invalid");
1016            meta.spawned_or_despawned_by = MaybeLocation::new(Some(caller));
1017        });
1018    }
1019
1020    /// Returns the source code location from which this entity has last been spawned
1021    /// or despawned. Returns `None` if its index has been reused by another entity
1022    /// or if this entity has never existed.
1023    pub fn entity_get_spawned_or_despawned_by(
1024        &self,
1025        entity: Entity,
1026    ) -> MaybeLocation<Option<&'static Location<'static>>> {
1027        MaybeLocation::new_with_flattened(|| {
1028            self.meta
1029                .get(entity.index() as usize)
1030                .filter(|meta|
1031                // Generation is incremented immediately upon despawn
1032                (meta.generation == entity.generation)
1033                || (meta.location.archetype_id == ArchetypeId::INVALID)
1034                && (meta.generation == IdentifierMask::inc_masked_high_by(entity.generation, 1)))
1035                .map(|meta| meta.spawned_or_despawned_by)
1036        })
1037        .map(Option::flatten)
1038    }
1039
1040    /// Constructs a message explaining why an entity does not exist, if known.
1041    pub(crate) fn entity_does_not_exist_error_details(
1042        &self,
1043        entity: Entity,
1044    ) -> EntityDoesNotExistDetails {
1045        EntityDoesNotExistDetails {
1046            location: self.entity_get_spawned_or_despawned_by(entity),
1047        }
1048    }
1049}
1050
1051/// An error that occurs when a specified [`Entity`] does not exist.
1052#[derive(thiserror::Error, Debug, Clone, Copy, PartialEq, Eq)]
1053#[error("The entity with ID {entity} {details}")]
1054pub struct EntityDoesNotExistError {
1055    /// The entity's ID.
1056    pub entity: Entity,
1057    /// Details on why the entity does not exist, if available.
1058    pub details: EntityDoesNotExistDetails,
1059}
1060
1061impl EntityDoesNotExistError {
1062    pub(crate) fn new(entity: Entity, entities: &Entities) -> Self {
1063        Self {
1064            entity,
1065            details: entities.entity_does_not_exist_error_details(entity),
1066        }
1067    }
1068}
1069
1070/// Helper struct that, when printed, will write the appropriate details
1071/// regarding an entity that did not exist.
1072#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
1073pub struct EntityDoesNotExistDetails {
1074    location: MaybeLocation<Option<&'static Location<'static>>>,
1075}
1076
1077impl fmt::Display for EntityDoesNotExistDetails {
1078    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1079        match self.location.into_option() {
1080            Some(Some(location)) => write!(f, "was despawned by {location}"),
1081            Some(None) => write!(
1082                f,
1083                "does not exist (index has been reused or was never spawned)"
1084            ),
1085            None => write!(
1086                f,
1087                "does not exist (enable `track_location` feature for more details)"
1088            ),
1089        }
1090    }
1091}
1092
1093#[derive(Copy, Clone, Debug)]
1094struct EntityMeta {
1095    /// The current generation of the [`Entity`].
1096    pub generation: NonZero<u32>,
1097    /// The current location of the [`Entity`]
1098    pub location: EntityLocation,
1099    /// Location of the last spawn or despawn of this entity
1100    spawned_or_despawned_by: MaybeLocation<Option<&'static Location<'static>>>,
1101}
1102
1103impl EntityMeta {
1104    /// meta for **pending entity**
1105    const EMPTY: EntityMeta = EntityMeta {
1106        generation: NonZero::<u32>::MIN,
1107        location: EntityLocation::INVALID,
1108        spawned_or_despawned_by: MaybeLocation::new(None),
1109    };
1110}
1111
1112/// A location of an entity in an archetype.
1113#[derive(Copy, Clone, Debug, PartialEq)]
1114pub struct EntityLocation {
1115    /// The ID of the [`Archetype`] the [`Entity`] belongs to.
1116    ///
1117    /// [`Archetype`]: crate::archetype::Archetype
1118    pub archetype_id: ArchetypeId,
1119
1120    /// The index of the [`Entity`] within its [`Archetype`].
1121    ///
1122    /// [`Archetype`]: crate::archetype::Archetype
1123    pub archetype_row: ArchetypeRow,
1124
1125    /// The ID of the [`Table`] the [`Entity`] belongs to.
1126    ///
1127    /// [`Table`]: crate::storage::Table
1128    pub table_id: TableId,
1129
1130    /// The index of the [`Entity`] within its [`Table`].
1131    ///
1132    /// [`Table`]: crate::storage::Table
1133    pub table_row: TableRow,
1134}
1135
1136impl EntityLocation {
1137    /// location for **pending entity** and **invalid entity**
1138    pub(crate) const INVALID: EntityLocation = EntityLocation {
1139        archetype_id: ArchetypeId::INVALID,
1140        archetype_row: ArchetypeRow::INVALID,
1141        table_id: TableId::INVALID,
1142        table_row: TableRow::INVALID,
1143    };
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148    use super::*;
1149    use alloc::format;
1150
1151    #[test]
1152    fn entity_niche_optimization() {
1153        assert_eq!(size_of::<Entity>(), size_of::<Option<Entity>>());
1154    }
1155
1156    #[test]
1157    fn entity_bits_roundtrip() {
1158        // Generation cannot be greater than 0x7FFF_FFFF else it will be an invalid Entity id
1159        let e =
1160            Entity::from_raw_and_generation(0xDEADBEEF, NonZero::<u32>::new(0x5AADF00D).unwrap());
1161        assert_eq!(Entity::from_bits(e.to_bits()), e);
1162    }
1163
1164    #[test]
1165    fn reserve_entity_len() {
1166        let mut e = Entities::new();
1167        e.reserve_entity();
1168        // SAFETY: entity_location is left invalid
1169        unsafe { e.flush(|_, _| {}) };
1170        assert_eq!(e.len(), 1);
1171    }
1172
1173    #[test]
1174    fn get_reserved_and_invalid() {
1175        let mut entities = Entities::new();
1176        let e = entities.reserve_entity();
1177        assert!(entities.contains(e));
1178        assert!(entities.get(e).is_none());
1179
1180        // SAFETY: entity_location is left invalid
1181        unsafe {
1182            entities.flush(|_entity, _location| {
1183                // do nothing ... leaving entity location invalid
1184            });
1185        };
1186
1187        assert!(entities.contains(e));
1188        assert!(entities.get(e).is_none());
1189    }
1190
1191    #[test]
1192    fn entity_const() {
1193        const C1: Entity = Entity::from_raw(42);
1194        assert_eq!(42, C1.index());
1195        assert_eq!(1, C1.generation());
1196
1197        const C2: Entity = Entity::from_bits(0x0000_00ff_0000_00cc);
1198        assert_eq!(0x0000_00cc, C2.index());
1199        assert_eq!(0x0000_00ff, C2.generation());
1200
1201        const C3: u32 = Entity::from_raw(33).index();
1202        assert_eq!(33, C3);
1203
1204        const C4: u32 = Entity::from_bits(0x00dd_00ff_0000_0000).generation();
1205        assert_eq!(0x00dd_00ff, C4);
1206    }
1207
1208    #[test]
1209    fn reserve_generations() {
1210        let mut entities = Entities::new();
1211        let entity = entities.alloc();
1212        entities.free(entity);
1213
1214        assert!(entities.reserve_generations(entity.index(), 1));
1215    }
1216
1217    #[test]
1218    fn reserve_generations_and_alloc() {
1219        const GENERATIONS: u32 = 10;
1220
1221        let mut entities = Entities::new();
1222        let entity = entities.alloc();
1223        entities.free(entity);
1224
1225        assert!(entities.reserve_generations(entity.index(), GENERATIONS));
1226
1227        // The very next entity allocated should be a further generation on the same index
1228        let next_entity = entities.alloc();
1229        assert_eq!(next_entity.index(), entity.index());
1230        assert!(next_entity.generation() > entity.generation() + GENERATIONS);
1231    }
1232
1233    #[test]
1234    #[expect(
1235        clippy::nonminimal_bool,
1236        reason = "This intentionally tests all possible comparison operators as separate functions; thus, we don't want to rewrite these comparisons to use different operators."
1237    )]
1238    fn entity_comparison() {
1239        assert_eq!(
1240            Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap()),
1241            Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1242        );
1243        assert_ne!(
1244            Entity::from_raw_and_generation(123, NonZero::<u32>::new(789).unwrap()),
1245            Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1246        );
1247        assert_ne!(
1248            Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap()),
1249            Entity::from_raw_and_generation(123, NonZero::<u32>::new(789).unwrap())
1250        );
1251        assert_ne!(
1252            Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap()),
1253            Entity::from_raw_and_generation(456, NonZero::<u32>::new(123).unwrap())
1254        );
1255
1256        // ordering is by generation then by index
1257
1258        assert!(
1259            Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1260                >= Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1261        );
1262        assert!(
1263            Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1264                <= Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1265        );
1266        assert!(
1267            !(Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1268                < Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap()))
1269        );
1270        assert!(
1271            !(Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap())
1272                > Entity::from_raw_and_generation(123, NonZero::<u32>::new(456).unwrap()))
1273        );
1274
1275        assert!(
1276            Entity::from_raw_and_generation(9, NonZero::<u32>::new(1).unwrap())
1277                < Entity::from_raw_and_generation(1, NonZero::<u32>::new(9).unwrap())
1278        );
1279        assert!(
1280            Entity::from_raw_and_generation(1, NonZero::<u32>::new(9).unwrap())
1281                > Entity::from_raw_and_generation(9, NonZero::<u32>::new(1).unwrap())
1282        );
1283
1284        assert!(
1285            Entity::from_raw_and_generation(1, NonZero::<u32>::new(1).unwrap())
1286                < Entity::from_raw_and_generation(2, NonZero::<u32>::new(1).unwrap())
1287        );
1288        assert!(
1289            Entity::from_raw_and_generation(1, NonZero::<u32>::new(1).unwrap())
1290                <= Entity::from_raw_and_generation(2, NonZero::<u32>::new(1).unwrap())
1291        );
1292        assert!(
1293            Entity::from_raw_and_generation(2, NonZero::<u32>::new(2).unwrap())
1294                > Entity::from_raw_and_generation(1, NonZero::<u32>::new(2).unwrap())
1295        );
1296        assert!(
1297            Entity::from_raw_and_generation(2, NonZero::<u32>::new(2).unwrap())
1298                >= Entity::from_raw_and_generation(1, NonZero::<u32>::new(2).unwrap())
1299        );
1300    }
1301
1302    // Feel free to change this test if needed, but it seemed like an important
1303    // part of the best-case performance changes in PR#9903.
1304    #[test]
1305    fn entity_hash_keeps_similar_ids_together() {
1306        use core::hash::BuildHasher;
1307        let hash = EntityHash;
1308
1309        let first_id = 0xC0FFEE << 8;
1310        let first_hash = hash.hash_one(Entity::from_raw(first_id));
1311
1312        for i in 1..=255 {
1313            let id = first_id + i;
1314            let hash = hash.hash_one(Entity::from_raw(id));
1315            assert_eq!(hash.wrapping_sub(first_hash) as u32, i);
1316        }
1317    }
1318
1319    #[test]
1320    fn entity_hash_id_bitflip_affects_high_7_bits() {
1321        use core::hash::BuildHasher;
1322
1323        let hash = EntityHash;
1324
1325        let first_id = 0xC0FFEE;
1326        let first_hash = hash.hash_one(Entity::from_raw(first_id)) >> 57;
1327
1328        for bit in 0..u32::BITS {
1329            let id = first_id ^ (1 << bit);
1330            let hash = hash.hash_one(Entity::from_raw(id)) >> 57;
1331            assert_ne!(hash, first_hash);
1332        }
1333    }
1334
1335    #[test]
1336    fn entity_debug() {
1337        let entity = Entity::from_raw(42);
1338        let string = format!("{:?}", entity);
1339        assert_eq!(string, "42v1#4294967338");
1340
1341        let entity = Entity::PLACEHOLDER;
1342        let string = format!("{:?}", entity);
1343        assert_eq!(string, "PLACEHOLDER");
1344    }
1345
1346    #[test]
1347    fn entity_display() {
1348        let entity = Entity::from_raw(42);
1349        let string = format!("{}", entity);
1350        assert_eq!(string, "42v1");
1351
1352        let entity = Entity::PLACEHOLDER;
1353        let string = format!("{}", entity);
1354        assert_eq!(string, "PLACEHOLDER");
1355    }
1356}