worlds_ecs/world/storage/
mod.rs

1use self::arch_storage::{ArchStorage, ArchStorageIndex};
2use crate::{
3    archetype::Archetype,
4    entity::EntityId,
5    prelude::{Bundle, ComponentFactory, ComponentId},
6};
7use bevy_ptr::PtrMut;
8use std::ops::Deref;
9
10/// Defining a data-structures to store a bundle of components, a.k.a archetype storage.
11pub mod arch_storage;
12/// A module to define abstractions around all the storages in the world.
13pub mod storages;
14/// A module to define abstractions around storing entities' tags.
15pub mod tag_storage;
16
17/// The storage for entities with the same [`Archetype`]. This holds the actual data of the entities,
18/// as well as data about the entities themselves.
19pub struct ArchEntityStorage {
20    /// The [`ArchStorage`] that stores the actual data.
21    arch_storage: ArchStorage,
22    /// The Id of each entity in the storage. Indexed by the entity's index in the [`ArchStorage`] ([`ArchStorageIndex`])
23    entities: Vec<EntityId>,
24}
25
26impl Deref for ArchEntityStorage {
27    type Target = ArchStorage;
28
29    fn deref(&self) -> &Self::Target {
30        &self.arch_storage
31    }
32}
33
34impl ArchEntityStorage {
35    /// Create a new [`ArchEntityStorage`] for the given [`Archetype`].
36    pub fn new<A: Archetype>(compf: &ComponentFactory) -> Option<Self> {
37        Some(Self {
38            arch_storage: ArchStorage::new::<A>(compf)?,
39            entities: Vec::new(),
40        })
41    }
42
43    /// Get the next index. As in, if a new entity were to be stored right now, that index it would get.
44    pub fn next_index(&self) -> ArchStorageIndex {
45        ArchStorageIndex(self.len())
46    }
47
48    /// Store an entity in the storage, with a [`Bundle`] of components, and return its index.
49    pub fn store_entity<B: Bundle + Archetype>(
50        &mut self,
51        entity_id: EntityId,
52        bundle: B,
53        compf: &ComponentFactory,
54    ) -> Option<ArchStorageIndex> {
55        self.entities.push(entity_id);
56        self.arch_storage.store_bundle(compf, bundle)
57    }
58
59    /// Get a type-erased mutable reference to a pointer, from its index and [`ComponentId`].
60    /// Retuns `None` if the index is out of bounds, or if the component is not stored in this storage.
61    pub fn get_component_mut(
62        &mut self,
63        index: ArchStorageIndex,
64        comp_id: ComponentId,
65    ) -> Option<PtrMut<'_>> {
66        self.arch_storage.get_component_mut(index, comp_id)
67    }
68
69    /// Get a type-erased mutable reference to a pointer, from its index and [`ComponentId`].
70    ///
71    /// # Safety
72    /// The caller must ensure that the component matching the given [`ComponentId`] is indeed
73    /// stored in [`Self`], and that `index < self.len()`.
74    pub unsafe fn get_component_mut_unchecked(
75        &mut self,
76        index: ArchStorageIndex,
77        comp_id: ComponentId,
78    ) -> PtrMut<'_> { unsafe {
79        self.arch_storage
80            .get_component_mut_unchecked(index, comp_id)
81    }}
82
83    /// Get the [`EntityId`] of the entity stored at that index.
84    /// Return `None` if the index is out of bounds.
85    pub fn get_entity_at(&self, index: ArchStorageIndex) -> Option<EntityId> {
86        self.entities.get(index.0).copied()
87    }
88
89    /// Get the [`EntityId`] of the entity stored at that index, without doing bounds checking.
90    /// # Safety
91    /// The caller must ensure that the `index` is valid, and within the bounds of the storage.
92    pub unsafe fn get_entity_at_unchecked(&self, index: ArchStorageIndex) -> EntityId { unsafe {
93        *self.entities.get_unchecked(index.0)
94    }}
95
96    /// Swap-remove an entity and its data. This is used for despawning entities.
97    /// Returns the [`EntityId`] that was last, so its [`EntityMeta`] can be updated
98    /// to reflect the new [`ArchStorageIndex`].
99    /// Return `None` if no `EntityMeta` needs to be updated (that swap-remove removed the last entity)
100    /// # Panics
101    /// Panics if the index is out of bounds.
102    pub fn swap_remove(&mut self, index: ArchStorageIndex) -> Option<EntityId> {
103        self.entities.swap_remove(index.0);
104        // SAFETY: doing `swap_remove` on self.entities didn't panic, and because self.entities and
105        // the internal component storages have the same length, that must mean the index is in bounds.
106        unsafe { self.arch_storage.swap_remove_unchecked(index) }
107        self.get_entity_at(index) // If we swap-remove the last entity, that means that there is no entity that
108                                  // whose `EntityMeta` needs updating. So we return `None`.
109    }
110}