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}