Skip to main content

bevy_ecs/
archetype.rs

1//! Types for defining [`Archetype`]s, collections of entities that have the same set of
2//! components.
3//!
4//! An archetype uniquely describes a group of entities that share the same components:
5//! a world only has one archetype for each unique combination of components, and all
6//! entities that have those components and only those components belong to that
7//! archetype.
8//!
9//! Archetypes are not to be confused with [`Table`]s. Each archetype stores its table
10//! components in one table, and each archetype uniquely points to one table, but multiple
11//! archetypes may store their table components in the same table. These archetypes
12//! differ only by the [`SparseSet`] components.
13//!
14//! Like tables, archetypes can be created but are never cleaned up. Empty archetypes are
15//! not removed, and persist until the world is dropped.
16//!
17//! Archetypes can be fetched from [`Archetypes`], which is accessible via [`World::archetypes`].
18//!
19//! [`Table`]: crate::storage::Table
20//! [`World::archetypes`]: crate::world::World::archetypes
21
22use crate::{
23    bundle::BundleId,
24    component::{ComponentId, Components, RequiredComponentConstructor, StorageType},
25    entity::{Entity, EntityLocation},
26    event::{Event, EventKey},
27    observer::Observers,
28    query::DebugCheckedUnwrap,
29    storage::{ImmutableSparseSet, SparseArray, SparseSet, TableId, TableRow},
30};
31use alloc::{boxed::Box, vec::Vec};
32use bevy_platform::collections::{hash_map::Entry, HashMap};
33use core::{
34    hash::Hash,
35    ops::{Index, IndexMut, RangeFrom},
36};
37use nonmax::NonMaxU32;
38
39#[derive(Event)]
40#[cfg_attr(
41    not(test),
42    expect(dead_code, reason = "Prepare for the upcoming Query as Entities")
43)]
44pub(crate) struct ArchetypeCreated(pub ArchetypeId);
45
46pub(crate) const ARCHETYPE_CREATED: EventKey = EventKey(crate::component::ARCHETYPE_CREATED);
47
48/// An opaque location within a [`Archetype`].
49///
50/// This can be used in conjunction with [`ArchetypeId`] to find the exact location
51/// of an [`Entity`] within a [`World`]. An entity's archetype and index can be
52/// retrieved via [`Entities::get`].
53///
54/// [`World`]: crate::world::World
55/// [`Entities::get`]: crate::entity::Entities
56#[derive(Debug, Copy, Clone, Eq, PartialEq)]
57// SAFETY: Must be repr(transparent) due to the safety requirements on EntityLocation
58#[repr(transparent)]
59pub struct ArchetypeRow(NonMaxU32);
60
61impl ArchetypeRow {
62    /// Creates a `ArchetypeRow`.
63    #[inline]
64    pub const fn new(index: NonMaxU32) -> Self {
65        Self(index)
66    }
67
68    /// Gets the index of the row.
69    #[inline]
70    pub const fn index(self) -> usize {
71        self.0.get() as usize
72    }
73
74    /// Gets the index of the row.
75    #[inline]
76    pub const fn index_u32(self) -> u32 {
77        self.0.get()
78    }
79}
80
81/// An opaque unique ID for a single [`Archetype`] within a [`World`].
82///
83/// Archetype IDs are only valid for a given World, and are not globally unique.
84/// Attempting to use an archetype ID on a world that it wasn't sourced from will
85/// not return the archetype with the same components. The only exception to this is
86/// [`EMPTY`] which is guaranteed to be identical for all Worlds.
87///
88/// [`World`]: crate::world::World
89/// [`EMPTY`]: ArchetypeId::EMPTY
90#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
91// SAFETY: Must be repr(transparent) due to the safety requirements on EntityLocation
92#[repr(transparent)]
93pub struct ArchetypeId(u32);
94
95impl ArchetypeId {
96    /// The ID for the [`Archetype`] without any components.
97    pub const EMPTY: ArchetypeId = ArchetypeId(0);
98
99    /// Create an `ArchetypeId` from a plain value.
100    ///
101    /// This is useful if you need to store the `ArchetypeId` as a plain value,
102    /// for example in a specialized data structure such as a bitset.
103    ///
104    /// While it doesn't break any safety invariants, you should ensure the
105    /// values comes from a pre-existing [`ArchetypeId::index`] in this world
106    /// to avoid panics and other unexpected behaviors.
107    #[inline]
108    pub const fn new(index: usize) -> Self {
109        ArchetypeId(index as u32)
110    }
111
112    /// The plain value of this `ArchetypeId`.
113    ///
114    /// In bevy, this is mostly used to store archetype ids in [`FixedBitSet`]s.
115    ///
116    /// [`FixedBitSet`]: fixedbitset::FixedBitSet
117    #[inline]
118    pub fn index(self) -> usize {
119        self.0 as usize
120    }
121}
122
123/// Used in [`ArchetypeAfterBundleInsert`] to track whether components in the bundle are newly
124/// added or already existed in the entity's archetype.
125#[derive(Copy, Clone, Eq, PartialEq)]
126pub(crate) enum ComponentStatus {
127    Added,
128    Existing,
129}
130
131/// Used in [`Edges`] to cache the result of inserting a bundle into the source archetype.
132pub(crate) struct ArchetypeAfterBundleInsert {
133    /// The target archetype after the bundle is inserted into the source archetype.
134    pub archetype_id: ArchetypeId,
135    /// For each component iterated in the same order as the source [`Bundle`](crate::bundle::Bundle),
136    /// indicate if the component is newly added to the target archetype or if it already existed.
137    bundle_status: Box<[ComponentStatus]>,
138    /// The set of additional required components that must be initialized immediately when adding this Bundle.
139    ///
140    /// The initial values are determined based on the provided constructor, falling back to the `Default` trait if none is given.
141    pub required_components: Box<[RequiredComponentConstructor]>,
142    /// The components inserted by this bundle, with added components before existing ones.
143    /// Added components includes any Required Components that are inserted when adding this bundle,
144    /// but existing components only includes ones explicitly contributed by this bundle.
145    inserted: Box<[ComponentId]>,
146    /// The number of components added by this bundle, including Required Components.
147    added_len: usize,
148}
149
150impl ArchetypeAfterBundleInsert {
151    pub(crate) fn inserted(&self) -> &[ComponentId] {
152        &self.inserted
153    }
154
155    pub(crate) fn added(&self) -> &[ComponentId] {
156        // SAFETY: `added_len` is always in range `0..=inserted.len()`
157        unsafe { self.inserted.get(..self.added_len).debug_checked_unwrap() }
158    }
159
160    pub(crate) fn existing(&self) -> &[ComponentId] {
161        // SAFETY: `added_len` is always in range `0..=inserted.len()`
162        unsafe { self.inserted.get(self.added_len..).debug_checked_unwrap() }
163    }
164}
165
166/// This trait is used to report the status of [`Bundle`](crate::bundle::Bundle) components
167/// being inserted into a given entity, relative to that entity's original archetype.
168/// See [`BundleInfo::write_components`](`crate::bundle::BundleInfo::write_components`) for more info.
169pub(crate) trait BundleComponentStatus {
170    /// Returns the Bundle's component status for the given "bundle index".
171    ///
172    /// # Safety
173    /// Callers must ensure that index is always a valid bundle index for the
174    /// Bundle associated with this [`BundleComponentStatus`]
175    unsafe fn get_status(&self, index: usize) -> ComponentStatus;
176}
177
178impl BundleComponentStatus for ArchetypeAfterBundleInsert {
179    #[inline]
180    unsafe fn get_status(&self, index: usize) -> ComponentStatus {
181        // SAFETY: caller has ensured index is a valid bundle index for this bundle
182        unsafe { *self.bundle_status.get_unchecked(index) }
183    }
184}
185
186pub(crate) struct SpawnBundleStatus;
187
188impl BundleComponentStatus for SpawnBundleStatus {
189    #[inline]
190    unsafe fn get_status(&self, _index: usize) -> ComponentStatus {
191        // Components inserted during a spawn call are always treated as added.
192        ComponentStatus::Added
193    }
194}
195
196/// Archetypes and bundles form a graph. Adding or removing a bundle moves
197/// an [`Entity`] to a new [`Archetype`].
198///
199/// [`Edges`] caches the results of these moves. Each archetype caches
200/// the result of a structural alteration. This can be used to monitor the
201/// state of the archetype graph.
202///
203/// Note: This type only contains edges the [`World`] has already traversed.
204/// If any of functions return `None`, it doesn't mean there is guaranteed
205/// not to be a result of adding or removing that bundle, but rather that
206/// operation that has moved an entity along that edge has not been performed
207/// yet.
208///
209/// [`World`]: crate::world::World
210#[derive(Default)]
211pub struct Edges {
212    insert_bundle: SparseArray<BundleId, ArchetypeAfterBundleInsert>,
213    remove_bundle: SparseArray<BundleId, Option<ArchetypeId>>,
214    take_bundle: SparseArray<BundleId, Option<ArchetypeId>>,
215}
216
217impl Edges {
218    /// Checks the cache for the target archetype when inserting a bundle into the
219    /// source archetype.
220    ///
221    /// If this returns `None`, it means there has not been a transition from
222    /// the source archetype via the provided bundle.
223    #[inline]
224    pub fn get_archetype_after_bundle_insert(&self, bundle_id: BundleId) -> Option<ArchetypeId> {
225        self.get_archetype_after_bundle_insert_internal(bundle_id)
226            .map(|bundle| bundle.archetype_id)
227    }
228
229    /// Internal version of `get_archetype_after_bundle_insert` that
230    /// fetches the full `ArchetypeAfterBundleInsert`.
231    #[inline]
232    pub(crate) fn get_archetype_after_bundle_insert_internal(
233        &self,
234        bundle_id: BundleId,
235    ) -> Option<&ArchetypeAfterBundleInsert> {
236        self.insert_bundle.get(bundle_id)
237    }
238
239    /// Caches the target archetype when inserting a bundle into the source archetype.
240    #[inline]
241    pub(crate) fn cache_archetype_after_bundle_insert(
242        &mut self,
243        bundle_id: BundleId,
244        archetype_id: ArchetypeId,
245        bundle_status: impl Into<Box<[ComponentStatus]>>,
246        required_components: impl Into<Box<[RequiredComponentConstructor]>>,
247        mut added: Vec<ComponentId>,
248        existing: Vec<ComponentId>,
249    ) {
250        let added_len = added.len();
251        // Make sure `extend` doesn't over-reserve, since the conversion to `Box<[_]>` would reallocate to shrink.
252        added.reserve_exact(existing.len());
253        added.extend(existing);
254        self.insert_bundle.insert(
255            bundle_id,
256            ArchetypeAfterBundleInsert {
257                archetype_id,
258                bundle_status: bundle_status.into(),
259                required_components: required_components.into(),
260                added_len,
261                inserted: added.into(),
262            },
263        );
264    }
265
266    /// Checks the cache for the target archetype when removing a bundle from the
267    /// source archetype.
268    ///
269    /// If this returns `None`, it means there has not been a transition from
270    /// the source archetype via the provided bundle.
271    ///
272    /// If this returns `Some(None)`, it means that the bundle cannot be removed
273    /// from the source archetype.
274    #[inline]
275    pub fn get_archetype_after_bundle_remove(
276        &self,
277        bundle_id: BundleId,
278    ) -> Option<Option<ArchetypeId>> {
279        self.remove_bundle.get(bundle_id).cloned()
280    }
281
282    /// Caches the target archetype when removing a bundle from the source archetype.
283    #[inline]
284    pub(crate) fn cache_archetype_after_bundle_remove(
285        &mut self,
286        bundle_id: BundleId,
287        archetype_id: Option<ArchetypeId>,
288    ) {
289        self.remove_bundle.insert(bundle_id, archetype_id);
290    }
291
292    /// Checks the cache for the target archetype when taking a bundle from the
293    /// source archetype.
294    ///
295    /// Unlike `remove`, `take` will only succeed if the source archetype
296    /// contains all of the components in the bundle.
297    ///
298    /// If this returns `None`, it means there has not been a transition from
299    /// the source archetype via the provided bundle.
300    ///
301    /// If this returns `Some(None)`, it means that the bundle cannot be taken
302    /// from the source archetype.
303    #[inline]
304    pub fn get_archetype_after_bundle_take(
305        &self,
306        bundle_id: BundleId,
307    ) -> Option<Option<ArchetypeId>> {
308        self.take_bundle.get(bundle_id).cloned()
309    }
310
311    /// Caches the target archetype when taking a bundle from the source archetype.
312    ///
313    /// Unlike `remove`, `take` will only succeed if the source archetype
314    /// contains all of the components in the bundle.
315    #[inline]
316    pub(crate) fn cache_archetype_after_bundle_take(
317        &mut self,
318        bundle_id: BundleId,
319        archetype_id: Option<ArchetypeId>,
320    ) {
321        self.take_bundle.insert(bundle_id, archetype_id);
322    }
323}
324
325/// Metadata about an [`Entity`] in a [`Archetype`].
326pub struct ArchetypeEntity {
327    entity: Entity,
328    table_row: TableRow,
329}
330
331impl ArchetypeEntity {
332    /// The ID of the entity.
333    #[inline]
334    pub const fn id(&self) -> Entity {
335        self.entity
336    }
337
338    /// The row in the [`Table`] where the entity's components are stored.
339    ///
340    /// [`Table`]: crate::storage::Table
341    #[inline]
342    pub const fn table_row(&self) -> TableRow {
343        self.table_row
344    }
345}
346
347/// Internal metadata for an [`Entity`] getting removed from an [`Archetype`].
348pub(crate) struct ArchetypeSwapRemoveResult {
349    /// If the [`Entity`] was not the last in the [`Archetype`], it gets removed by swapping it out
350    /// with the last entity in the archetype. In that case, this field contains the swapped entity.
351    pub(crate) swapped_entity: Option<Entity>,
352    /// The [`TableRow`] where the removed entity's components are stored.
353    pub(crate) table_row: TableRow,
354}
355
356/// Internal metadata for a [`Component`] within a given [`Archetype`].
357///
358/// [`Component`]: crate::component::Component
359struct ArchetypeComponentInfo {
360    storage_type: StorageType,
361}
362
363bitflags::bitflags! {
364    /// Flags used to keep track of metadata about the component in this [`Archetype`]
365    ///
366    /// Used primarily to early-out when there are no [`ComponentHook`] registered for any contained components.
367    #[derive(Clone, Copy)]
368    pub(crate) struct ArchetypeFlags: u32 {
369        const ON_ADD_HOOK    = (1 << 0);
370        const ON_INSERT_HOOK = (1 << 1);
371        const ON_DISCARD_HOOK = (1 << 2);
372        const ON_REMOVE_HOOK = (1 << 3);
373        const ON_DESPAWN_HOOK = (1 << 4);
374        const ON_ADD_OBSERVER = (1 << 5);
375        const ON_INSERT_OBSERVER = (1 << 6);
376        const ON_DISCARD_OBSERVER = (1 << 7);
377        const ON_REMOVE_OBSERVER = (1 << 8);
378        const ON_DESPAWN_OBSERVER = (1 << 9);
379    }
380}
381
382/// Metadata for a single archetype within a [`World`].
383///
384/// For more information, see the *[module level documentation]*.
385///
386/// [`World`]: crate::world::World
387/// [module level documentation]: crate::archetype
388pub struct Archetype {
389    id: ArchetypeId,
390    table_id: TableId,
391    edges: Edges,
392    entities: Vec<ArchetypeEntity>,
393    components: ImmutableSparseSet<ComponentId, ArchetypeComponentInfo>,
394    pub(crate) flags: ArchetypeFlags,
395}
396
397impl Archetype {
398    /// `table_components` and `sparse_set_components` must be sorted
399    pub(crate) fn new(
400        components: &Components,
401        component_index: &mut ComponentIndex,
402        observers: &Observers,
403        id: ArchetypeId,
404        table_id: TableId,
405        table_components: impl Iterator<Item = ComponentId>,
406        sparse_set_components: impl Iterator<Item = ComponentId>,
407    ) -> Self {
408        let (min_table, _) = table_components.size_hint();
409        let (min_sparse, _) = sparse_set_components.size_hint();
410        let mut flags = ArchetypeFlags::empty();
411        let mut archetype_components = SparseSet::with_capacity(min_table + min_sparse);
412        for (idx, component_id) in table_components.enumerate() {
413            // SAFETY: We are creating an archetype that includes this component so it must exist
414            let info = unsafe { components.get_info_unchecked(component_id) };
415            info.update_archetype_flags(&mut flags);
416            observers.update_archetype_flags(component_id, &mut flags);
417            archetype_components.insert(
418                component_id,
419                ArchetypeComponentInfo {
420                    storage_type: StorageType::Table,
421                },
422            );
423            // NOTE: the `table_components` are sorted AND they were inserted in the `Table` in the same
424            // sorted order, so the index of the `Column` in the `Table` is the same as the index of the
425            // component in the `table_components` vector
426            component_index
427                .entry(component_id)
428                .or_default()
429                .insert(id, ArchetypeRecord { column: Some(idx) });
430        }
431
432        for component_id in sparse_set_components {
433            // SAFETY: We are creating an archetype that includes this component so it must exist
434            let info = unsafe { components.get_info_unchecked(component_id) };
435            info.update_archetype_flags(&mut flags);
436            observers.update_archetype_flags(component_id, &mut flags);
437            archetype_components.insert(
438                component_id,
439                ArchetypeComponentInfo {
440                    storage_type: StorageType::SparseSet,
441                },
442            );
443            component_index
444                .entry(component_id)
445                .or_default()
446                .insert(id, ArchetypeRecord { column: None });
447        }
448        Self {
449            id,
450            table_id,
451            entities: Vec::new(),
452            components: archetype_components.into_immutable(),
453            edges: Default::default(),
454            flags,
455        }
456    }
457
458    /// Fetches the ID for the archetype.
459    #[inline]
460    pub fn id(&self) -> ArchetypeId {
461        self.id
462    }
463
464    /// Fetches the flags for the archetype.
465    #[inline]
466    pub(crate) fn flags(&self) -> ArchetypeFlags {
467        self.flags
468    }
469
470    /// Fetches the archetype's [`Table`] ID.
471    ///
472    /// [`Table`]: crate::storage::Table
473    #[inline]
474    pub fn table_id(&self) -> TableId {
475        self.table_id
476    }
477
478    /// Fetches the entities contained in this archetype.
479    #[inline]
480    pub fn entities(&self) -> &[ArchetypeEntity] {
481        &self.entities
482    }
483
484    /// Fetches the entities contained in this archetype.
485    #[inline]
486    pub fn entities_with_location(&self) -> impl Iterator<Item = (Entity, EntityLocation)> {
487        self.entities.iter().enumerate().map(
488            |(archetype_row, &ArchetypeEntity { entity, table_row })| {
489                (
490                    entity,
491                    EntityLocation {
492                        archetype_id: self.id,
493                        // SAFETY: The entities in the archetype must be unique and there are never more than u32::MAX entities.
494                        archetype_row: unsafe {
495                            ArchetypeRow::new(NonMaxU32::new_unchecked(archetype_row as u32))
496                        },
497                        table_id: self.table_id,
498                        table_row,
499                    },
500                )
501            },
502        )
503    }
504
505    /// Gets an iterator of all of the components stored in [`Table`]s.
506    ///
507    /// All of the IDs are unique.
508    ///
509    /// [`Table`]: crate::storage::Table
510    #[inline]
511    pub fn table_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
512        self.components
513            .iter()
514            .filter(|(_, component)| component.storage_type == StorageType::Table)
515            .map(|(id, _)| *id)
516    }
517
518    /// Gets an iterator of all of the components stored in [`ComponentSparseSet`]s.
519    ///
520    /// All of the IDs are unique.
521    ///
522    /// [`ComponentSparseSet`]: crate::storage::ComponentSparseSet
523    #[inline]
524    pub fn sparse_set_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
525        self.components
526            .iter()
527            .filter(|(_, component)| component.storage_type == StorageType::SparseSet)
528            .map(|(id, _)| *id)
529    }
530
531    /// Returns a slice of all of the components in the archetype.
532    ///
533    /// All of the IDs are unique.
534    #[inline]
535    pub fn components(&self) -> &[ComponentId] {
536        self.components.indices()
537    }
538
539    /// Gets an iterator of all of the components in the archetype.
540    ///
541    /// All of the IDs are unique.
542    #[inline]
543    pub fn iter_components(&self) -> impl Iterator<Item = ComponentId> + Clone {
544        self.components.indices().iter().copied()
545    }
546
547    /// Returns the total number of components in the archetype
548    #[inline]
549    pub fn component_count(&self) -> usize {
550        self.components.len()
551    }
552
553    /// Fetches an immutable reference to the archetype's [`Edges`], a cache of
554    /// archetypal relationships.
555    #[inline]
556    pub fn edges(&self) -> &Edges {
557        &self.edges
558    }
559
560    /// Fetches a mutable reference to the archetype's [`Edges`], a cache of
561    /// archetypal relationships.
562    #[inline]
563    pub(crate) fn edges_mut(&mut self) -> &mut Edges {
564        &mut self.edges
565    }
566
567    /// Fetches the row in the [`Table`] where the components for the entity at `index`
568    /// is stored.
569    ///
570    /// An entity's archetype row can be fetched from [`EntityLocation::archetype_row`], which
571    /// can be retrieved from [`Entities::get`].
572    ///
573    /// # Panics
574    /// This function will panic if `index >= self.len()`.
575    ///
576    /// [`Table`]: crate::storage::Table
577    /// [`EntityLocation::archetype_row`]: crate::entity::EntityLocation::archetype_row
578    /// [`Entities::get`]: crate::entity::Entities::get
579    #[inline]
580    pub fn entity_table_row(&self, row: ArchetypeRow) -> TableRow {
581        self.entities[row.index()].table_row
582    }
583
584    /// Updates if the components for the entity at `index` can be found
585    /// in the corresponding table.
586    ///
587    /// # Panics
588    /// This function will panic if `index >= self.len()`.
589    #[inline]
590    pub(crate) fn set_entity_table_row(&mut self, row: ArchetypeRow, table_row: TableRow) {
591        self.entities[row.index()].table_row = table_row;
592    }
593
594    /// Allocates an entity to the archetype.
595    ///
596    /// # Safety
597    /// - valid component values must have been or be immediately written to the relevant storages
598    /// - `table_row` must be valid
599    #[inline]
600    pub(crate) unsafe fn allocate(
601        &mut self,
602        entity: Entity,
603        table_row: TableRow,
604    ) -> EntityLocation {
605        // SAFETY: An entity can not have multiple archetype rows and there can not be more than u32::MAX entities.
606        let archetype_row = unsafe { ArchetypeRow::new(NonMaxU32::new_unchecked(self.len())) };
607        self.entities.push(ArchetypeEntity { entity, table_row });
608
609        EntityLocation {
610            archetype_id: self.id,
611            archetype_row,
612            table_id: self.table_id,
613            table_row,
614        }
615    }
616
617    #[inline]
618    pub(crate) fn reserve(&mut self, additional: usize) {
619        self.entities.reserve(additional);
620    }
621
622    /// Removes the entity at `row` by swapping it out. Returns the table row the entity is stored
623    /// in.
624    ///
625    /// # Panics
626    /// This function will panic if `row >= self.entities.len()`
627    #[inline]
628    pub(crate) fn swap_remove(&mut self, row: ArchetypeRow) -> ArchetypeSwapRemoveResult {
629        let is_last = row.index() == self.entities.len() - 1;
630        let entity = self.entities.swap_remove(row.index());
631        ArchetypeSwapRemoveResult {
632            swapped_entity: if is_last {
633                None
634            } else {
635                Some(self.entities[row.index()].entity)
636            },
637            table_row: entity.table_row,
638        }
639    }
640
641    /// Gets the total number of entities that belong to the archetype.
642    #[inline]
643    pub fn len(&self) -> u32 {
644        // No entity may have more than one archetype row, so there are no duplicates,
645        // and there may only ever be u32::MAX entities, so the length never exceeds u32's capacity.
646        self.entities.len() as u32
647    }
648
649    /// Checks if the archetype has any entities.
650    #[inline]
651    pub fn is_empty(&self) -> bool {
652        self.entities.is_empty()
653    }
654
655    /// Checks if the archetype contains a specific component. This runs in `O(1)` time.
656    #[inline]
657    pub fn contains(&self, component_id: ComponentId) -> bool {
658        self.components.contains(component_id)
659    }
660
661    /// Gets the type of storage where a component in the archetype can be found.
662    /// Returns `None` if the component is not part of the archetype.
663    /// This runs in `O(1)` time.
664    #[inline]
665    pub fn get_storage_type(&self, component_id: ComponentId) -> Option<StorageType> {
666        self.components
667            .get(component_id)
668            .map(|info| info.storage_type)
669    }
670
671    /// Clears all entities from the archetype.
672    pub(crate) fn clear_entities(&mut self) {
673        self.entities.clear();
674    }
675
676    /// Returns true if any of the components in this archetype have `on_add` hooks
677    #[inline]
678    pub fn has_add_hook(&self) -> bool {
679        self.flags().contains(ArchetypeFlags::ON_ADD_HOOK)
680    }
681
682    /// Returns true if any of the components in this archetype have `on_insert` hooks
683    #[inline]
684    pub fn has_insert_hook(&self) -> bool {
685        self.flags().contains(ArchetypeFlags::ON_INSERT_HOOK)
686    }
687
688    /// Returns true if any of the components in this archetype have `on_discard` hooks
689    #[inline]
690    pub fn has_discard_hook(&self) -> bool {
691        self.flags().contains(ArchetypeFlags::ON_DISCARD_HOOK)
692    }
693
694    /// Returns true if any of the components in this archetype have `on_remove` hooks
695    #[inline]
696    pub fn has_remove_hook(&self) -> bool {
697        self.flags().contains(ArchetypeFlags::ON_REMOVE_HOOK)
698    }
699
700    /// Returns true if any of the components in this archetype have `on_despawn` hooks
701    #[inline]
702    pub fn has_despawn_hook(&self) -> bool {
703        self.flags().contains(ArchetypeFlags::ON_DESPAWN_HOOK)
704    }
705
706    /// Returns true if any of the components in this archetype have at least one [`Add`] observer
707    ///
708    /// [`Add`]: crate::lifecycle::Add
709    #[inline]
710    pub fn has_add_observer(&self) -> bool {
711        self.flags().contains(ArchetypeFlags::ON_ADD_OBSERVER)
712    }
713
714    /// Returns true if any of the components in this archetype have at least one [`Insert`] observer
715    ///
716    /// [`Insert`]: crate::lifecycle::Insert
717    #[inline]
718    pub fn has_insert_observer(&self) -> bool {
719        self.flags().contains(ArchetypeFlags::ON_INSERT_OBSERVER)
720    }
721
722    /// Returns true if any of the components in this archetype have at least one [`Discard`] observer
723    ///
724    /// [`Discard`]: crate::lifecycle::Discard
725    #[inline]
726    pub fn has_discard_observer(&self) -> bool {
727        self.flags().contains(ArchetypeFlags::ON_DISCARD_OBSERVER)
728    }
729
730    /// Returns true if any of the components in this archetype have at least one [`Remove`] observer
731    ///
732    /// [`Remove`]: crate::lifecycle::Remove
733    #[inline]
734    pub fn has_remove_observer(&self) -> bool {
735        self.flags().contains(ArchetypeFlags::ON_REMOVE_OBSERVER)
736    }
737
738    /// Returns true if any of the components in this archetype have at least one [`Despawn`] observer
739    ///
740    /// [`Despawn`]: crate::lifecycle::Despawn
741    #[inline]
742    pub fn has_despawn_observer(&self) -> bool {
743        self.flags().contains(ArchetypeFlags::ON_DESPAWN_OBSERVER)
744    }
745}
746
747/// The next [`ArchetypeId`] in an [`Archetypes`] collection.
748///
749/// This is used in archetype update methods to limit archetype updates to the
750/// ones added since the last time the method ran.
751#[derive(Debug, Copy, Clone, PartialEq)]
752pub struct ArchetypeGeneration(pub(crate) ArchetypeId);
753
754impl ArchetypeGeneration {
755    /// The first archetype.
756    #[inline]
757    pub const fn initial() -> Self {
758        ArchetypeGeneration(ArchetypeId::EMPTY)
759    }
760}
761
762#[derive(Hash, PartialEq, Eq)]
763struct ArchetypeComponents {
764    table_components: Box<[ComponentId]>,
765    sparse_set_components: Box<[ComponentId]>,
766}
767
768/// Maps a [`ComponentId`] to the list of [`Archetypes`]([`Archetype`]) that contain the [`Component`](crate::component::Component),
769/// along with an [`ArchetypeRecord`] which contains some metadata about how the component is stored in the archetype.
770pub type ComponentIndex = HashMap<ComponentId, HashMap<ArchetypeId, ArchetypeRecord>>;
771
772/// The backing store of all [`Archetype`]s within a [`World`].
773///
774/// For more information, see the *[module level documentation]*.
775///
776/// [`World`]: crate::world::World
777/// [module level documentation]: crate::archetype
778pub struct Archetypes {
779    pub(crate) archetypes: Vec<Archetype>,
780    /// find the archetype id by the archetype's components
781    by_components: HashMap<ArchetypeComponents, ArchetypeId>,
782    /// find all the archetypes that contain a component
783    pub(crate) by_component: ComponentIndex,
784}
785
786/// Metadata about how a component is stored in an [`Archetype`].
787pub struct ArchetypeRecord {
788    /// Index of the component in the archetype's [`Table`](crate::storage::Table),
789    /// or None if the component is a sparse set component.
790    #[expect(
791        dead_code,
792        reason = "Currently unused, but planned to be used to implement a component index to improve performance of fragmenting relations."
793    )]
794    pub(crate) column: Option<usize>,
795}
796
797impl Archetypes {
798    pub(crate) fn new() -> Self {
799        let mut archetypes = Archetypes {
800            archetypes: Vec::new(),
801            by_components: Default::default(),
802            by_component: Default::default(),
803        };
804        // SAFETY: Empty archetype has no components
805        unsafe {
806            archetypes.get_id_or_insert(
807                &Components::default(),
808                &Observers::default(),
809                TableId::empty(),
810                Vec::new(),
811                Vec::new(),
812            );
813        }
814        archetypes
815    }
816
817    /// Returns the "generation", a handle to the current highest archetype ID.
818    ///
819    /// This can be used with the `Index` [`Archetypes`] implementation to
820    /// iterate over newly introduced [`Archetype`]s since the last time this
821    /// function was called.
822    #[inline]
823    pub fn generation(&self) -> ArchetypeGeneration {
824        let id = ArchetypeId::new(self.archetypes.len());
825        ArchetypeGeneration(id)
826    }
827
828    /// Fetches the total number of [`Archetype`]s within the world.
829    #[inline]
830    #[expect(
831        clippy::len_without_is_empty,
832        reason = "The internal vec is never empty"
833    )]
834    pub fn len(&self) -> usize {
835        self.archetypes.len()
836    }
837
838    /// Fetches an immutable reference to the archetype without any components.
839    ///
840    /// Shorthand for `archetypes.get(ArchetypeId::EMPTY).unwrap()`
841    #[inline]
842    pub fn empty(&self) -> &Archetype {
843        // SAFETY: empty archetype always exists
844        unsafe { self.archetypes.get_unchecked(ArchetypeId::EMPTY.index()) }
845    }
846
847    /// Fetches a mutable reference to the archetype without any components.
848    #[inline]
849    pub(crate) fn empty_mut(&mut self) -> &mut Archetype {
850        // SAFETY: empty archetype always exists
851        unsafe {
852            self.archetypes
853                .get_unchecked_mut(ArchetypeId::EMPTY.index())
854        }
855    }
856
857    /// Fetches an immutable reference to an [`Archetype`] using its
858    /// ID. Returns `None` if no corresponding archetype exists.
859    #[inline]
860    pub fn get(&self, id: ArchetypeId) -> Option<&Archetype> {
861        self.archetypes.get(id.index())
862    }
863
864    /// Tries to fetch mutable references to two disjoint archetypes.
865    ///
866    /// Returns `(&mut Archetype, None)` if the same [`ArchetypeId`] was provided twice.
867    ///
868    /// # Safety
869    /// - Both [`ArchetypeId`]s must be valid for this [`Archetypes`].
870    #[inline]
871    pub(crate) unsafe fn get_maybe_disjoint_mut(
872        &mut self,
873        id_a: ArchetypeId,
874        id_b: ArchetypeId,
875    ) -> (&mut Archetype, Option<&mut Archetype>) {
876        if id_a == id_b {
877            // SAFETY:
878            // - The caller ensures `id_a` is in-bounds.
879            let archetype_a = unsafe { self.archetypes.get_unchecked_mut(id_a.index()) };
880            (archetype_a, None)
881        } else {
882            // SAFETY:
883            // - `id_a` and `id_b` do not overlap in this branch.
884            // - The caller ensures `id_a` and `id_b` are in-bounds.
885            let [archetype_a, archetype_b] = unsafe {
886                self.archetypes
887                    .get_disjoint_unchecked_mut([id_a.index(), id_b.index()])
888            };
889            (archetype_a, Some(archetype_b))
890        }
891    }
892
893    /// Returns a read-only iterator over all archetypes.
894    #[inline]
895    pub fn iter(&self) -> impl Iterator<Item = &Archetype> {
896        self.archetypes.iter()
897    }
898
899    /// Gets the archetype id matching the given inputs or inserts a new one if it doesn't exist.
900    ///
901    /// Specifically, it returns a tuple where the first element
902    /// is the [`ArchetypeId`] that the given inputs belong to, and the second element is a boolean indicating whether a new archetype was created.
903    ///
904    /// `table_components` and `sparse_set_components` must be sorted
905    ///
906    /// # Safety
907    /// [`TableId`] must exist in tables
908    /// `table_components` and `sparse_set_components` must exist in `components`
909    pub(crate) unsafe fn get_id_or_insert(
910        &mut self,
911        components: &Components,
912        observers: &Observers,
913        table_id: TableId,
914        table_components: Vec<ComponentId>,
915        sparse_set_components: Vec<ComponentId>,
916    ) -> (ArchetypeId, bool) {
917        let archetype_identity = ArchetypeComponents {
918            sparse_set_components: sparse_set_components.into_boxed_slice(),
919            table_components: table_components.into_boxed_slice(),
920        };
921
922        let archetypes = &mut self.archetypes;
923        let component_index = &mut self.by_component;
924        match self.by_components.entry(archetype_identity) {
925            Entry::Occupied(occupied) => (*occupied.get(), false),
926            Entry::Vacant(vacant) => {
927                let ArchetypeComponents {
928                    table_components,
929                    sparse_set_components,
930                } = vacant.key();
931                let id = ArchetypeId::new(archetypes.len());
932                archetypes.push(Archetype::new(
933                    components,
934                    component_index,
935                    observers,
936                    id,
937                    table_id,
938                    table_components.iter().copied(),
939                    sparse_set_components.iter().copied(),
940                ));
941                vacant.insert(id);
942                (id, true)
943            }
944        }
945    }
946
947    /// Clears all entities from all archetypes.
948    pub(crate) fn clear_entities(&mut self) {
949        for archetype in &mut self.archetypes {
950            archetype.clear_entities();
951        }
952    }
953
954    /// Get the component index
955    pub fn component_index(&self) -> &ComponentIndex {
956        &self.by_component
957    }
958
959    pub(crate) fn update_flags(
960        &mut self,
961        component_id: ComponentId,
962        flags: ArchetypeFlags,
963        set: bool,
964    ) {
965        if let Some(archetypes) = self.by_component.get(&component_id) {
966            for archetype_id in archetypes.keys() {
967                // SAFETY: the component index only contains valid archetype ids
968                self.archetypes
969                    .get_mut(archetype_id.index())
970                    .unwrap()
971                    .flags
972                    .set(flags, set);
973            }
974        }
975    }
976}
977
978impl Index<RangeFrom<ArchetypeGeneration>> for Archetypes {
979    type Output = [Archetype];
980
981    #[inline]
982    fn index(&self, index: RangeFrom<ArchetypeGeneration>) -> &Self::Output {
983        &self.archetypes[index.start.0.index()..]
984    }
985}
986
987impl Index<ArchetypeId> for Archetypes {
988    type Output = Archetype;
989
990    #[inline]
991    fn index(&self, index: ArchetypeId) -> &Self::Output {
992        &self.archetypes[index.index()]
993    }
994}
995
996impl IndexMut<ArchetypeId> for Archetypes {
997    #[inline]
998    fn index_mut(&mut self, index: ArchetypeId) -> &mut Self::Output {
999        &mut self.archetypes[index.index()]
1000    }
1001}