use super::entities::*;
use std::cell::{RefCell, RefMut};
trait ComponentVec {
fn as_any(&self) -> &dyn std::any::Any;
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
fn push_none(&mut self);
}
impl<C: 'static + Clone> ComponentVec for RefCell<Vec<Option<RefCell<C>>>> {
fn as_any(&self) -> &dyn std::any::Any {
self as &dyn std::any::Any
}
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self as &mut dyn std::any::Any
}
fn push_none(&mut self) {
self.get_mut().push(None)
}
}
#[derive(Default)]
pub struct World {
count: usize,
component_vectors: Vec<Box<dyn ComponentVec>>,
}
impl World {
pub fn new() -> Self {
Self {
count: 0,
component_vectors: Vec::new(),
}
}
pub fn spawn(&mut self) -> EntityId {
let entity_id = self.count;
for component_vector in self.component_vectors.iter_mut() {
component_vector.push_none();
}
self.count += 1;
entity_id
}
pub fn add_to<C: 'static + Clone>(
&mut self,
entity: EntityId,
component: C,
) -> Result<ComponentAddSuccess, ComponentAddError> {
for component_vector in self.component_vectors.iter_mut() {
if let Some(component_vector) = component_vector
.as_any_mut()
.downcast_mut::<RefCell<Vec<Option<RefCell<C>>>>>()
{
let slot = &mut component_vector.borrow_mut()[entity];
if slot.is_some() {
return Err(ComponentAddError::ComponentExistsOnEntity);
}
*slot = Some(RefCell::new(component));
return Ok(ComponentAddSuccess::ExistingType);
}
}
let mut new_component_vec = Vec::with_capacity(self.count);
for _ in 0..self.count {
new_component_vec.push(None);
}
new_component_vec[entity] = Some(RefCell::new(component));
self.component_vectors
.push(Box::new(RefCell::new(new_component_vec)));
Ok(ComponentAddSuccess::NewType)
}
pub fn set_for<C: 'static>(
&mut self,
entity: EntityId,
component: C,
) -> Result<(), ComponentSetError> {
for component_vector in self.component_vectors.iter_mut() {
if let Some(vec) = component_vector
.as_any_mut()
.downcast_mut::<RefCell<Vec<Option<RefCell<C>>>>>()
{
let slot = &mut vec.borrow_mut()[entity];
if let Some(old_component) = slot {
*old_component.borrow_mut() = component;
return Ok(());
}
}
}
Err(ComponentSetError::ComponentDoesNotExistOnEntity)
}
fn borrow_component_vec_mut<C: 'static>(&self) -> Option<RefMut<Vec<Option<RefCell<C>>>>> {
for component_vector in self.component_vectors.iter() {
if let Some(component_vector) = component_vector
.as_any()
.downcast_ref::<RefCell<Vec<Option<RefCell<C>>>>>()
{
return Some(component_vector.borrow_mut());
}
}
None
}
pub fn get<C: 'static + Clone>(&self, entity_id: EntityId) -> Option<C> {
Some(
self.borrow_component_vec_mut::<C>().unwrap()[entity_id]
.as_ref()?
.borrow()
.clone()
)
}
pub fn query<C: 'static>(&self) -> Result<Vec<EntityId>, QueryError> {
if let Some(component_vector) = self.borrow_component_vec_mut::<C>() {
let numbers: Vec<EntityId> = (0..component_vector.len()).collect();
let filtered = numbers
.iter()
.filter(|i| component_vector[**i].is_some())
.copied()
.collect::<Vec<_>>();
return Ok(filtered);
}
Err(QueryError::WorldDoesNotContainType)
}
}
#[derive(Debug)]
pub enum GetComponentError {
WorldDoesNotContainType,
EntityDoesNotContainComponent,
}
#[derive(Debug)]
pub enum QueryError {
WorldDoesNotContainType,
}
#[cfg(test)]
mod tests {
use crate::world::*;
#[test]
fn spawn() {
let mut w = World::new();
let e = w.spawn();
let f = w.spawn();
assert_eq!(e, 0);
assert_eq!(f, 1);
}
}