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(crate) entity: OnceCell<Box<dyn Any>>,
158 pub(crate) property_store: OnceCell<Box<dyn Any>>,
160}
161
162impl EntityRecord {
163 pub(crate) fn new() -> Self {
164 Self {
165 entity_count: 0,
166 entity: OnceCell::new(),
167 property_store: OnceCell::new(),
168 }
169 }
170}
171
172pub struct EntityStore {
174 items: Vec<EntityRecord>,
175}
176
177impl Default for EntityStore {
178 fn default() -> Self {
179 EntityStore::new()
180 }
181}
182
183impl EntityStore {
184 #[must_use]
192 pub fn new() -> Self {
193 let num_items = get_registered_entity_count();
194 Self {
195 items: (0..num_items).map(|_| EntityRecord::new()).collect(),
196 }
197 }
198
199 #[must_use]
202 pub fn get<E: Entity>(&self) -> &E {
203 let index = E::id();
204 self.items
205 .get(index)
206 .unwrap_or_else(|| panic!("No registered entity found with index = {index:?}. You must use the `define_entity!` macro to create an entity."))
207 .entity
208 .get_or_init(|| E::new_boxed())
209 .downcast_ref::<E>()
210 .expect("TypeID does not match registered entity type. You must use the `define_entity!` macro to create an entity.")
211 }
212
213 #[must_use]
216 pub fn get_mut<E: Entity>(&mut self) -> &mut E {
217 let index = E::id();
218
219 let record = self.items.get_mut(index).unwrap_or_else(|| {
220 panic!(
221 "No registered entity found with index = {index:?}. \
222 You must use the `define_entity!` macro to create an entity."
223 )
224 });
225
226 if record.entity.get().is_none() {
228 record.entity.set(E::new_boxed()).unwrap();
229 }
230
231 record.entity.get_mut().unwrap().downcast_mut::<E>().expect(
233 "TypeID does not match registered entity type. \
234 You must use the `define_entity!` macro to create an entity.",
235 )
236 }
237
238 pub(crate) fn new_entity_id<E: Entity>(&mut self) -> EntityId<E> {
241 let index = E::id();
242 let record = &mut self.items[index];
243 let id = record.entity_count;
244 record.entity_count += 1;
245 EntityId::new(id)
246 }
247
248 #[must_use]
250 pub fn get_entity_count<E: Entity>(&self) -> usize {
251 let index = E::id();
252 let record = &self.items[index];
253 record.entity_count
254 }
255
256 #[must_use]
258 pub fn get_entity_count_by_id(&self, id: usize) -> usize {
259 let record = &self.items[id];
260 record.entity_count
261 }
262
263 #[must_use]
265 pub fn get_entity_iterator<E: Entity>(&self) -> PopulationIterator<E> {
266 let count = self.get_entity_count::<E>();
267 PopulationIterator::new(count)
268 }
269
270 #[must_use]
271 pub fn get_property_store<E: Entity>(&self) -> &PropertyStore<E> {
272 let index = E::id();
273 let record = self.items
274 .get(index)
275 .unwrap_or_else(|| panic!("No registered entity found with index = {index:?}. You must use the `define_entity!` macro to create an entity."));
276 let property_store = record
277 .property_store
278 .get_or_init(|| Box::new(PropertyStore::<E>::new()));
279 property_store.downcast_ref::<PropertyStore<E>>()
280 .expect("TypeID does not match registered item type. You must use the `define_registered_item!` macro to create a registered item.")
281 }
282
283 pub fn get_property_store_mut<E: Entity>(&mut self) -> &mut PropertyStore<E> {
284 let index = E::id();
285 let record = self.items
286 .get_mut(index)
287 .unwrap_or_else(|| panic!("No registered entity found with index = {index:?}. You must use the `define_entity!` macro to create an entity."));
288 let _ = record
289 .property_store
290 .get_or_init(|| Box::new(PropertyStore::<E>::new()));
291 let property_store = record.property_store.get_mut().unwrap();
292 property_store.downcast_mut::<PropertyStore<E>>()
293 .expect("TypeID does not match registered item type. You must use the `define_registered_item!` macro to create a registered item.")
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use std::any::Any;
300 use std::sync::atomic::{AtomicUsize, Ordering};
301 use std::sync::{Arc, Barrier};
302 use std::thread;
303
304 use crate::entity::entity_store::{
305 add_to_entity_registry, get_registered_entity_count, initialize_entity_index, EntityStore,
306 };
307 use crate::entity::Entity;
308 use crate::{impl_entity, with, Context, ContextEntitiesExt, HashMap};
309 #[derive(Debug, Clone, PartialEq)]
311 pub struct TestItem1 {
312 value: usize,
313 }
314 impl Default for TestItem1 {
315 fn default() -> Self {
316 Self { value: 42 }
317 }
318 }
319
320 #[derive(Debug, Clone, PartialEq)]
321 pub struct TestItem2 {
322 name: String,
323 }
324 impl Default for TestItem2 {
325 fn default() -> Self {
326 TestItem2 {
327 name: "test".to_string(),
328 }
329 }
330 }
331
332 #[derive(Debug, Clone, PartialEq)]
333 pub struct TestItem3 {
334 data: Vec<u8>,
335 }
336 impl Default for TestItem3 {
337 fn default() -> Self {
338 TestItem3 {
339 data: vec![1, 2, 3],
340 }
341 }
342 }
343
344 impl_entity!(TestItem1);
346 impl_entity!(TestItem2);
347 impl_entity!(TestItem3);
348
349 #[test]
360 fn test_initialize_item_index_concurrent() {
361 let initial_registered_items_count = get_registered_entity_count();
363
364 const NUM_THREADS: usize = 100;
365 let index = Arc::new(AtomicUsize::new(usize::MAX));
366 let barrier = Arc::new(Barrier::new(NUM_THREADS));
367
368 let handles: Vec<_> = (0..NUM_THREADS)
369 .map(|_| {
370 let index_clone = Arc::clone(&index);
371 let barrier_clone = Arc::clone(&barrier);
372
373 thread::spawn(move || {
374 barrier_clone.wait();
376 initialize_entity_index(&index_clone)
378 })
379 })
380 .collect();
381
382 let results: Vec<usize> = handles.into_iter().map(|h| h.join().unwrap()).collect();
383
384 let first = results[0];
385
386 assert_ne!(first, usize::MAX);
388 assert!(results.iter().all(|&r| r == first));
390 assert_eq!(first, initial_registered_items_count);
392
393 let initial_registered_items_count = get_registered_entity_count();
401
402 const NUM_ENTITIES: usize = 5;
404 let entities: Vec<_> = (0..NUM_ENTITIES)
405 .map(|_| Arc::new(AtomicUsize::new(usize::MAX)))
406 .collect();
407
408 let mut handles = vec![];
409
410 for entity in entities.iter() {
412 let entity_clone = Arc::clone(entity);
413 let handle = thread::spawn(move || initialize_entity_index(&entity_clone));
414 handles.push(handle);
415 }
416
417 let mut results = vec![];
419 for handle in handles {
420 results.push(handle.join().unwrap());
421 }
422
423 results.sort();
425 for (i, &result) in results.iter().enumerate() {
426 assert_eq!(
427 result,
428 i + initial_registered_items_count,
429 "Entity should have index {}, got {}",
430 i,
431 result
432 );
433 }
434
435 let initial_registered_items_count = get_registered_entity_count();
440
441 let entity1 = Arc::new(AtomicUsize::new(usize::MAX));
443 let entity2 = Arc::new(AtomicUsize::new(usize::MAX));
444 let entity3 = Arc::new(AtomicUsize::new(usize::MAX));
445
446 let mut handles = vec![];
447
448 for _ in 0..5 {
450 let e1 = Arc::clone(&entity1);
451 handles.push(thread::spawn(move || initialize_entity_index(&e1)));
452
453 let e2 = Arc::clone(&entity2);
454 handles.push(thread::spawn(move || initialize_entity_index(&e2)));
455
456 let e3 = Arc::clone(&entity3);
457 handles.push(thread::spawn(move || initialize_entity_index(&e3)));
458 }
459
460 let results: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
462
463 let mut counts = HashMap::default();
465 for &result in &results {
466 *counts.entry(result).or_insert(0) += 1;
467 }
468
469 assert_eq!(counts.len(), 3, "Should have 3 unique indices");
471
472 for (&idx, &count) in &counts {
474 assert_eq!(
475 count, 5,
476 "Index {} should appear 5 times, appeared {} times",
477 idx, count
478 );
479 }
480
481 assert_eq!(
483 get_registered_entity_count() - initial_registered_items_count,
484 3
485 );
486
487 let indices: Vec<_> = vec![
489 entity1.load(Ordering::Acquire),
490 entity2.load(Ordering::Acquire),
491 entity3.load(Ordering::Acquire),
492 ];
493
494 let mut sorted_indices = indices.clone();
495 sorted_indices.sort_unstable();
496 let expected_indices = vec![
499 initial_registered_items_count,
500 1 + initial_registered_items_count,
501 2 + initial_registered_items_count,
502 ];
503 assert_eq!(sorted_indices, expected_indices);
504 }
505
506 #[test]
508 fn test_add_to_registry_idempotent() {
509 let index1 = TestItem1::id();
510 let index2 = TestItem2::id();
511 let index3 = TestItem3::id();
512
513 assert_ne!(index1, usize::MAX);
515 assert_ne!(index2, usize::MAX);
516 assert_ne!(index3, usize::MAX);
517
518 assert_ne!(index1, index2);
520 assert_ne!(index2, index3);
521 assert_ne!(index1, index3);
522
523 add_to_entity_registry::<TestItem1>();
525 add_to_entity_registry::<TestItem1>();
526 add_to_entity_registry::<TestItem1>();
527
528 let index_from_registry_1 = TestItem1::id();
529 let index_from_registry_2 = TestItem2::id();
530 let index_from_registry_3 = TestItem3::id();
531
532 assert_eq!(index1, index_from_registry_1);
533 assert_eq!(index2, index_from_registry_2);
534 assert_eq!(index3, index_from_registry_3);
535 }
536
537 #[test]
539 fn test_registered_items_get() {
540 {
542 let mut items = EntityStore::new();
543
544 let item1 = items.get_mut::<TestItem1>();
545 assert_eq!(item1.value, 42);
546 assert_eq!(TestItem1::name(), "TestItem1");
547
548 let item2 = items.get_mut::<TestItem2>();
549 assert_eq!(item2.name, "test");
550
551 let item3 = items.get_mut::<TestItem3>();
552 assert_eq!(item3.data, vec![1, 2, 3]);
553 }
554
555 {
557 let items = EntityStore::new();
558
559 let item1 = items.get::<TestItem1>();
560 assert_eq!(item1.value, 42);
561 assert_eq!(TestItem1::name(), "TestItem1");
562
563 let item2 = items.get::<TestItem2>();
564 assert_eq!(item2.name, "test");
565
566 let item3 = items.get::<TestItem3>();
567 assert_eq!(item3.data, vec![1, 2, 3]);
568 }
569 }
570
571 #[test]
573 fn test_registered_items_get_cached() {
574 {
576 let items = EntityStore::new();
577
578 let item1_ref1 = items.get::<TestItem1>();
580 let item1_ref2 = items.get::<TestItem1>();
581
582 assert!(std::ptr::eq(item1_ref1, item1_ref2));
584 }
585
586 {
588 let mut items = EntityStore::new();
589
590 let item1_ptr1: *mut TestItem1 = items.get_mut::<TestItem1>();
592 let item1_ptr2: *mut TestItem1 = items.get_mut::<TestItem1>();
593
594 assert!(std::ptr::eq(item1_ptr1, item1_ptr2));
596 }
597 }
598
599 #[test]
600 fn test_registered_items_get_mut() {
601 let mut items = EntityStore::new();
602
603 let item = items.get_mut::<TestItem1>();
605 assert_eq!(item.value, 42);
606 item.value = 100;
607
608 let item = items.get::<TestItem1>();
610 assert_eq!(item.value, 100);
611 }
612
613 #[test]
614 fn test_registered_items_multiple_items_mutated() {
615 let mut items = EntityStore::new();
616
617 let item1 = items.get_mut::<TestItem1>();
619 assert_eq!(item1.value, 42);
620 item1.value = 10;
621
622 let item2 = items.get_mut::<TestItem2>();
623 assert_eq!(item2.name, "test");
624 item2.name = "modified".to_string();
625
626 let item3 = items.get_mut::<TestItem3>();
627 assert_eq!(item3.data, vec![1, 2, 3]);
628 item3.data = vec![9, 8, 7];
629
630 assert_eq!(items.get::<TestItem1>().value, 10);
632 assert_eq!(items.get::<TestItem2>().name, "modified");
633 assert_eq!(items.get::<TestItem3>().data, vec![9, 8, 7]);
634 }
635
636 #[test]
637 #[should_panic(expected = "No registered entity found with index")]
638 fn test_registered_items_invalid_index() {
639 #[derive(Debug, Default)]
640 struct UnregisteredEntity;
641
642 impl Entity for UnregisteredEntity {
644 fn name() -> &'static str
645 where
646 Self: Sized,
647 {
648 "UnregisteredItem"
649 }
650
651 fn id() -> usize
652 where
653 Self: Sized,
654 {
655 87000 }
657
658 fn as_any(&self) -> &dyn Any {
659 self
660 }
661 fn as_any_mut(&mut self) -> &mut dyn Any {
662 self
663 }
664 }
665
666 let items = EntityStore::new();
668
669 let _ = items.get::<UnregisteredEntity>();
671 }
672
673 #[test]
674 fn test_registered_item_trait_name() {
675 assert_eq!(TestItem1::name(), "TestItem1");
676 assert_eq!(TestItem2::name(), "TestItem2");
677 assert_eq!(TestItem3::name(), "TestItem3");
678 }
679
680 #[test]
681 fn test_registered_item_new_boxed() {
682 let boxed1 = TestItem1::new_boxed();
683 assert_eq!(boxed1.value, 42);
684
685 let boxed2 = TestItem2::new_boxed();
686 assert_eq!(boxed2.name, "test");
687
688 let boxed3 = TestItem3::new_boxed();
689 assert_eq!(boxed3.data, vec![1, 2, 3]);
690 }
691
692 #[test]
693 fn test_box_dyn_registered_item_type_alias() {
694 let item = TestItem1::new_boxed();
695 assert_eq!(
696 (item as Box<dyn Any>)
697 .downcast_ref::<TestItem1>()
698 .unwrap()
699 .value,
700 42
701 );
702 }
703
704 #[test]
705 fn test_entity_iterator() {
706 let mut context = Context::new();
707
708 for _ in 0..5 {
711 context
712 .add_entity::<TestItem1, _>(with!(TestItem1))
713 .unwrap();
714 }
715 for _ in 0..3 {
716 context
717 .add_entity::<TestItem2, _>(with!(TestItem2))
718 .unwrap();
719 }
720 assert_eq!(context.get_entity_count::<TestItem1>(), 5);
724 assert_eq!(context.get_entity_count::<TestItem2>(), 3);
725 assert_eq!(context.get_entity_count::<TestItem3>(), 0);
726
727 let iter1 = context.get_entity_iterator::<TestItem1>();
729 let results1: Vec<_> = iter1.collect();
730 assert_eq!(results1.len(), 5);
731 for (i, id) in results1.into_iter().enumerate() {
733 assert_eq!(id.0, i);
734 }
735
736 let iter2 = context.get_entity_iterator::<TestItem2>();
737 assert_eq!(iter2.count(), 3);
738
739 let mut iter3 = context.get_entity_iterator::<TestItem3>();
740 assert!(iter3.next().is_none());
741
742 let snapshot_iter = context.get_entity_iterator::<TestItem1>();
745
746 context
747 .add_entity::<TestItem1, _>(with!(TestItem1))
748 .unwrap();
749
750 assert_eq!(context.get_entity_count::<TestItem1>(), 6);
751 assert_eq!(snapshot_iter.count(), 5); assert_eq!(context.get_entity_iterator::<TestItem1>().count(), 6); }
754}