use std::any::{Any, TypeId}; use crate::{world::{Entity, ArchetypeEntityId}, bundle::Bundle, component::Component}; pub trait ComponentColumn: Any { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; fn new_empty_column(&self) -> Box; fn is_same_type(&self, column: &dyn ComponentColumn) -> bool; fn len(&self) -> usize; fn append(&mut self, column: &mut dyn ComponentColumn); fn component_type_id(&self) -> TypeId; // used for debugging fn component_type_name(&self) -> String; } impl ComponentColumn for Vec { fn as_any(&self) -> &dyn Any { self } fn as_any_mut(&mut self) -> &mut dyn Any { self } fn new_empty_column(&self) -> Box { Box::new(Vec::::new()) } fn is_same_type(&self, column: &dyn ComponentColumn) -> bool { column.as_any().downcast_ref::().is_some() } fn len(&self) -> usize { Vec::len(self) } fn append(&mut self, column: &mut dyn ComponentColumn) { let column: &mut Self = column.as_any_mut().downcast_mut() .expect("Attempt at appending an different column type!"); self.append(column); } fn component_type_id(&self) -> TypeId { self.first().unwrap().type_id() } fn component_type_name(&self) -> String { //self.first().unwrap().type_id() std::any::type_name::().to_string() } } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct ArchetypeId(pub u64); impl ArchetypeId { /// Increments the id and returns a new id with the value it was before incrementing. pub(crate) fn increment(&mut self) -> Self { let v = self.0; self.0 += 1; ArchetypeId(v) } } pub struct Archetype { pub(crate) id: ArchetypeId, entities: Vec, pub(crate) columns: Vec>, } impl Archetype { /// Create a new archetype from another archetype and add a column pub fn new_archetype_add(new_id: ArchetypeId, archetype: &Archetype) -> Archetype { let mut columns: Vec<_> = archetype .columns .iter() .map(|c| c.new_empty_column()) .collect(); assert!(columns .iter() .find(|column| column.as_any().is::>()) .is_none()); columns.push(Box::new(Vec::::new())); Archetype { id: new_id, entities: Vec::new(), columns, } } /// Create a new archetype from another archetype and remove a column pub fn new_archetype_remove(new_id: ArchetypeId, archetype: &Archetype) -> Archetype { let mut columns: Vec<_> = archetype .columns .iter() .map(|c| c.new_empty_column()) .collect(); let idx = columns .iter() .position(|column| column.as_any().is::>()) .unwrap(); columns.remove(idx); Archetype { id: new_id, entities: Vec::new(), columns, } } pub fn from_columns(new_id: ArchetypeId, columns: Vec>) -> Archetype { Archetype { id: new_id, entities: Vec::new(), columns, } } pub fn get_component_mut(&mut self, entity: ArchetypeEntityId) -> Option<&mut T> { for col in self.columns.iter_mut() { if col.as_any().is::>() { let components: &mut Vec = col.as_any_mut().downcast_mut().unwrap(); return components.get_mut(entity.0 as usize); } } None } pub fn get_component(&self, entity: ArchetypeEntityId) -> Option<&T> { for col in self.columns.iter() { if col.as_ref().as_any().is::>() { let components: &Vec = col.as_any().downcast_ref().unwrap(); return components.get(entity.0 as usize); } } None } pub fn get_component_column(&self) -> Option<&Vec> { let col = self.columns.iter().find(|c| c.as_any().is::>())?; col.as_any().downcast_ref() } pub(crate) fn add_entity(&mut self, components: Vec>) -> ArchetypeEntityId { let mut created_entity: Option = None; for mut component in components.into_iter() { for col in self.columns.iter_mut() { if col.is_same_type(component.as_ref()) { match created_entity { Some(e) => { assert!(e.0 == col.len() as u64); }, None => { created_entity = Some(ArchetypeEntityId(col.len() as u64)); } } col.append(component.as_mut()); } } } created_entity.expect("Failure to create entity!") } /// returns a boolean indicating whether this archetype can store the TypeIds given pub(crate) fn is_archetype_for(&self, types: Vec) -> bool { let types_iter = types.into_iter(); self.columns .iter() .map(|c| c.component_type_id()) .eq(types_iter) } }