use std::collections::HashMap;
use crate::util::OpaquePtr;
mod codec;
pub use codec::*;
pub struct EntityType {
pub name: &'static str,
pub codecs: &'static [&'static dyn EntityCodec]
}
pub trait EntityComponent {
const CODEC: &'static dyn EntityCodec;
}
pub struct GlobalEntities {
name_to_entity_type: HashMap<&'static str, &'static EntityType>,
entity_type_to_codecs: HashMap<OpaquePtr<EntityType>, Vec<&'static dyn EntityCodec>>
}
impl GlobalEntities {
pub fn new() -> Self {
Self {
name_to_entity_type: HashMap::new(),
entity_type_to_codecs: HashMap::new()
}
}
pub fn with_all(slice: &[&'static EntityType]) -> Self {
let mut entities = Self::new();
entities.register_all(slice);
entities
}
pub fn register(&mut self, entity_type: &'static EntityType) {
let default_codecs = entity_type.codecs.iter()
.copied()
.collect();
self.name_to_entity_type.insert(entity_type.name, entity_type);
self.entity_type_to_codecs.insert(OpaquePtr::new(entity_type), default_codecs);
}
pub fn register_all(&mut self, slice: &[&'static EntityType]) {
self.name_to_entity_type.reserve(slice.len());
self.entity_type_to_codecs.reserve(slice.len());
for &entity_type in slice {
self.register(entity_type);
}
}
pub fn get_entity_type(&self, name: &str) -> Option<&'static EntityType> {
self.name_to_entity_type.get(name).copied()
}
pub fn get_codecs(&self, entity_type: &'static EntityType) -> Option<&Vec<&'static dyn EntityCodec>> {
self.entity_type_to_codecs.get(&OpaquePtr::new(entity_type))
}
pub fn get_entity_type_and_codecs(&self, name: &str) -> Option<(&'static EntityType, &Vec<&'static dyn EntityCodec>)> {
match self.name_to_entity_type.get(name) {
Some(&typ) => {
Some((typ, self.entity_type_to_codecs.get(&OpaquePtr::new(typ)).unwrap()))
},
None => None
}
}
pub fn has_entity_type(&self, entity_type: &'static EntityType) -> bool {
self.entity_type_to_codecs.contains_key(&OpaquePtr::new(entity_type))
}
pub fn entity_types_count(&self) -> usize {
self.name_to_entity_type.len()
}
}
#[macro_export]
macro_rules! entities {
($global_vis:vis $static_id:ident $namespace:literal [
$($entity_id:ident $entity_name:literal [$($component_struct:ident),*]),*
$(,)?
]) => {
$($global_vis static $entity_id: $crate::entity::EntityType = $crate::entity::EntityType {
name: concat!($namespace, ':', $entity_name),
codecs: &[$(<$component_struct as $crate::entity::EntityComponent>::CODEC),*]
};)*
$global_vis static $static_id: [&'static $crate::entity::EntityType; $crate::count!($($entity_id)*)] = [
$(&$entity_id),*
];
};
}
#[macro_export]
macro_rules! entity_component {
($struct_id:ident: default) => {
impl $crate::entity::EntityComponent for $struct_id {
const CODEC: &'static dyn $crate::entity::EntityCodec =
&$crate::entity::DefaultEntityCodec::<$struct_id>::new();
}
};
($struct_id:ident: $codec_struct_id:ident) => {
impl $crate::entity::EntityComponent for $struct_id {
const CODEC: &'static dyn $crate::entity::EntityCodec = &$codec_struct_id;
}
};
}