use super::entity::Entity;
use crate::no_such_entity::NoSuchEntity;
use crate::Entities;
use std::fmt::Debug;
use std::sync::{Arc, RwLock};
#[derive(Debug)]
pub struct VecStorage<T> {
vec: Vec<Option<T>>,
entities: Arc<RwLock<Entities>>,
}
impl<T> VecStorage<T> {
pub fn new(entities: Arc<RwLock<Entities>>, capacity: u32) -> Self {
let mut vec = vec![];
vec.resize_with(capacity as usize, Default::default);
Self { vec, entities }
}
pub fn get(&self, entity: Entity) -> Option<&T> {
let lock = self.entities.read().unwrap();
if lock.exists(entity) {
self.vec
.get(entity.index as usize)
.unwrap_or(&None)
.as_ref()
} else {
None
}
}
pub fn get_mut(&mut self, entity: Entity) -> Option<&mut T> {
let lock = self.entities.read().unwrap();
if lock.exists(entity) {
if let Some(entry) = self.vec.get_mut(entity.index as usize) {
entry.as_mut()
} else {
None
}
} else {
None
}
}
pub fn set(&mut self, entity: Entity, data: T) -> Result<Option<T>, NoSuchEntity> {
let lock = self.entities.read().unwrap();
if lock.exists(entity) {
match self.vec.get_mut(entity.index as usize) {
None => {
let new_len = usize::max(self.vec.capacity() * 2, entity.index as usize + 1);
self.vec.resize_with(new_len, || None);
self.vec[entity.index as usize] = Some(data);
Ok(None)
}
Some(entry) => Ok(entry.replace(data)),
}
} else {
Err(NoSuchEntity {})
}
}
pub fn remove_unchecked(&mut self, entity: Entity) -> Option<T> {
if let Some(entry) = self.vec.get_mut(entity.index as usize) {
entry.take()
} else {
None
}
}
pub fn remove(&mut self, entity: Entity) -> Result<Option<T>, NoSuchEntity> {
let lock = self.entities.read().unwrap();
if lock.exists(entity) {
if let Some(entry) = self.vec.get_mut(entity.index as usize) {
Ok(entry.take())
} else {
Ok(None)
}
} else {
Err(NoSuchEntity)
}
}
pub fn clear(&mut self) {
self.vec.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
struct VecTestData(i32);
#[test]
fn vec_get_not_set() {
let entities = Arc::new(RwLock::new(Entities::new(3)));
let vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), 3);
let entity = Entity {
index: 0,
generation: 0,
};
let entry = vec.get(entity);
assert_eq!(entry, None);
}
#[test]
fn vec_get() -> Result<(), NoSuchEntity> {
let entities = Arc::new(RwLock::new(Entities::new(3)));
let mut vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), 3);
let entity = {
let mut lock = entities.write().unwrap();
lock.spawn()
};
let data = VecTestData(42);
let old_data = vec.set(entity, data)?;
assert_eq!(old_data, None);
let entry = vec.get(entity);
assert_eq!(entry, Some(&data));
Ok(())
}
#[test]
fn vec_set_exists() -> Result<(), NoSuchEntity> {
let entities = Arc::new(RwLock::new(Entities::new(3)));
let mut vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), 3);
let entity = {
let mut lock = entities.write().unwrap();
lock.spawn()
};
let data = VecTestData(42);
let old_data = vec.set(entity, data)?;
assert_eq!(old_data, None);
assert_eq!(vec.get(entity), Some(&data));
let wrong_entity = Entity {
index: 0,
generation: 1,
};
assert!(vec.set(wrong_entity, VecTestData(69)).is_err()); Ok(())
}
#[test]
fn can_insert_after_remove() -> Result<(), NoSuchEntity> {
let entities = Arc::new(RwLock::new(Entities::new(3)));
let mut vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), 3);
let entity = {
let mut lock = entities.write().unwrap();
lock.spawn()
};
let data = VecTestData(42);
vec.set(entity, data)?;
let removed_data = vec.remove(entity)?;
assert_eq!(removed_data, Some(VecTestData(42)));
let missing_entry = vec.get(entity);
assert_eq!(missing_entry, None);
let missing_entry = vec.set(entity, data)?;
assert_eq!(missing_entry, None);
let entry = vec.get(entity);
assert_eq!(entry, Some(&VecTestData(42)));
Ok(())
}
#[test]
fn cannot_access_out_of_bounds() {
let n = 3;
let entities = Arc::new(RwLock::new(Entities::new(3)));
let vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), 3);
let entity = Entity {
index: n,
generation: 0,
};
let nope = vec.get(entity);
assert_eq!(nope, None);
}
#[test]
fn inserting_grows_vec_enough() -> Result<(), NoSuchEntity> {
let capacity = 1;
let n = 3;
let entities = Arc::new(RwLock::new(Entities::new(capacity)));
let mut vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), capacity);
let entity = {
let mut lock = entities.write().unwrap();
for _i in 0..n - 1 {
lock.spawn();
}
lock.spawn()
};
let data = VecTestData(42);
let old_data = vec.set(entity, data)?;
assert_eq!(old_data, None);
let value = vec.get(entity);
assert_eq!(value, Some(&data));
Ok(())
}
#[test]
fn remove_missing_is_ok() -> Result<(), NoSuchEntity> {
let entities = Arc::new(RwLock::new(Entities::new(3)));
let mut vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), 3);
let entity = {
let mut lock = entities.write().unwrap();
lock.spawn()
};
let remove_result = vec.remove(entity)?;
assert_eq!(remove_result, None);
Ok(())
}
#[test]
fn test_iter_update() -> Result<(), NoSuchEntity> {
let entities = Arc::new(RwLock::new(Entities::new(3)));
let mut vec = VecStorage::<VecTestData>::new(Arc::clone(&entities), 3);
let (entity1, entity2) = {
let mut write = entities.write().unwrap();
let entity1 = write.spawn();
let entity2 = write.spawn();
write.spawn(); (entity1, entity2)
};
vec.set(entity1, VecTestData(1))?;
vec.set(entity2, VecTestData(2))?;
{
let read = entities.read().unwrap();
let mut expected_value = 1;
for entity in read.iter() {
if let Some(data) = vec.get_mut(entity) {
assert_eq!(data.0, expected_value);
expected_value += 1;
*data = VecTestData(40 + data.0);
}
}
let mut expected_value = 41;
for entity in read.iter() {
if let Some(data) = vec.get(entity) {
assert_eq!(data.0, expected_value);
expected_value += 1;
}
}
}
Ok(())
}
}