use std::any::{Any, TypeId};
use std::cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut};
use std::collections::hash_map::{Iter, IterMut};
use std::collections::HashMap;
pub const EMPTY: u32 = 0;
pub struct PartMap {
map: HashMap<u32, Box<Any>>,
}
impl PartMap {
fn new(init_size: usize) -> PartMap {
PartMap {
map: HashMap::with_capacity(init_size),
}
}
fn insert<T: 'static>(&mut self, id: u32, part: T) {
self.map.insert(id, Box::new(part));
}
fn remove(&mut self, id: u32) {
self.map.remove(&id);
}
pub fn get_part_ref<T: 'static>(&self, id: u32) -> Result<&T, &'static str> {
if let Some(part) = self.map.get(&id) {
let part = part.downcast_ref::<T>().ok_or("Downcast failed for type")?;
return Ok(part);
}
Err("could find requested entity part")
}
pub fn get_part_mut<T: 'static>(&mut self, id: u32) -> Result<&mut T, &'static str> {
if let Some(part) = self.map.get_mut(&id) {
let part = part.downcast_mut::<T>().ok_or("Downcast failed for type")?;
return Ok(part);
}
Err("could find requested entity part")
}
pub fn iter_ref(&self) -> Iter<u32, Box<Any>> {
return self.map.iter();
}
pub fn iter_mut(&mut self) -> IterMut<u32, Box<Any>> {
return self.map.iter_mut();
}
}
pub struct Entities {
entity_masks: Vec<u32>,
parts: HashMap<u32, RefCell<PartMap>>,
next_free_entity: u32,
type_masks: HashMap<TypeId, u32>,
next_typemask: u32,
}
impl Default for Entities {
fn default() -> Self {
Entities::new(None, None)
}
}
impl Entities {
pub fn new(entity_count: Option<usize>, part_count: Option<usize>) -> Entities {
Entities {
entity_masks: vec![EMPTY; entity_count.unwrap_or(0)],
parts: HashMap::with_capacity(part_count.unwrap_or(0)),
next_free_entity: 0,
type_masks: HashMap::with_capacity(part_count.unwrap_or(0)),
next_typemask: 1,
}
}
pub fn get_free_slot(&mut self) -> Result<u32, &'static str> {
if self.next_free_entity >= self.entity_masks.len() as u32 {
self.entity_masks.push(EMPTY);
}
for index in 0..=self.next_free_entity {
if self.entity_masks[index as usize] == EMPTY {
if index >= self.next_free_entity {
self.next_free_entity += 1;
}
return Ok(index);
}
}
Err("no free entity slots")
}
pub fn get_entity_mask(&self, id: u32) -> u32 {
self.entity_masks[id as usize]
}
pub fn get_type_mask<T: 'static>(&self) -> Result<u32, &'static str> {
if let Some(mask) = self.type_masks.get(&TypeId::of::<T>()) {
return Ok(*mask);
}
Err("requested non-existant mask for type")
}
pub fn entity_contains<T: 'static>(&self, id: u32) -> bool {
if let Some(entity_mask) = self.entity_masks.get(id as usize) {
if let Some(type_mask) = self.type_masks.get(&TypeId::of::<T>()) {
if entity_mask & type_mask == *type_mask {
return true;
}
}
}
false
}
pub fn add_part<T>(&mut self, id: u32, part: T)
where
T: Any, {
let tid = TypeId::of::<T>();
if !self.type_masks.contains_key(&tid) {
self.type_masks.insert(tid, self.next_typemask);
let mask = self.next_typemask << 1;
self.next_typemask = mask;
}
let type_mask = self.type_masks[&tid];
self.parts
.entry(type_mask)
.or_insert(RefCell::new(PartMap::new(self.entity_masks.len())));
if let Some(col) = self.parts.get_mut(&type_mask) {
col.borrow_mut().insert(id, part);
let old = self.entity_masks[id as usize];
self.entity_masks[id as usize] = old | type_mask;
}
}
pub fn rm_part<T: 'static>(&mut self, id: u32) -> bool {
let type_mask = self.type_masks[&TypeId::of::<T>()];
if let Some(map) = self.parts.get_mut(&type_mask) {
map.borrow_mut().remove(id);
self.entity_masks[id as usize] ^= type_mask;
return true;
}
false
}
pub fn rm_entity(&mut self, id: u32) {
for (_, part_map) in &mut self.parts {
part_map.borrow_mut().remove(id);
}
self.entity_masks[id as usize] = EMPTY;
}
pub fn get_pmap_ref<T>(&self) -> Result<Option<Ref<PartMap>>, BorrowError>
where
T: 'static, {
if let Some(type_mask) = self.type_masks.get(&TypeId::of::<T>()) {
if let Some(partmap) = self.parts.get(&type_mask) {
let partmap = partmap.try_borrow()?;
return Ok(Some(partmap));
}
}
Ok(None)
}
pub fn get_pmap_mut<T>(&self) -> Result<Option<RefMut<PartMap>>, BorrowMutError>
where
T: 'static, {
if let Some(type_mask) = self.type_masks.get(&TypeId::of::<T>()) {
if let Some(partmap) = self.parts.get(&type_mask) {
let partmap = partmap.try_borrow_mut()?;
return Ok(Some(partmap));
}
}
Ok(None)
}
}
#[cfg(test)]
mod tests {
use crate::Entities;
#[test]
fn add_entity_and_part_check_contains_and_mask() {
struct Test1 {}
struct Test2 {}
struct Test3 {}
let mut entities = Entities::new(Some(3), Some(3));
let entity_1 = entities.get_free_slot().unwrap();
assert_eq!(entity_1, 0);
entities.add_part(entity_1, Test1 {});
let entity_1_mask = entities.get_entity_mask(entity_1);
let type_mask = entities.get_type_mask::<Test1>().unwrap();
assert_eq!(entity_1_mask, type_mask);
assert!(entities.entity_contains::<Test1>(entity_1));
assert!(!entities.entity_contains::<Test2>(entity_1));
entities.add_part(entity_1, Test3 {});
assert!(entities.entity_contains::<Test3>(entity_1));
let e2 = entities.get_free_slot().unwrap();
assert_eq!(e2, 1);
}
#[test]
fn get_part_map_for_type_as_ref() {
struct Test1 {}
let mut entities = Entities::new(Some(3), Some(3));
{
let m = entities.get_pmap_ref::<Test1>();
assert_eq!(m.unwrap().is_none(), true);
}
let entity_1 = entities.get_free_slot().unwrap();
entities.add_part(entity_1, Test1 {});
let map = entities.get_pmap_ref::<Test1>();
assert_eq!(map.unwrap().is_some(), true);
let map = entities.get_pmap_ref::<Test1>();
let map = map.unwrap().unwrap();
assert!(map.get_part_ref::<Test1>(entity_1).is_ok());
}
#[test]
fn get_part_map_for_type_as_mut() {
struct Test1 {}
let mut entities = Entities::new(Some(3), Some(3));
{
let m = entities.get_pmap_mut::<Test1>();
assert_eq!(m.unwrap().is_none(), true);
}
let entity_1 = entities.get_free_slot().unwrap();
entities.add_part(entity_1, Test1 {});
let map = entities.get_pmap_mut::<Test1>();
assert_eq!(map.unwrap().is_some(), true);
let map = entities.get_pmap_mut::<Test1>();
let mut map = map.unwrap().unwrap();
assert!(map.get_part_mut::<Test1>(entity_1).is_ok());
}
#[test]
fn partmap_ref_and_mut_diff_parts_and_modify() {
#[derive(Debug, PartialEq)]
struct Test1 {
x: u32,
}
#[derive(Debug, PartialEq)]
struct Test2 {
x: u32,
}
let mut entities = Entities::new(Some(3), Some(3));
let entity_1 = entities.get_free_slot().unwrap();
entities.add_part(entity_1, Test1 { x: 66 });
entities.add_part(entity_1, Test2 { x: 42 });
let partmap = entities.get_pmap_ref::<Test1>().unwrap().unwrap();
let part = partmap.get_part_ref::<Test1>(entity_1).unwrap();
assert_eq!(part, &Test1 { x: 66 });
assert!(entities.entity_contains::<Test1>(entity_1));
let mut partmap = entities.get_pmap_mut::<Test2>().unwrap().unwrap();
let part = partmap.get_part_mut::<Test2>(entity_1).unwrap();
assert_eq!(part.x, 42);
part.x = 666;
assert_ne!(part.x, 42);
}
#[test]
fn partmap_iter_ref() {
struct Test1 {
x: u32,
}
let mut entities = Entities::new(Some(3), Some(3));
let mut ids = Vec::new();
let id = entities.get_free_slot().unwrap();
entities.add_part(id, Test1 { x: id });
ids.push(id);
let id = entities.get_free_slot().unwrap();
entities.add_part(id, Test1 { x: id });
ids.push(id);
let id = entities.get_free_slot().unwrap();
entities.add_part(id, Test1 { x: id });
ids.push(id);
let partmap = entities.get_pmap_ref::<Test1>().unwrap().unwrap();
for (k, v) in partmap.iter_ref() {
let part = v.downcast_ref::<Test1>().unwrap();
assert!(part.x == *k);
}
}
#[test]
fn partmap_iter_mut() {
struct Test1 {
x: u32,
}
let mut entities = Entities::new(Some(3), Some(3));
let mut ids = Vec::new();
let id = entities.get_free_slot().unwrap();
entities.add_part(id, Test1 { x: id });
ids.push(id);
let id = entities.get_free_slot().unwrap();
entities.add_part(id, Test1 { x: id });
ids.push(id);
let id = entities.get_free_slot().unwrap();
entities.add_part(id, Test1 { x: id });
ids.push(id);
let mut partmap = entities.get_pmap_mut::<Test1>().unwrap().unwrap();
for (k, v) in partmap.iter_mut() {
let part = v.downcast_mut::<Test1>().unwrap();
part.x += 1;
assert!(part.x > *k);
}
}
#[test]
fn remove_parts_then_entity() {
#[derive(Debug, PartialEq)]
struct Test1 {}
#[derive(Debug, PartialEq)]
struct Test2 {
x: u32,
}
let mut entities = Entities::new(Some(3), Some(3));
let entity_1 = entities.get_free_slot().unwrap();
entities.add_part(entity_1, Test1 {});
entities.add_part(entity_1, Test2 { x: 42 });
assert!(entities.entity_contains::<Test1>(entity_1));
assert!(entities.rm_part::<Test1>(entity_1));
assert!(!entities.entity_contains::<Test1>(entity_1));
assert!(entities.entity_contains::<Test2>(entity_1));
let type_mask_2 = entities.get_type_mask::<Test2>().unwrap();
assert_eq!(entities.get_entity_mask(entity_1), type_mask_2);
assert!(entities.rm_part::<Test2>(entity_1));
assert_eq!(entities.get_entity_mask(entity_1), 0);
}
#[test]
fn removing_entity() {
struct Test1 {}
let mut entities = Entities::new(Some(3), Some(3));
let entity_1 = entities.get_free_slot().unwrap();
entities.add_part(entity_1, Test1 {});
entities.rm_entity(entity_1);
let partmap = entities.get_pmap_ref::<Test1>().unwrap().unwrap();
assert_eq!(partmap.get_part_ref::<Test1>(entity_1).is_err(), true);
}
}