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 #[must_use]
221 pub fn component_type_count(&self) -> usize {
222 self.components.len()
223 }
224
225 #[must_use]
227 #[doc(hidden)]
228 pub fn component_type_count_internal(&self) -> usize {
229 self.components.len()
230 }
231
232 #[must_use]
236 pub fn entity_component_count_internal(&self, entity: Entity) -> usize {
237 self.components
238 .values()
239 .filter(|storage| storage.contains(entity))
240 .count()
241 }
242}
243
244impl fmt::Debug for World {
245 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246 f.debug_struct("World")
247 .field("entity_count", &self.entities.len())
248 .field("component_types", &self.components.len())
249 .finish_non_exhaustive()
250 }
251}
252
253#[cfg(test)]
254#[allow(
255 clippy::unwrap_used,
256 clippy::expect_used,
257 clippy::let_underscore_must_use
258)]
259mod tests {
260 use super::*;
261 use crate::components::{Position, Velocity};
262
263 #[test]
266 fn test_entity_creation() {
267 let e = Entity::new(42);
268 assert_eq!(e.id(), 42);
269 }
270
271 #[test]
272 fn test_entity_display() {
273 let e = Entity::new(123);
274 assert_eq!(format!("{e}"), "e123");
275 }
276
277 #[test]
278 fn test_entity_debug() {
279 let e = Entity::new(456);
280 assert_eq!(format!("{e:?}"), "Entity(456)");
281 }
282
283 #[test]
284 fn test_entity_equality() {
285 let e1 = Entity::new(1);
286 let e2 = Entity::new(1);
287 let e3 = Entity::new(2);
288 assert_eq!(e1, e2);
289 assert_ne!(e1, e3);
290 }
291
292 #[test]
293 fn test_entity_hash() {
294 use std::collections::HashSet;
295 let mut set = HashSet::new();
296 let _ = set.insert(Entity::new(1));
297 let _ = set.insert(Entity::new(2));
298 let _ = set.insert(Entity::new(1)); assert_eq!(set.len(), 2);
300 }
301
302 #[test]
305 fn test_world_spawn_increments_id() {
306 let mut world = World::new();
307 let e1 = world.spawn();
308 let e2 = world.spawn();
309 let e3 = world.spawn();
310
311 assert_eq!(e1.id(), 0);
312 assert_eq!(e2.id(), 1);
313 assert_eq!(e3.id(), 2);
314 }
315
316 #[test]
317 fn test_world_entity_count() {
318 let mut world = World::new();
319 assert_eq!(world.entity_count(), 0);
320
321 let _ = world.spawn();
322 assert_eq!(world.entity_count(), 1);
323
324 let _ = world.spawn();
325 let _ = world.spawn();
326 assert_eq!(world.entity_count(), 3);
327 }
328
329 #[test]
330 fn test_world_despawn() {
331 let mut world = World::new();
332 let e1 = world.spawn();
333 let e2 = world.spawn();
334
335 assert_eq!(world.entity_count(), 2);
336 assert!(world.despawn(e1).is_ok());
337 assert_eq!(world.entity_count(), 1);
338 assert!(!world.contains(e1));
339 assert!(world.contains(e2));
340 }
341
342 #[test]
343 fn test_world_despawn_nonexistent() {
344 let mut world = World::new();
345 let fake = Entity::new(999);
346 let result = world.despawn(fake);
347 assert!(matches!(result, Err(CoreError::EntityNotFound(_))));
348 }
349
350 #[test]
351 fn test_world_contains() {
352 let mut world = World::new();
353 let e = world.spawn();
354 assert!(world.contains(e));
355 assert!(!world.contains(Entity::new(999)));
356 }
357
358 #[test]
361 fn test_add_and_get_component() {
362 let mut world = World::new();
363 let e = world.spawn();
364
365 world.add_component(e, Position::new(10.0, 20.0));
366
367 let pos = world.get_component::<Position>(e);
368 assert!(pos.is_some());
369 let pos = pos.unwrap();
370 assert!((pos.x - 10.0).abs() < f32::EPSILON);
371 assert!((pos.y - 20.0).abs() < f32::EPSILON);
372 }
373
374 #[test]
375 fn test_get_component_mut() {
376 let mut world = World::new();
377 let e = world.spawn();
378 world.add_component(e, Position::new(0.0, 0.0));
379
380 if let Some(pos) = world.get_component_mut::<Position>(e) {
381 pos.x = 100.0;
382 pos.y = 200.0;
383 }
384
385 let pos = world.get_component::<Position>(e).unwrap();
386 assert!((pos.x - 100.0).abs() < f32::EPSILON);
387 assert!((pos.y - 200.0).abs() < f32::EPSILON);
388 }
389
390 #[test]
391 fn test_has_component() {
392 let mut world = World::new();
393 let e = world.spawn();
394
395 assert!(!world.has_component::<Position>(e));
396 world.add_component(e, Position::new(0.0, 0.0));
397 assert!(world.has_component::<Position>(e));
398 assert!(!world.has_component::<Velocity>(e));
399 }
400
401 #[test]
402 fn test_remove_component() {
403 let mut world = World::new();
404 let e = world.spawn();
405 world.add_component(e, Position::new(0.0, 0.0));
406
407 assert!(world.has_component::<Position>(e));
408 assert!(world.remove_component::<Position>(e));
409 assert!(!world.has_component::<Position>(e));
410 assert!(!world.remove_component::<Position>(e)); }
412
413 #[test]
414 fn test_multiple_components() {
415 let mut world = World::new();
416 let e = world.spawn();
417
418 world.add_component(e, Position::new(1.0, 2.0));
419 world.add_component(e, Velocity::new(3.0, 4.0));
420
421 let pos = world.get_component::<Position>(e).unwrap();
422 let vel = world.get_component::<Velocity>(e).unwrap();
423
424 assert!((pos.x - 1.0).abs() < f32::EPSILON);
425 assert!((vel.x - 3.0).abs() < f32::EPSILON);
426 }
427
428 #[test]
429 fn test_despawn_removes_components() {
430 let mut world = World::new();
431 let e = world.spawn();
432 world.add_component(e, Position::new(0.0, 0.0));
433
434 world.despawn(e).unwrap();
435
436 assert!(world.get_component::<Position>(e).is_none());
438 }
439
440 #[test]
441 fn test_component_replacement() {
442 let mut world = World::new();
443 let e = world.spawn();
444
445 world.add_component(e, Position::new(1.0, 1.0));
446 world.add_component(e, Position::new(2.0, 2.0)); let pos = world.get_component::<Position>(e).unwrap();
449 assert!((pos.x - 2.0).abs() < f32::EPSILON);
450 }
451
452 #[test]
455 fn test_entities_iterator() {
456 let mut world = World::new();
457 let e1 = world.spawn();
458 let e2 = world.spawn();
459 let e3 = world.spawn();
460
461 let entities: Vec<_> = world.entities().collect();
462 assert_eq!(entities.len(), 3);
463 assert!(entities.contains(&e1));
464 assert!(entities.contains(&e2));
465 assert!(entities.contains(&e3));
466 }
467
468 #[test]
471 fn test_position_actually_moves_after_velocity_applied() {
472 let mut world = World::new();
473 let e = world.spawn();
474
475 world.add_component(e, Position::new(0.0, 0.0));
476 world.add_component(e, Velocity::new(10.0, 5.0));
477
478 let dt = 1.0;
480 let vel = *world.get_component::<Velocity>(e).unwrap();
481 if let Some(pos) = world.get_component_mut::<Position>(e) {
482 pos.x += vel.x * dt;
483 pos.y += vel.y * dt;
484 }
485
486 let pos = world.get_component::<Position>(e).unwrap();
487 assert!(
488 (pos.x - 10.0).abs() < f32::EPSILON,
489 "X should move by velocity"
490 );
491 assert!(
492 (pos.y - 5.0).abs() < f32::EPSILON,
493 "Y should move by velocity"
494 );
495 }
496}