1use core::any::{Any, TypeId};
7use core::fmt;
8use std::collections::HashMap;
9
10use serde::{Deserialize, Serialize};
11
12use crate::{CoreError, Result};
13
14#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19pub struct Entity(pub u64);
20
21impl Entity {
22 #[must_use]
24 pub const fn new(id: u64) -> Self {
25 Self(id)
26 }
27
28 #[must_use]
30 pub const fn id(self) -> u64 {
31 self.0
32 }
33}
34
35impl fmt::Debug for Entity {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 write!(f, "Entity({})", self.0)
38 }
39}
40
41impl fmt::Display for Entity {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 write!(f, "e{}", self.0)
44 }
45}
46
47struct ComponentStorage {
49 data: HashMap<Entity, Box<dyn Any + Send + Sync>>,
50}
51
52impl ComponentStorage {
53 fn new() -> Self {
54 Self {
55 data: HashMap::new(),
56 }
57 }
58
59 fn insert<T: Any + Send + Sync>(&mut self, entity: Entity, component: T) {
60 let _ = self.data.insert(entity, Box::new(component));
61 }
62
63 fn get<T: Any>(&self, entity: Entity) -> Option<&T> {
64 self.data.get(&entity).and_then(|c| c.downcast_ref())
65 }
66
67 fn get_mut<T: Any>(&mut self, entity: Entity) -> Option<&mut T> {
68 self.data.get_mut(&entity).and_then(|c| c.downcast_mut())
69 }
70
71 fn remove(&mut self, entity: Entity) -> bool {
72 self.data.remove(&entity).is_some()
73 }
74
75 fn contains(&self, entity: Entity) -> bool {
76 self.data.contains_key(&entity)
77 }
78}
79
80pub struct World {
99 next_entity_id: u64,
100 entities: Vec<Entity>,
101 components: HashMap<TypeId, ComponentStorage>,
102}
103
104impl Default for World {
105 fn default() -> Self {
106 Self::new()
107 }
108}
109
110impl World {
111 #[must_use]
113 pub fn new() -> Self {
114 Self {
115 next_entity_id: 0,
116 entities: Vec::new(),
117 components: HashMap::new(),
118 }
119 }
120
121 pub fn spawn(&mut self) -> Entity {
123 let entity = Entity::new(self.next_entity_id);
124 self.next_entity_id += 1;
125 self.entities.push(entity);
126 entity
127 }
128
129 pub fn despawn(&mut self, entity: Entity) -> Result<()> {
135 let idx = self
136 .entities
137 .iter()
138 .position(|&e| e == entity)
139 .ok_or(CoreError::EntityNotFound(entity))?;
140
141 let _ = self.entities.swap_remove(idx);
142
143 for storage in self.components.values_mut() {
145 let _ = storage.remove(entity);
146 }
147
148 Ok(())
149 }
150
151 pub fn add_component<T: Any + Send + Sync>(&mut self, entity: Entity, component: T) {
155 let type_id = TypeId::of::<T>();
156 self.components
157 .entry(type_id)
158 .or_insert_with(ComponentStorage::new)
159 .insert(entity, component);
160 }
161
162 #[must_use]
164 pub fn get_component<T: Any>(&self, entity: Entity) -> Option<&T> {
165 let type_id = TypeId::of::<T>();
166 self.components.get(&type_id).and_then(|s| s.get(entity))
167 }
168
169 pub fn get_component_mut<T: Any>(&mut self, entity: Entity) -> Option<&mut T> {
171 let type_id = TypeId::of::<T>();
172 self.components
173 .get_mut(&type_id)
174 .and_then(|s| s.get_mut(entity))
175 }
176
177 #[must_use]
179 pub fn has_component<T: Any>(&self, entity: Entity) -> bool {
180 let type_id = TypeId::of::<T>();
181 self.components
182 .get(&type_id)
183 .is_some_and(|s| s.contains(entity))
184 }
185
186 pub fn remove_component<T: Any>(&mut self, entity: Entity) -> bool {
190 let type_id = TypeId::of::<T>();
191 self.components
192 .get_mut(&type_id)
193 .is_some_and(|s| s.remove(entity))
194 }
195
196 #[must_use]
198 pub fn entity_count(&self) -> usize {
199 self.entities.len()
200 }
201
202 pub fn entities(&self) -> impl Iterator<Item = Entity> + '_ {
204 self.entities.iter().copied()
205 }
206
207 #[must_use]
209 pub fn contains(&self, entity: Entity) -> bool {
210 self.entities.contains(&entity)
211 }
212}
213
214impl fmt::Debug for World {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 f.debug_struct("World")
217 .field("entity_count", &self.entities.len())
218 .field("component_types", &self.components.len())
219 .finish_non_exhaustive()
220 }
221}
222
223#[cfg(test)]
224#[allow(
225 clippy::unwrap_used,
226 clippy::expect_used,
227 clippy::let_underscore_must_use
228)]
229mod tests {
230 use super::*;
231 use crate::components::{Position, Velocity};
232
233 #[test]
236 fn test_entity_creation() {
237 let e = Entity::new(42);
238 assert_eq!(e.id(), 42);
239 }
240
241 #[test]
242 fn test_entity_display() {
243 let e = Entity::new(123);
244 assert_eq!(format!("{e}"), "e123");
245 }
246
247 #[test]
248 fn test_entity_debug() {
249 let e = Entity::new(456);
250 assert_eq!(format!("{e:?}"), "Entity(456)");
251 }
252
253 #[test]
254 fn test_entity_equality() {
255 let e1 = Entity::new(1);
256 let e2 = Entity::new(1);
257 let e3 = Entity::new(2);
258 assert_eq!(e1, e2);
259 assert_ne!(e1, e3);
260 }
261
262 #[test]
263 fn test_entity_hash() {
264 use std::collections::HashSet;
265 let mut set = HashSet::new();
266 let _ = set.insert(Entity::new(1));
267 let _ = set.insert(Entity::new(2));
268 let _ = set.insert(Entity::new(1)); assert_eq!(set.len(), 2);
270 }
271
272 #[test]
275 fn test_world_spawn_increments_id() {
276 let mut world = World::new();
277 let e1 = world.spawn();
278 let e2 = world.spawn();
279 let e3 = world.spawn();
280
281 assert_eq!(e1.id(), 0);
282 assert_eq!(e2.id(), 1);
283 assert_eq!(e3.id(), 2);
284 }
285
286 #[test]
287 fn test_world_entity_count() {
288 let mut world = World::new();
289 assert_eq!(world.entity_count(), 0);
290
291 let _ = world.spawn();
292 assert_eq!(world.entity_count(), 1);
293
294 let _ = world.spawn();
295 let _ = world.spawn();
296 assert_eq!(world.entity_count(), 3);
297 }
298
299 #[test]
300 fn test_world_despawn() {
301 let mut world = World::new();
302 let e1 = world.spawn();
303 let e2 = world.spawn();
304
305 assert_eq!(world.entity_count(), 2);
306 assert!(world.despawn(e1).is_ok());
307 assert_eq!(world.entity_count(), 1);
308 assert!(!world.contains(e1));
309 assert!(world.contains(e2));
310 }
311
312 #[test]
313 fn test_world_despawn_nonexistent() {
314 let mut world = World::new();
315 let fake = Entity::new(999);
316 let result = world.despawn(fake);
317 assert!(matches!(result, Err(CoreError::EntityNotFound(_))));
318 }
319
320 #[test]
321 fn test_world_contains() {
322 let mut world = World::new();
323 let e = world.spawn();
324 assert!(world.contains(e));
325 assert!(!world.contains(Entity::new(999)));
326 }
327
328 #[test]
331 fn test_add_and_get_component() {
332 let mut world = World::new();
333 let e = world.spawn();
334
335 world.add_component(e, Position::new(10.0, 20.0));
336
337 let pos = world.get_component::<Position>(e);
338 assert!(pos.is_some());
339 let pos = pos.unwrap();
340 assert!((pos.x - 10.0).abs() < f32::EPSILON);
341 assert!((pos.y - 20.0).abs() < f32::EPSILON);
342 }
343
344 #[test]
345 fn test_get_component_mut() {
346 let mut world = World::new();
347 let e = world.spawn();
348 world.add_component(e, Position::new(0.0, 0.0));
349
350 if let Some(pos) = world.get_component_mut::<Position>(e) {
351 pos.x = 100.0;
352 pos.y = 200.0;
353 }
354
355 let pos = world.get_component::<Position>(e).unwrap();
356 assert!((pos.x - 100.0).abs() < f32::EPSILON);
357 assert!((pos.y - 200.0).abs() < f32::EPSILON);
358 }
359
360 #[test]
361 fn test_has_component() {
362 let mut world = World::new();
363 let e = world.spawn();
364
365 assert!(!world.has_component::<Position>(e));
366 world.add_component(e, Position::new(0.0, 0.0));
367 assert!(world.has_component::<Position>(e));
368 assert!(!world.has_component::<Velocity>(e));
369 }
370
371 #[test]
372 fn test_remove_component() {
373 let mut world = World::new();
374 let e = world.spawn();
375 world.add_component(e, Position::new(0.0, 0.0));
376
377 assert!(world.has_component::<Position>(e));
378 assert!(world.remove_component::<Position>(e));
379 assert!(!world.has_component::<Position>(e));
380 assert!(!world.remove_component::<Position>(e)); }
382
383 #[test]
384 fn test_multiple_components() {
385 let mut world = World::new();
386 let e = world.spawn();
387
388 world.add_component(e, Position::new(1.0, 2.0));
389 world.add_component(e, Velocity::new(3.0, 4.0));
390
391 let pos = world.get_component::<Position>(e).unwrap();
392 let vel = world.get_component::<Velocity>(e).unwrap();
393
394 assert!((pos.x - 1.0).abs() < f32::EPSILON);
395 assert!((vel.x - 3.0).abs() < f32::EPSILON);
396 }
397
398 #[test]
399 fn test_despawn_removes_components() {
400 let mut world = World::new();
401 let e = world.spawn();
402 world.add_component(e, Position::new(0.0, 0.0));
403
404 world.despawn(e).unwrap();
405
406 assert!(world.get_component::<Position>(e).is_none());
408 }
409
410 #[test]
411 fn test_component_replacement() {
412 let mut world = World::new();
413 let e = world.spawn();
414
415 world.add_component(e, Position::new(1.0, 1.0));
416 world.add_component(e, Position::new(2.0, 2.0)); let pos = world.get_component::<Position>(e).unwrap();
419 assert!((pos.x - 2.0).abs() < f32::EPSILON);
420 }
421
422 #[test]
425 fn test_entities_iterator() {
426 let mut world = World::new();
427 let e1 = world.spawn();
428 let e2 = world.spawn();
429 let e3 = world.spawn();
430
431 let entities: Vec<_> = world.entities().collect();
432 assert_eq!(entities.len(), 3);
433 assert!(entities.contains(&e1));
434 assert!(entities.contains(&e2));
435 assert!(entities.contains(&e3));
436 }
437
438 #[test]
441 fn test_position_actually_moves_after_velocity_applied() {
442 let mut world = World::new();
443 let e = world.spawn();
444
445 world.add_component(e, Position::new(0.0, 0.0));
446 world.add_component(e, Velocity::new(10.0, 5.0));
447
448 let dt = 1.0;
450 let vel = *world.get_component::<Velocity>(e).unwrap();
451 if let Some(pos) = world.get_component_mut::<Position>(e) {
452 pos.x += vel.x * dt;
453 pos.y += vel.y * dt;
454 }
455
456 let pos = world.get_component::<Position>(e).unwrap();
457 assert!(
458 (pos.x - 10.0).abs() < f32::EPSILON,
459 "X should move by velocity"
460 );
461 assert!(
462 (pos.y - 5.0).abs() < f32::EPSILON,
463 "Y should move by velocity"
464 );
465 }
466}