use std::mem;
use std::ops::{Index, IndexMut};
use std::usize;
use uuid::Uuid;
use cell::CellState;
use entity::{Entity, EntityState, MutEntityState};
#[derive(Debug)]
pub struct EntityPositions(pub Vec<Vec<usize>>);
impl EntityPositions {
pub fn new(universe_size: usize) -> Self {
EntityPositions(vec![Vec::new(); universe_size * universe_size])
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl Index<usize> for EntityPositions {
type Output = Vec<usize>;
fn index<'a>(&'a self, index: usize) -> &'a Self::Output {
debug_assert!(index < self.0.len());
unsafe { &self.0.get_unchecked(index) }
}
}
impl IndexMut<usize> for EntityPositions {
fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut Self::Output {
debug_assert!(index < self.0.len());
unsafe { self.0.get_unchecked_mut(index) }
}
}
pub enum EntitySlot<C: CellState, E: EntityState<C>, M: MutEntityState> {
Occupied{
entity: Entity<C, E, M>,
universe_index: usize
},
Empty(usize),
}
unsafe impl<C: CellState, E: EntityState<C>, M: MutEntityState> Send for EntitySlot<C, E, M> where E:Send, M:Send {}
pub struct EntityContainer<C: CellState, E: EntityState<C>, M: MutEntityState> {
pub entities: Vec<EntitySlot<C, E, M>>,
pub empty_index: usize,
pub positions: EntityPositions
}
impl<C: CellState, E: EntityState<C>, M: MutEntityState> EntityContainer<C, E, M> {
pub fn new(universe_size: usize) -> Self {
EntityContainer{
entities: vec![EntitySlot::Empty(usize::MAX)],
empty_index: 0,
positions: EntityPositions::new(universe_size)
}
}
pub fn insert(&mut self, entity: Entity<C, E, M>, universe_index: usize) -> usize {
let &mut EntityContainer{ref mut entities, empty_index, ref mut positions} = self;
let entity_index = if empty_index != usize::MAX {
let next_empty = match entities[empty_index] {
EntitySlot::Empty(next_empty) => next_empty,
_ => unreachable!(),
};
self.empty_index = next_empty;
entities[empty_index] = EntitySlot::Occupied{entity, universe_index};
empty_index
} else {
let entity_count = entities.len();
entities.push(EntitySlot::Occupied{entity, universe_index});
entity_count
};
positions[universe_index].push(entity_index);
entity_index
}
pub fn remove(&mut self, entity_index: usize) -> Entity<C, E, M> {
let removed = mem::replace(&mut self.entities[entity_index], EntitySlot::Empty(self.empty_index));
self.empty_index = entity_index;
match removed {
EntitySlot::Occupied{entity, universe_index} => {
let position_index = self.positions[universe_index]
.iter()
.position(|&index| index == entity_index)
.expect("Unable to locate entity index at the expected location in the positions vector!");
let removed_entity_index = self.positions[universe_index].remove(position_index);
debug_assert_eq!(removed_entity_index, entity_index);
entity
},
EntitySlot::Empty(_) => unreachable!(),
}
}
pub unsafe fn get(&self, index: usize) -> &Entity<C, E, M> {
debug_assert!(index < self.entities.len());
match self.entities.get_unchecked(index) {
&EntitySlot::Occupied{ref entity, universe_index: _} => entity,
_ => unreachable!(),
}
}
pub unsafe fn get_mut(&mut self, index: usize) -> &mut Entity<C, E, M> {
debug_assert!(index < self.entities.len());
match self.entities.get_unchecked_mut(index) {
&mut EntitySlot::Occupied{ref mut entity, universe_index: _} => entity,
_ => unreachable!(),
}
}
pub fn get_verify(&self, index: usize, uuid: Uuid) -> Option<(&Entity<C, E, M>, usize)> {
debug_assert!(index < self.entities.len());
match unsafe { self.entities.get_unchecked(index) } {
&EntitySlot::Occupied{ref entity, universe_index} => {
if entity.uuid == uuid { Some((entity, universe_index)) } else { None }
},
_ => None,
}
}
pub fn get_verify_mut(&mut self, index: usize, uuid: Uuid) -> Option<(&mut Entity<C, E, M>, usize)> {
debug_assert!(index < self.entities.len());
match unsafe { self.entities.get_unchecked_mut(index) } {
&mut EntitySlot::Occupied{ref mut entity, universe_index} => {
if entity.uuid == uuid { Some((entity, universe_index)) } else { None }
},
_ => None,
}
}
pub fn move_entity(&mut self, entity_index: usize, dst_universe_index: usize) {
debug_assert!(entity_index < self.entities.len());
debug_assert!(dst_universe_index < self.positions.len());
let src_universe_index: usize = match self.entities[entity_index] {
EntitySlot::Occupied{entity: _, ref mut universe_index} => {
let src_universe_index: usize = *universe_index;
*universe_index = dst_universe_index;
src_universe_index
},
_ => unreachable!(),
};
let position_index = self.positions[src_universe_index]
.iter()
.position(|&index| index == entity_index)
.expect("Unable to locate entity index at the expected location in the positions vector!");
let removed = self.positions[src_universe_index].remove(position_index);
debug_assert_eq!(entity_index, removed);
self.positions[dst_universe_index].push(entity_index);
}
pub fn iter<'a>(&'a self) -> impl Iterator<Item=(&'a Entity<C, E, M>, usize, usize)> {
self.entities.iter()
.enumerate()
.filter(|&(_, slot)| match slot {
&EntitySlot::Occupied{entity: _, universe_index: _} => true,
&EntitySlot::Empty(_) => false,
}).map(|(entity_index, slot)| match slot {
&EntitySlot::Occupied{ref entity, universe_index} => (entity, entity_index, universe_index),
_ => unreachable!(),
})
}
pub fn get_position_index(&self, entity_index: usize) -> usize {
debug_assert!(self.entities.len() > entity_index);
let universe_index = match self.entities[entity_index] {
EntitySlot::Occupied{entity: _, universe_index} => universe_index,
_ => unreachable!(),
};
self.positions[universe_index]
.iter()
.position(|&index| index == entity_index)
.expect("Unable to find entry in position vector at at index pointed to by entity vector!")
}
pub fn get_entities_at(&self, universe_index: usize) -> &[usize] {
debug_assert!(universe_index < self.positions.len());
&self.positions[universe_index]
}
pub fn len(&self) -> usize {
self.entities.len()
}
}