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