use core::any::{Any, TypeId};
use std::collections::HashMap;
use super::{Component, ComponentBox, ComponentStore, Entity, SharedComponentBox};
use crate::error::NotFound;
#[derive(Default)]
pub struct TypeComponentBuilder {
components: HashMap<TypeId, Box<dyn Any>>,
shared: HashMap<TypeId, Entity>,
}
impl TypeComponentBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with<C: Component>(mut self, component: C) -> Self {
self.components
.insert(TypeId::of::<C>(), Box::new(component));
self
}
pub fn with_shared<C: Component>(mut self, source: Entity) -> Self {
self.shared.insert(TypeId::of::<C>(), source);
self
}
pub fn with_shared_box(mut self, source: SharedComponentBox) -> Self {
self.shared.insert(source.type_id, source.source);
self
}
pub fn with_box(mut self, component_box: ComponentBox) -> Self {
let (type_id, component) = component_box.consume();
self.components.insert(type_id, component);
self
}
pub fn build(self) -> (HashMap<TypeId, Box<dyn Any>>, HashMap<TypeId, Entity>) {
(self.components, self.shared)
}
}
#[derive(Default, Debug)]
pub struct TypeComponentStore {
components: HashMap<(Entity, TypeId), Box<dyn Any>>,
shared: HashMap<(Entity, TypeId), Entity>,
}
impl ComponentStore for TypeComponentStore {
type Components = (HashMap<TypeId, Box<dyn Any>>, HashMap<TypeId, Entity>);
fn append(&mut self, entity: Entity, components: Self::Components) {
for (key, value) in components.0 {
self.components.insert((entity, key), value);
}
for (key, value) in components.1 {
self.shared.insert((entity, key), value);
}
}
fn remove_entity(&mut self, entity: impl Into<Entity>) {
let entity = entity.into();
let keys: Vec<(Entity, TypeId)> = self
.components
.iter()
.filter(|&(k, _)| k.0 == entity)
.map(|(k, _)| *k)
.collect();
for k in keys {
self.components.remove(&k);
}
let keys: Vec<(Entity, TypeId)> = self
.shared
.iter()
.filter(|&(k, _)| k.0 == entity)
.map(|(k, _)| *k)
.collect();
for k in keys {
self.shared.remove(&k);
}
}
fn print_entity(&self, entity: impl Into<Entity>) {
let entity = entity.into();
let _blub = self
.components
.iter()
.filter(|(k, _)| k.0 == entity)
.map(|(_, _)| println!("blub"));
}
}
impl TypeComponentStore {
pub fn register<C: Component>(&mut self, entity: Entity, component: C) {
self.components
.insert((entity, TypeId::of::<C>()), Box::new(component));
}
pub fn register_shared<C: Component>(&mut self, target: Entity, source: Entity) {
let target_key = (target, TypeId::of::<C>());
self.components.remove(&target_key);
self.shared.insert(target_key, source);
}
pub fn register_shared_box(&mut self, target: impl Into<Entity>, source: SharedComponentBox) {
let target_key = (target.into(), source.type_id);
self.components.remove(&target_key);
self.shared.insert(target_key, source.source);
}
pub fn register_box(&mut self, entity: impl Into<Entity>, component_box: ComponentBox) {
let entity = entity.into();
let (type_id, component) = component_box.consume();
self.components.insert((entity, type_id), component);
}
pub fn len(&self) -> usize {
self.components.len()
}
pub fn is_empty(&self) -> bool {
self.components.is_empty()
}
pub fn contains_entity(&self, entity: Entity) -> bool {
self.components.iter().any(|(k, _)| k.0 == entity)
}
pub fn is_origin<C: Component>(&self, entity: Entity) -> bool {
self.components.contains_key(&(entity, TypeId::of::<C>()))
}
fn source_from_shared<C: Component>(&self, entity: Entity) -> Result<Entity, NotFound> {
self.shared
.get(&(entity, TypeId::of::<C>()))
.ok_or_else(|| NotFound::Entity(entity))
.map(|s| *s)
}
fn source<C: Component>(&self, entity: Entity) -> Result<Entity, NotFound> {
if !self.components.contains_key(&(entity, TypeId::of::<C>())) {
return self.source_from_shared::<C>(entity);
}
Result::Ok(entity)
}
pub fn get<C: Component>(&self, entity: Entity) -> Result<&C, NotFound> {
let source = self.source::<C>(entity);
match source {
Ok(entity) => self
.components
.get(&(entity, TypeId::of::<C>()))
.ok_or_else(|| NotFound::Entity(entity))
.map(|component| {
component
.downcast_ref()
.expect("EntityComponentManager.get: internal downcast error")
}),
Err(_) => Result::Err(NotFound::Entity(entity)),
}
}
pub fn get_mut<C: Component>(&mut self, entity: Entity) -> Result<&mut C, NotFound> {
let source = self.source::<C>(entity);
match source {
Ok(entity) => self
.components
.get_mut(&(entity, TypeId::of::<C>()))
.ok_or_else(|| NotFound::Entity(entity))
.map(|component| {
component
.downcast_mut()
.expect("EntityComponentManager.get_mut: internal downcast error")
}),
Err(_) => Result::Err(NotFound::Entity(entity)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::any::TypeId;
#[test]
fn builder_with() {
let builder = TypeComponentBuilder::new();
let component = String::from("Test");
let (map, _) = builder.with(component).build();
assert!(map.contains_key(&TypeId::of::<String>()));
}
#[test]
fn builder_with_shared() {
let builder = TypeComponentBuilder::new();
let source = Entity::from(1);
let (_, map) = builder.with_shared::<String>(source).build();
assert!(map.contains_key(&TypeId::of::<String>()));
assert_eq!(*map.get(&TypeId::of::<String>()).unwrap(), source);
}
#[test]
fn builder_with_shared_box() {
let builder = TypeComponentBuilder::new();
let source = Entity::from(1);
let (_, map) = builder
.with_shared_box(SharedComponentBox::new(TypeId::of::<String>(), source))
.build();
assert!(map.contains_key(&TypeId::of::<String>()));
}
#[test]
fn builder_with_box() {
let builder = TypeComponentBuilder::new();
let component = String::from("Test");
let (map, _) = builder.with_box(ComponentBox::new(component)).build();
assert!(map.contains_key(&TypeId::of::<String>()));
}
#[test]
fn remove_entity() {
let mut store = TypeComponentStore::default();
let entity = Entity::from(1);
store.register(entity, String::from("Test"));
store.remove_entity(entity);
assert!(!store.contains_entity(entity));
}
#[test]
fn register() {
let mut store = TypeComponentStore::default();
let entity = Entity::from(1);
let component = String::from("Test");
store.register(entity, component);
assert!(store.get::<String>(entity).is_ok());
}
#[test]
fn len() {
let mut store = TypeComponentStore::default();
let entity = Entity::from(1);
store.register(entity, String::from("Test"));
store.register(entity, 5 as f64);
assert_eq!(store.len(), 2);
}
#[test]
fn register_shared() {
let mut store = TypeComponentStore::default();
let entity = Entity::from(1);
let target = Entity::from(2);
let component = String::from("Test");
store.register(entity, component);
store.register_shared::<String>(target, entity);
assert!(store.get::<String>(entity).is_ok());
assert!(store.get::<String>(target).is_ok());
assert!(store.is_origin::<String>(entity));
assert!(!store.is_origin::<String>(target));
}
#[test]
fn register_box() {
let mut store = TypeComponentStore::default();
let entity = Entity::from(1);
let component = String::from("Test");
store.register_box(entity, ComponentBox::new(component));
assert!(store.get::<String>(entity).is_ok());
}
#[test]
fn register_shared_box() {
let mut store = TypeComponentStore::default();
let entity = Entity::from(1);
let target = Entity::from(2);
let component = String::from("Test");
store.register(entity, component);
store.register_shared_box(
target,
SharedComponentBox::new(TypeId::of::<String>(), entity),
);
assert!(store.get::<String>(entity).is_ok());
assert!(store.get::<String>(target).is_ok());
assert!(store.is_origin::<String>(entity));
assert!(!store.is_origin::<String>(target));
}
}