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}