hyperion/component_storage.rs
1use crate::entity::Entity;
2use std::any::Any;
3use std::collections::HashMap;
4
5/// Marker trait for types that can be used as components in the ECS.
6pub trait Component: 'static {}
7
8/// Storage for components of type `T`. Maintains dense storage and entity-index mappings.
9///
10/// # Fields
11/// - `components`: Dense array of components of type `T`.
12/// - `entity_to_index`: Map from `Entity` to its dense array index.
13/// - `index_to_entity`: Reverse map from dense array index to owning `Entity`.
14///
15/// # Safety
16/// - Storage remains dense by using swap-remove on deletion; index maps are updated
17/// accordingly to prevent dangling indices. Component references returned by
18/// queries are valid for the borrow duration and follow Rust's aliasing rules.
19pub struct ComponentStorage<T: Component> {
20 components: Vec<T>,
21 entity_to_index: HashMap<Entity, usize>,
22 index_to_entity: Vec<Entity>,
23}
24
25impl<T: Component> ComponentStorage<T> {
26 /// Creates a new, empty component storage.
27 ///
28 /// # Returns
29 /// - `ComponentStorage<T>`: An empty storage ready to hold components of type `T`.
30 pub fn new() -> Self {
31 Self {
32 components: Vec::new(),
33 entity_to_index: HashMap::new(),
34 index_to_entity: Vec::new(),
35 }
36 }
37
38 /// Given a reference to a component in this storage, return the owning `Entity`.
39 ///
40 /// This performs an O(n) scan comparing pointer identity within the dense
41 /// component array to locate the index, then maps that index back to the entity.
42 ///
43 /// # Parameters
44 /// - `component`: A reference to a component stored in this storage.
45 ///
46 /// # Returns
47 /// - `Option<Entity>`: The entity that owns the component, if found.
48 pub fn get_entity_for_component(&self, component: &T) -> Option<Entity> {
49 for (idx, comp_ref) in self.components.iter().enumerate() {
50 if std::ptr::eq(comp_ref, component) {
51 return Some(self.index_to_entity[idx]);
52 }
53 }
54 None
55 }
56
57 /// Inserts or replaces a component for an entity.
58 ///
59 /// # Parameters
60 /// - `entity`: The entity that will own the component.
61 /// - `component`: The component instance to insert (or replace if one already exists).
62 pub fn insert(&mut self, entity: Entity, component: T) {
63 if let Some(&index) = self.entity_to_index.get(&entity) {
64 // Replace existing component at index.
65 self.components[index] = component;
66 } else {
67 // Insert new component at end and update mappings.
68 let index = self.components.len();
69 self.components.push(component);
70 self.entity_to_index.insert(entity, index);
71 self.index_to_entity.push(entity);
72 }
73 }
74
75 /// Removes the component for an entity, returning it if present.
76 /// Uses swap-remove to keep storage dense and updates mappings accordingly.
77 ///
78 /// # Parameters
79 /// - `entity`: The entity whose component should be removed.
80 ///
81 /// # Returns
82 /// - `Option<T>`: The removed component if it existed.
83 pub fn remove(&mut self, entity: Entity) -> Option<T> {
84 self.entity_to_index.remove(&entity).map(|index| {
85 let last_index = self.components.len() - 1;
86
87 // If not the last component, swap to keep storage dense
88 if index != last_index {
89 self.components.swap(index, last_index);
90 self.index_to_entity.swap(index, last_index);
91
92 // Update moved entity's mapping to new index
93 let swapped_entity = self.index_to_entity[index];
94 self.entity_to_index.insert(swapped_entity, index);
95 }
96
97 self.index_to_entity.pop();
98 self.components.pop().unwrap()
99 })
100 }
101
102 /// Gets an immutable reference to a component for an entity, if it exists.
103 ///
104 /// # Parameters
105 /// - `entity`: The entity whose component to retrieve.
106 ///
107 /// # Returns
108 /// - `Option<&T>`: A reference to the component if present.
109 pub fn get(&self, entity: Entity) -> Option<&T> {
110 self.entity_to_index
111 .get(&entity)
112 .map(|&index| &self.components[index])
113 }
114
115 /// Gets a mutable reference to a component for an entity, if it exists.
116 ///
117 /// # Parameters
118 /// - `entity`: The entity whose component to retrieve mutably.
119 ///
120 /// # Returns
121 /// - `Option<&mut T>`: A mutable reference to the component if present.
122 pub fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
123 self.entity_to_index
124 .get(&entity)
125 .map(|&index| &mut self.components[index])
126 }
127
128 /// Returns all components as a vector of immutable references.
129 ///
130 /// # Returns
131 /// - `Vec<&T>`: All components currently stored.
132 pub fn get_all(&self) -> Vec<&T> {
133 self.components.iter().collect()
134 }
135
136 /// Returns all components as a vector of mutable references.
137 ///
138 /// # Returns
139 /// - `Vec<&mut T>`: All components currently stored, mutably borrowed.
140 pub fn get_all_mut(&mut self) -> Vec<&mut T> {
141 self.components.iter_mut().collect()
142 }
143
144 /// Returns an iterator over immutable references to components.
145 ///
146 /// # Returns
147 /// - `impl Iterator<Item = &T>`: Iterator over all components.
148 pub fn iter(&self) -> impl Iterator<Item = &T> {
149 self.components.iter()
150 }
151
152 /// Returns an iterator over mutable references to components.
153 ///
154 /// # Returns
155 /// - `impl Iterator<Item = &mut T>`: Iterator over all components mutably.
156 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut T> {
157 self.components.iter_mut()
158 }
159
160 /// Returns an iterator over all entities and immutable references to their components.
161 ///
162 /// # Returns
163 /// - `impl Iterator<Item = (Entity, &T)>`: Iterator of `(Entity, &T)` pairs.
164 pub fn iter_with_entities(&self) -> impl Iterator<Item = (Entity, &T)> {
165 self.index_to_entity
166 .iter()
167 .copied()
168 .zip(self.components.iter())
169 }
170
171 /// Returns an iterator over all entities and mutable references to their components.
172 ///
173 /// # Returns
174 /// - `impl Iterator<Item = (Entity, &mut T)>`: Iterator of `(Entity, &mut T)` pairs.
175 pub fn iter_with_entities_mut(&mut self) -> impl Iterator<Item = (Entity, &mut T)> {
176 let entities = self.index_to_entity.clone(); // Clone to avoid borrow checker issues
177 entities.into_iter().zip(self.components.iter_mut())
178 }
179
180 /// Returns true if this storage contains a component for the specified entity.
181 ///
182 /// # Parameters
183 /// - `entity`: The entity to check.
184 ///
185 /// # Returns
186 /// - `bool`: `true` if a component for `entity` exists in this storage.
187 pub fn has(&self, entity: Entity) -> bool {
188 self.entity_to_index.contains_key(&entity)
189 }
190}
191
192/// A type-erased interface over concrete `ComponentStorage<T>` implementations.
193///
194/// Enables the `World` to store heterogeneous component storages behind a single
195/// trait object and perform operations such as removing an entity's component
196/// without knowing the concrete `T` at compile time.
197///
198/// # Safety
199/// - Downcasting is only exposed via `as_any`/`as_any_mut` and is guarded by
200/// external `TypeId` checks in `World` before downcast is attempted.
201/// - `remove_entity` must maintain dense storage invariants of the underlying
202/// storage (e.g., swap-remove updates index maps) when implemented.
203pub trait ComponentStorageTrait {
204 /// Removes the component associated with `entity` from this storage, if present.
205 ///
206 /// # Parameters
207 /// - `entity`: The entity whose component should be removed from this storage.
208 ///
209 /// # Effects
210 /// - If a component exists for `entity`, it is removed. Implementations typically
211 /// use swap-remove to keep storage dense and update internal mappings accordingly.
212 fn remove_entity(&mut self, entity: Entity);
213
214 /// Returns a type-erased immutable view of this storage for downcasting.
215 ///
216 /// # Returns
217 /// - `&dyn Any`: A reference that can be downcast using `Any::downcast_ref` to
218 /// access the concrete `ComponentStorage<T>` when the caller knows `T`.
219 ///
220 /// # Safety
221 /// - Callers must only downcast to the correct type, typically ensured via
222 /// `TypeId` checks performed by `World` helpers.
223 fn as_any(&self) -> &dyn Any;
224
225 /// Returns a type-erased mutable view of this storage for downcasting.
226 ///
227 /// # Returns
228 /// - `&mut dyn Any`: A mutable reference that can be downcast using
229 /// `Any::downcast_mut` to access the concrete `ComponentStorage<T>`.
230 ///
231 /// # Safety
232 /// - Callers must ensure the downcast target type matches the actual storage type.
233 /// The `World` ensures correctness via `TypeId` checks before downcasting.
234 fn as_any_mut(&mut self) -> &mut dyn Any;
235}
236
237impl<T: Component> ComponentStorageTrait for ComponentStorage<T> {
238 /// Removes the component for the given `entity` from this concrete storage.
239 ///
240 /// # Parameters
241 /// - `entity`: The entity whose component should be removed.
242 ///
243 /// # Effects
244 /// - If a component exists for `entity`, it is removed using the storage's
245 /// internal removal logic (swap-remove), maintaining dense storage and
246 /// updating index mappings accordingly.
247 fn remove_entity(&mut self, entity: Entity) {
248 let _ = self.remove(entity);
249 }
250
251 /// Returns an immutable, type-erased view of this concrete storage for downcasting.
252 ///
253 /// # Returns
254 /// - `&dyn Any`: A reference that can be downcast via `Any::downcast_ref`
255 /// to `ComponentStorage<T>` by callers that know the concrete `T`.
256 ///
257 /// # Safety
258 /// - Callers must only attempt to downcast to the correct concrete type.
259 /// The `World` ensures this by checking `TypeId` prior to downcasting.
260 fn as_any(&self) -> &dyn Any {
261 self
262 }
263
264 /// Returns a mutable, type-erased view of this concrete storage for downcasting.
265 ///
266 /// # Returns
267 /// - `&mut dyn Any`: A mutable reference that can be downcast via
268 /// `Any::downcast_mut` to `ComponentStorage<T>` when the caller knows `T`.
269 ///
270 /// # Safety
271 /// - Callers must ensure the downcast target type matches the underlying
272 /// storage. `World` APIs guard this via `TypeId` checks before downcasting.
273 fn as_any_mut(&mut self) -> &mut dyn Any {
274 self
275 }
276}