1use std::collections::HashMap;
4use crate::util::OpaquePtr;
5
6mod codec;
7pub use codec::*;
8
9
10pub struct EntityType {
12 pub name: &'static str,
14 pub codecs: &'static [&'static dyn EntityCodec]
16}
17
18pub trait EntityComponent {
21 const CODEC: &'static dyn EntityCodec;
22}
23
24
25pub struct GlobalEntities {
27 name_to_entity_type: HashMap<&'static str, &'static EntityType>,
28 entity_type_to_codecs: HashMap<OpaquePtr<EntityType>, Vec<&'static dyn EntityCodec>>
29}
30
31impl GlobalEntities {
32
33 pub fn new() -> Self {
34 Self {
35 name_to_entity_type: HashMap::new(),
36 entity_type_to_codecs: HashMap::new()
37 }
38 }
39
40 pub fn with_all(slice: &[&'static EntityType]) -> Self {
42 let mut entities = Self::new();
43 entities.register_all(slice);
44 entities
45 }
46
47 pub fn register(&mut self, entity_type: &'static EntityType) {
49
50 let default_codecs = entity_type.codecs.iter()
51 .copied()
52 .collect();
53
54 self.name_to_entity_type.insert(entity_type.name, entity_type);
55 self.entity_type_to_codecs.insert(OpaquePtr::new(entity_type), default_codecs);
56
57 }
58
59 pub fn register_all(&mut self, slice: &[&'static EntityType]) {
61 self.name_to_entity_type.reserve(slice.len());
62 self.entity_type_to_codecs.reserve(slice.len());
63 for &entity_type in slice {
64 self.register(entity_type);
65 }
66 }
67
68 pub fn get_entity_type(&self, name: &str) -> Option<&'static EntityType> {
70 self.name_to_entity_type.get(name).copied()
71 }
72
73 pub fn get_codecs(&self, entity_type: &'static EntityType) -> Option<&Vec<&'static dyn EntityCodec>> {
74 self.entity_type_to_codecs.get(&OpaquePtr::new(entity_type))
75 }
76
77 pub fn get_entity_type_and_codecs(&self, name: &str) -> Option<(&'static EntityType, &Vec<&'static dyn EntityCodec>)> {
78 match self.name_to_entity_type.get(name) {
79 Some(&typ) => {
80 Some((typ, self.entity_type_to_codecs.get(&OpaquePtr::new(typ)).unwrap()))
83 },
84 None => None
85 }
86 }
87
88 pub fn has_entity_type(&self, entity_type: &'static EntityType) -> bool {
89 self.entity_type_to_codecs.contains_key(&OpaquePtr::new(entity_type))
90 }
91
92 pub fn entity_types_count(&self) -> usize {
93 self.name_to_entity_type.len()
94 }
95
96}
97
98
99#[macro_export]
100macro_rules! entities {
101 ($global_vis:vis $static_id:ident $namespace:literal [
102 $($entity_id:ident $entity_name:literal [$($component_struct:ident),*]),*
103 $(,)?
104 ]) => {
105
106 $($global_vis static $entity_id: $crate::entity::EntityType = $crate::entity::EntityType {
107 name: concat!($namespace, ':', $entity_name),
108 codecs: &[$(<$component_struct as $crate::entity::EntityComponent>::CODEC),*]
109 };)*
110
111 $global_vis static $static_id: [&'static $crate::entity::EntityType; $crate::count!($($entity_id)*)] = [
112 $(&$entity_id),*
113 ];
114
115 };
116}
117
118#[macro_export]
119macro_rules! entity_component {
120 ($struct_id:ident: default) => {
121 impl $crate::entity::EntityComponent for $struct_id {
122 const CODEC: &'static dyn $crate::entity::EntityCodec =
123 &$crate::entity::DefaultEntityCodec::<$struct_id>::new();
124 }
125 };
126 ($struct_id:ident: $codec_struct_id:ident) => {
127 impl $crate::entity::EntityComponent for $struct_id {
128 const CODEC: &'static dyn $crate::entity::EntityCodec = &$codec_struct_id;
129 }
130 };
131}