1use std::any::{Any, TypeId};
15use std::cell::OnceCell;
16use std::sync::atomic::{AtomicUsize, Ordering};
17use std::sync::{LazyLock, Mutex, OnceLock};
18
19use crate::entity::property_store::PropertyStore;
20use crate::entity::{Entity, EntityId, PopulationIterator};
21use crate::HashMap;
22
23static NEXT_ENTITY_INDEX: Mutex<usize> = Mutex::new(0);
26
27#[allow(clippy::type_complexity)]
32static ENTITY_METADATA_BUILDER: LazyLock<Mutex<HashMap<TypeId, (Vec<TypeId>, Vec<TypeId>)>>> =
33 LazyLock::new(|| Mutex::new(HashMap::default()));
34
35#[allow(clippy::type_complexity)]
40static ENTITY_METADATA: OnceLock<HashMap<TypeId, (Box<[TypeId]>, Box<[TypeId]>)>> = OnceLock::new();
41
42#[allow(clippy::type_complexity)]
44fn entity_metadata() -> &'static HashMap<TypeId, (Box<[TypeId]>, Box<[TypeId]>)> {
45 ENTITY_METADATA.get_or_init(|| {
46 let mut builder = ENTITY_METADATA_BUILDER.lock().unwrap();
47 let builder = std::mem::take(&mut *builder);
48 builder
49 .into_iter()
50 .map(|(entity_type_id, (props, reqs))| {
51 (
52 entity_type_id,
53 (props.into_boxed_slice(), reqs.into_boxed_slice()),
54 )
55 })
56 .collect()
57 })
58}
59
60pub fn register_property_with_entity(
62 entity_type_id: TypeId,
63 property_type_id: TypeId,
64 required: bool,
65) {
66 let mut builder = ENTITY_METADATA_BUILDER.lock().unwrap();
67 if ENTITY_METADATA.get().is_some() {
68 panic!(
69 "`register_property_with_entity()` called after entity metadata was frozen; registration must occur during startup/ctors."
70 );
71 }
72
73 let (property_type_ids, required_property_type_ids) = builder
74 .entry(entity_type_id)
75 .or_insert_with(|| (Vec::new(), Vec::new()));
76 property_type_ids.push(property_type_id);
77 if required {
78 required_property_type_ids.push(property_type_id);
79 }
80}
81
82#[must_use]
87pub fn get_entity_metadata_static(
88 entity_type_id: TypeId,
89) -> (&'static [TypeId], &'static [TypeId]) {
90 match entity_metadata().get(&entity_type_id) {
91 Some((props, reqs)) => (props.as_ref(), reqs.as_ref()),
92 None => (&[], &[]),
93 }
94}
95
96pub fn add_to_entity_registry<R: Entity>() {
106 let _ = R::id();
107}
108
109pub fn get_registered_entity_count() -> usize {
111 *NEXT_ENTITY_INDEX.lock().unwrap()
112}
113
114pub fn initialize_entity_index(plugin_index: &AtomicUsize) -> usize {
127 let mut guard = NEXT_ENTITY_INDEX.lock().unwrap();
129 let candidate = *guard;
130
131 match plugin_index.compare_exchange(usize::MAX, candidate, Ordering::AcqRel, Ordering::Acquire)
138 {
139 Ok(_) => {
140 *guard += 1;
142 candidate
143 }
144 Err(existing) => {
145 existing
148 }
149 }
150}
151
152pub struct EntityRecord {
154 pub(crate) entity_count: usize,
156 pub(in crate::entity) entity_created_event_subscribed: bool,
159 pub(crate) entity: OnceCell<Box<dyn Any>>,
161 pub(crate) property_store: OnceCell<Box<dyn Any>>,
163}
164
165impl EntityRecord {
166 pub(crate) fn new() -> Self {
167 Self {
168 entity_count: 0,
169 entity_created_event_subscribed: false,
170 entity: OnceCell::new(),
171 property_store: OnceCell::new(),
172 }
173 }
174}
175
176pub struct EntityStore {
178 pub(in crate::entity) items: Vec<EntityRecord>,
179}
180
181impl Default for EntityStore {
182 fn default() -> Self {
183 EntityStore::new()
184 }
185}
186
187impl EntityStore {
188 #[must_use]
196 pub fn new() -> Self {
197 let num_items = get_registered_entity_count();
198 Self {
199 items: (0..num_items).map(|_| EntityRecord::new()).collect(),
200 }
201 }
202
203 #[must_use]
206 pub fn get<E: Entity>(&self) -> &E {
207 let index = E::id();
208 self.items
209 .get(index)
210 .unwrap_or_else(|| panic!("No registered entity found with index = {index:?}. You must use the `define_entity!` macro to create an entity."))
211 .entity
212 .get_or_init(|| E::new_boxed())
213 .downcast_ref::<E>()
214 .expect("TypeID does not match registered entity type. You must use the `define_entity!` macro to create an entity.")
215 }
216
217 #[must_use]
220 pub fn get_mut<E: Entity>(&mut self) -> &mut E {
221 let index = E::id();
222
223 let record = self.items.get_mut(index).unwrap_or_else(|| {
224 panic!(
225 "No registered entity found with index = {index:?}. \
226 You must use the `define_entity!` macro to create an entity."
227 )
228 });
229
230 if record.entity.get().is_none() {
232 record.entity.set(E::new_boxed()).unwrap();
233 }
234
235 record.entity.get_mut().unwrap().downcast_mut::<E>().expect(
237 "TypeID does not match registered entity type. \
238 You must use the `define_entity!` macro to create an entity.",
239 )
240 }
241
242 pub(crate) fn new_entity_id<E: Entity>(&mut self) -> (EntityId<E>, bool) {
246 let index = E::id();
247 let record = &mut self.items[index];
248 let id = record.entity_count;
249 record.entity_count += 1;
250 (EntityId::new(id), record.entity_created_event_subscribed)
251 }
252
253 #[must_use]
255 pub fn get_entity_count<E: Entity>(&self) -> usize {
256 let index = E::id();
257 let record = &self.items[index];
258 record.entity_count
259 }
260
261 #[must_use]
263 pub fn get_entity_count_by_id(&self, id: usize) -> usize {
264 let record = &self.items[id];
265 record.entity_count
266 }
267
268 #[must_use]
270 pub fn get_entity_iterator<E: Entity>(&self) -> PopulationIterator<E> {
271 let count = self.get_entity_count::<E>();
272 PopulationIterator::new(count)
273 }
274
275 #[must_use]
276 #[inline]
277 pub fn get_property_store<E: Entity>(&self) -> &PropertyStore<E> {
278 let index = E::id();
279 let record = self.items
280 .get(index)
281 .unwrap_or_else(|| panic!("No registered entity found with index = {index:?}. You must use the `define_entity!` macro to create an entity."));
282 let property_store = record
283 .property_store
284 .get_or_init(|| Box::new(PropertyStore::<E>::new()));
285 property_store.downcast_ref::<PropertyStore<E>>()
286 .expect("TypeID does not match registered item type. You must use the `define_registered_item!` macro to create a registered item.")
287 }
288
289 pub fn get_property_store_mut<E: Entity>(&mut self) -> &mut PropertyStore<E> {
290 let index = E::id();
291 let record = self.items
292 .get_mut(index)
293 .unwrap_or_else(|| panic!("No registered entity found with index = {index:?}. You must use the `define_entity!` macro to create an entity."));
294 let _ = record
295 .property_store
296 .get_or_init(|| Box::new(PropertyStore::<E>::new()));
297 let property_store = record.property_store.get_mut().unwrap();
299 property_store.downcast_mut::<PropertyStore<E>>()
300 .expect("TypeID does not match registered item type. You must use the `define_registered_item!` macro to create a registered item.")
301 }
302}
303
304#[cfg(test)]
305mod tests {
306 use std::any::Any;
307 use std::sync::atomic::{AtomicUsize, Ordering};
308 use std::sync::{Arc, Barrier};
309 use std::thread;
310
311 use crate::entity::entity_store::{
312 add_to_entity_registry, get_registered_entity_count, initialize_entity_index, EntityStore,
313 };
314 use crate::entity::Entity;
315 use crate::{impl_entity, with, Context, ContextEntitiesExt, HashMap};
316 #[derive(Debug, Clone, PartialEq)]
318 pub struct TestItem1 {
319 value: usize,
320 }
321 impl Default for TestItem1 {
322 fn default() -> Self {
323 Self { value: 42 }
324 }
325 }
326
327 #[derive(Debug, Clone, PartialEq)]
328 pub struct TestItem2 {
329 name: String,
330 }
331 impl Default for TestItem2 {
332 fn default() -> Self {
333 TestItem2 {
334 name: "test".to_string(),
335 }
336 }
337 }
338
339 #[derive(Debug, Clone, PartialEq)]
340 pub struct TestItem3 {
341 data: Vec<u8>,
342 }
343 impl Default for TestItem3 {
344 fn default() -> Self {
345 TestItem3 {
346 data: vec![1, 2, 3],
347 }
348 }
349 }
350
351 impl_entity!(TestItem1);
353 impl_entity!(TestItem2);
354 impl_entity!(TestItem3);
355
356 #[test]
367 fn test_initialize_item_index_concurrent() {
368 let initial_registered_items_count = get_registered_entity_count();
370
371 const NUM_THREADS: usize = 100;
372 let index = Arc::new(AtomicUsize::new(usize::MAX));
373 let barrier = Arc::new(Barrier::new(NUM_THREADS));
374
375 let handles: Vec<_> = (0..NUM_THREADS)
376 .map(|_| {
377 let index_clone = Arc::clone(&index);
378 let barrier_clone = Arc::clone(&barrier);
379
380 thread::spawn(move || {
381 barrier_clone.wait();
383 initialize_entity_index(&index_clone)
385 })
386 })
387 .collect();
388
389 let results: Vec<usize> = handles.into_iter().map(|h| h.join().unwrap()).collect();
390
391 let first = results[0];
392
393 assert_ne!(first, usize::MAX);
395 assert!(results.iter().all(|&r| r == first));
397 assert_eq!(first, initial_registered_items_count);
399
400 let initial_registered_items_count = get_registered_entity_count();
408
409 const NUM_ENTITIES: usize = 5;
411 let entities: Vec<_> = (0..NUM_ENTITIES)
412 .map(|_| Arc::new(AtomicUsize::new(usize::MAX)))
413 .collect();
414
415 let mut handles = vec![];
416
417 for entity in entities.iter() {
419 let entity_clone = Arc::clone(entity);
420 let handle = thread::spawn(move || initialize_entity_index(&entity_clone));
421 handles.push(handle);
422 }
423
424 let mut results = vec![];
426 for handle in handles {
427 results.push(handle.join().unwrap());
428 }
429
430 results.sort();
432 for (i, &result) in results.iter().enumerate() {
433 assert_eq!(
434 result,
435 i + initial_registered_items_count,
436 "Entity should have index {}, got {}",
437 i,
438 result
439 );
440 }
441
442 let initial_registered_items_count = get_registered_entity_count();
447
448 let entity1 = Arc::new(AtomicUsize::new(usize::MAX));
450 let entity2 = Arc::new(AtomicUsize::new(usize::MAX));
451 let entity3 = Arc::new(AtomicUsize::new(usize::MAX));
452
453 let mut handles = vec![];
454
455 for _ in 0..5 {
457 let e1 = Arc::clone(&entity1);
458 handles.push(thread::spawn(move || initialize_entity_index(&e1)));
459
460 let e2 = Arc::clone(&entity2);
461 handles.push(thread::spawn(move || initialize_entity_index(&e2)));
462
463 let e3 = Arc::clone(&entity3);
464 handles.push(thread::spawn(move || initialize_entity_index(&e3)));
465 }
466
467 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
469
470 let mut counts = HashMap::default();
472 for &result in &results {
473 *counts.entry(result).or_insert(0) += 1;
474 }
475
476 assert_eq!(counts.len(), 3, "Should have 3 unique indices");
478
479 for (&idx, &count) in &counts {
481 assert_eq!(
482 count, 5,
483 "Index {} should appear 5 times, appeared {} times",
484 idx, count
485 );
486 }
487
488 assert_eq!(
490 get_registered_entity_count() - initial_registered_items_count,
491 3
492 );
493
494 let indices: Vec<_> = vec![
496 entity1.load(Ordering::Acquire),
497 entity2.load(Ordering::Acquire),
498 entity3.load(Ordering::Acquire),
499 ];
500
501 let mut sorted_indices = indices.clone();
502 sorted_indices.sort_unstable();
503 let expected_indices = vec![
506 initial_registered_items_count,
507 1 + initial_registered_items_count,
508 2 + initial_registered_items_count,
509 ];
510 assert_eq!(sorted_indices, expected_indices);
511 }
512
513 #[test]
515 fn test_add_to_registry_idempotent() {
516 let index1 = TestItem1::id();
517 let index2 = TestItem2::id();
518 let index3 = TestItem3::id();
519
520 assert_ne!(index1, usize::MAX);
522 assert_ne!(index2, usize::MAX);
523 assert_ne!(index3, usize::MAX);
524
525 assert_ne!(index1, index2);
527 assert_ne!(index2, index3);
528 assert_ne!(index1, index3);
529
530 add_to_entity_registry::<TestItem1>();
532 add_to_entity_registry::<TestItem1>();
533 add_to_entity_registry::<TestItem1>();
534
535 let index_from_registry_1 = TestItem1::id();
536 let index_from_registry_2 = TestItem2::id();
537 let index_from_registry_3 = TestItem3::id();
538
539 assert_eq!(index1, index_from_registry_1);
540 assert_eq!(index2, index_from_registry_2);
541 assert_eq!(index3, index_from_registry_3);
542 }
543
544 #[test]
546 fn test_registered_items_get() {
547 {
549 let mut items = EntityStore::new();
550
551 let item1 = items.get_mut::<TestItem1>();
552 assert_eq!(item1.value, 42);
553 assert_eq!(TestItem1::name(), "TestItem1");
554
555 let item2 = items.get_mut::<TestItem2>();
556 assert_eq!(item2.name, "test");
557
558 let item3 = items.get_mut::<TestItem3>();
559 assert_eq!(item3.data, vec![1, 2, 3]);
560 }
561
562 {
564 let items = EntityStore::new();
565
566 let item1 = items.get::<TestItem1>();
567 assert_eq!(item1.value, 42);
568 assert_eq!(TestItem1::name(), "TestItem1");
569
570 let item2 = items.get::<TestItem2>();
571 assert_eq!(item2.name, "test");
572
573 let item3 = items.get::<TestItem3>();
574 assert_eq!(item3.data, vec![1, 2, 3]);
575 }
576 }
577
578 #[test]
580 fn test_registered_items_get_cached() {
581 {
583 let items = EntityStore::new();
584
585 let item1_ref1 = items.get::<TestItem1>();
587 let item1_ref2 = items.get::<TestItem1>();
588
589 assert!(std::ptr::eq(item1_ref1, item1_ref2));
591 }
592
593 {
595 let mut items = EntityStore::new();
596
597 let item1_ptr1: *mut TestItem1 = items.get_mut::<TestItem1>();
599 let item1_ptr2: *mut TestItem1 = items.get_mut::<TestItem1>();
600
601 assert!(std::ptr::eq(item1_ptr1, item1_ptr2));
603 }
604 }
605
606 #[test]
607 fn test_registered_items_get_mut() {
608 let mut items = EntityStore::new();
609
610 let item = items.get_mut::<TestItem1>();
612 assert_eq!(item.value, 42);
613 item.value = 100;
614
615 let item = items.get::<TestItem1>();
617 assert_eq!(item.value, 100);
618 }
619
620 #[test]
621 fn test_registered_items_multiple_items_mutated() {
622 let mut items = EntityStore::new();
623
624 let item1 = items.get_mut::<TestItem1>();
626 assert_eq!(item1.value, 42);
627 item1.value = 10;
628
629 let item2 = items.get_mut::<TestItem2>();
630 assert_eq!(item2.name, "test");
631 item2.name = "modified".to_string();
632
633 let item3 = items.get_mut::<TestItem3>();
634 assert_eq!(item3.data, vec![1, 2, 3]);
635 item3.data = vec![9, 8, 7];
636
637 assert_eq!(items.get::<TestItem1>().value, 10);
639 assert_eq!(items.get::<TestItem2>().name, "modified");
640 assert_eq!(items.get::<TestItem3>().data, vec![9, 8, 7]);
641 }
642
643 #[test]
644 #[should_panic(expected = "No registered entity found with index")]
645 fn test_registered_items_invalid_index() {
646 #[derive(Debug, Default)]
647 struct UnregisteredEntity;
648
649 impl Entity for UnregisteredEntity {
651 fn name() -> &'static str
652 where
653 Self: Sized,
654 {
655 "UnregisteredItem"
656 }
657
658 fn id() -> usize
659 where
660 Self: Sized,
661 {
662 87000 }
664
665 fn as_any(&self) -> &dyn Any {
666 self
667 }
668 fn as_any_mut(&mut self) -> &mut dyn Any {
669 self
670 }
671 }
672
673 let items = EntityStore::new();
675
676 let _ = items.get::<UnregisteredEntity>();
678 }
679
680 #[test]
681 fn test_registered_item_trait_name() {
682 assert_eq!(TestItem1::name(), "TestItem1");
683 assert_eq!(TestItem2::name(), "TestItem2");
684 assert_eq!(TestItem3::name(), "TestItem3");
685 }
686
687 #[test]
688 fn test_registered_item_new_boxed() {
689 let boxed1 = TestItem1::new_boxed();
690 assert_eq!(boxed1.value, 42);
691
692 let boxed2 = TestItem2::new_boxed();
693 assert_eq!(boxed2.name, "test");
694
695 let boxed3 = TestItem3::new_boxed();
696 assert_eq!(boxed3.data, vec![1, 2, 3]);
697 }
698
699 #[test]
700 fn test_box_dyn_registered_item_type_alias() {
701 let item = TestItem1::new_boxed();
702 assert_eq!(
703 (item as Box<dyn Any>)
704 .downcast_ref::<TestItem1>()
705 .unwrap()
706 .value,
707 42
708 );
709 }
710
711 #[test]
712 fn test_entity_iterator() {
713 let mut context = Context::new();
714
715 for _ in 0..5 {
718 context
719 .add_entity::<TestItem1, _>(with!(TestItem1))
720 .unwrap();
721 }
722 for _ in 0..3 {
723 context
724 .add_entity::<TestItem2, _>(with!(TestItem2))
725 .unwrap();
726 }
727 assert_eq!(context.get_entity_count::<TestItem1>(), 5);
731 assert_eq!(context.get_entity_count::<TestItem2>(), 3);
732 assert_eq!(context.get_entity_count::<TestItem3>(), 0);
733
734 let iter1 = context.get_entity_iterator::<TestItem1>();
736 let results1: Vec<_> = iter1.collect();
737 assert_eq!(results1.len(), 5);
738 for (i, id) in results1.into_iter().enumerate() {
740 assert_eq!(id.0, i);
741 }
742
743 let iter2 = context.get_entity_iterator::<TestItem2>();
744 assert_eq!(iter2.count(), 3);
745
746 let mut iter3 = context.get_entity_iterator::<TestItem3>();
747 assert!(iter3.next().is_none());
748
749 let snapshot_iter = context.get_entity_iterator::<TestItem1>();
752
753 context
754 .add_entity::<TestItem1, _>(with!(TestItem1))
755 .unwrap();
756
757 assert_eq!(context.get_entity_count::<TestItem1>(), 6);
758 assert_eq!(snapshot_iter.count(), 5); assert_eq!(context.get_entity_iterator::<TestItem1>().count(), 6); }
761}