use std::{
any::{Any, TypeId},
cell::RefCell,
collections::HashMap,
};
use crate::error::NotFound;
#[cfg(test)]
mod tests;
pub type Entity = u32;
pub trait Component: Any {}
impl<T: Any> Component for T {}
pub struct ComponentBox {
component: Box<dyn Any>,
type_id: TypeId,
}
pub struct SharedComponentBox {
source: Entity,
type_id: TypeId,
}
impl SharedComponentBox {
pub fn new(type_id: TypeId, source: Entity) -> Self {
SharedComponentBox {
source,
type_id,
}
}
pub fn consume(self) -> (TypeId, Entity) {
(self.type_id, self.source)
}
}
impl ComponentBox {
pub fn new<C: Component>(component: C) -> Self {
ComponentBox {
component: Box::new(component),
type_id: TypeId::of::<C>(),
}
}
pub fn consume(self) -> (TypeId, Box<dyn Any>) {
(self.type_id, self.component)
}
}
pub struct EntityBuilder<'a, T>
where
T: EntityContainer,
{
pub entity: Entity,
pub entity_component_manager: &'a mut EntityComponentManager,
pub entity_container: &'a mut T,
}
impl<'a, T> EntityBuilder<'a, T>
where
T: EntityContainer,
{
pub fn with<C: Component>(self, component: C) -> Self {
self.entity_component_manager
.register_component(self.entity, component);
self
}
pub fn with_shared<C: Component>(self, source: Entity) -> Self {
self.entity_component_manager
.register_shared_component::<C>(self.entity, source);
self
}
pub fn with_shared_box(self, source: SharedComponentBox) -> Self {
self.entity_component_manager
.register_shared_component_box(self.entity, source);
self
}
pub fn with_box(self, component_box: ComponentBox) -> Self {
self.entity_component_manager
.register_component_box(self.entity, component_box);
self
}
pub fn build(self) -> Entity {
self.entity_container.register_entity(self.entity);
self.entity
}
}
#[derive(Default)]
pub struct EntityComponentManager {
pub entities: HashMap<Entity, HashMap<TypeId, Box<dyn Any>>>,
pub shared: HashMap<Entity, RefCell<HashMap<TypeId, Entity>>>,
}
impl EntityComponentManager {
pub fn new() -> Self {
Default::default()
}
pub fn register_entity(&mut self, entity: Entity) {
self.entities.insert(entity, HashMap::new());
}
pub fn remove_entity(&mut self, entity: Entity) {
self.entities.remove(&entity);
}
pub fn register_component<C: Component>(&mut self, entity: Entity, component: C) {
self.entities
.get_mut(&entity)
.get_or_insert(&mut HashMap::new())
.insert(TypeId::of::<C>(), Box::new(component));
}
pub fn register_shared_component<C: Component>(&mut self, target: Entity, source: Entity) {
if !self.shared.contains_key(&target) {
self.shared.insert(target, RefCell::new(HashMap::new()));
}
self.shared[&target]
.borrow_mut()
.insert(TypeId::of::<C>(), source);
}
pub fn register_shared_component_box(&mut self, target: Entity, source: SharedComponentBox) {
if !self.shared.contains_key(&target) {
self.shared.insert(target, RefCell::new(HashMap::new()));
}
self.shared[&target]
.borrow_mut()
.insert(source.type_id, source.source);
}
pub fn register_component_box(&mut self, entity: Entity, component_box: ComponentBox) {
let (type_id, component) = component_box.consume();
self.entities
.get_mut(&entity)
.get_or_insert(&mut HashMap::new())
.insert(type_id, component);
}
fn target_entity_from_shared<C: Component>(&self, entity: Entity) -> Result<Entity, NotFound> {
self.shared
.get(&entity)
.ok_or_else(|| NotFound::Entity(entity))
.and_then(|en| {
en.borrow()
.get(&TypeId::of::<C>())
.map(|entity| *entity)
.ok_or_else(|| NotFound::Component(TypeId::of::<C>()))
})
}
fn target_entity<C: Component>(&self, entity: Entity) -> Result<Entity, NotFound> {
if !self.entities.contains_key(&entity)
|| !self.entities[&entity].contains_key(&TypeId::of::<C>())
{
return self.target_entity_from_shared::<C>(entity);
}
Result::Ok(entity)
}
pub fn borrow_component<C: Component>(&self, entity: Entity) -> Result<&C, NotFound> {
let target_entity = self.target_entity::<C>(entity);
match target_entity {
Ok(entity) => self
.entities
.get(&entity)
.ok_or_else(|| NotFound::Entity(entity))
.and_then(|en| {
en.get(&TypeId::of::<C>())
.map(|component| {
component.downcast_ref().expect(
"EntityComponentManager.borrow_component: internal downcast error",
)
})
.ok_or_else(|| NotFound::Component(TypeId::of::<C>()))
}),
Err(_) => Result::Err(NotFound::Entity(entity)),
}
}
pub fn borrow_mut_component<C: Component>(
&mut self,
entity: Entity,
) -> Result<&mut C, NotFound> {
let target_entity = self.target_entity::<C>(entity);
match target_entity {
Ok(entity) => self
.entities
.get_mut(&entity)
.ok_or_else(|| NotFound::Entity(entity))
.and_then(|en| {
en.get_mut(&TypeId::of::<C>())
.map(|component| {
component.downcast_mut().expect(
"EntityComponentManager.borrow_mut_component: internal downcast error",
)
})
.ok_or_else(|| NotFound::Component(TypeId::of::<C>()))
}),
Err(_) => Result::Err(NotFound::Entity(entity)),
}
}
}
pub trait EntityContainer {
fn register_entity(&mut self, entity: Entity);
fn remove_entity(&mut self, entity: Entity);
}
#[derive(Default)]
pub struct VecEntityContainer {
pub inner: Vec<Entity>,
}
impl EntityContainer for VecEntityContainer {
fn register_entity(&mut self, entity: Entity) {
self.inner.push(entity);
}
fn remove_entity(&mut self, entity: Entity) {
self.inner
.iter()
.position(|&n| n == entity)
.map(|e| self.inner.remove(e));
}
}