use std::any::{Any, TypeId};
use std::mem::{transmute, size_of};
use std::ops::{Index, IndexMut};
#[derive(Debug)]
pub struct DynVec {
vec: Vec<u8>,
unused: Vec<usize>,
t: TypeId,
size: usize,
}
impl DynVec {
pub fn new<T: Any>() -> DynVec {
assert!(size_of::<T>() > 0);
DynVec {
vec: Vec::new(),
unused: Vec::new(),
t: TypeId::of::<T>(),
size: size_of::<T>(),
}
}
pub fn get_component<T: Any>(&self, i: usize) -> Option<&T> {
unsafe {
assert_eq!(self.t, TypeId::of::<T>()); Some(transmute::<&u8, &T>(self.vec.index(i * self.size)))
}
}
pub fn get_component_mut<T: Any>(&mut self, i: usize) -> Option<&mut T> {
unsafe {
assert_eq!(self.t, TypeId::of::<T>()); Some(transmute::<&mut u8, &mut T>(self.vec.index_mut(i * self.size)))
}
}
pub fn add<T: Any>(&mut self, val: T) -> usize {
unsafe {
use std::slice::from_raw_parts;
assert_eq!(self.t, TypeId::of::<T>()); let slice: &[u8] = from_raw_parts::<u8>(transmute(&val), self.size);
if let Some(index) = self.unused.pop() {
for i in 0..self.size {
self.vec[i + index * self.size] = slice[i]; }
index
} else {
self.vec.extend_from_slice(slice);
self.vec.len() / self.size - 1
}
}
}
pub fn remove(&mut self, index: usize) {
assert!(index * self.size < self.vec.len());
assert!(!self.unused.contains(&index));
self.unused.push(index);
}
}
#[cfg(test)]
mod tests {
use super::DynVec;
#[test]
fn add_remove() {
struct Test(u32, f64);
let mut vec = DynVec::new::<Test>();
let id1 = vec.add(Test(32, 32.0));
let id2 = vec.add(Test(35, 64.125));
assert!(id1 != id2);
{
println!("{} {}", id1, id2);
let ref1 = vec.get_component::<Test>(id1).unwrap();
let ref2 = vec.get_component::<Test>(id2).unwrap();
assert_eq!(ref1.0, 32);
assert_eq!(ref1.1, 32.0); assert_eq!(ref2.0, 35);
assert_eq!(ref2.1, 64.125); }
let id3 = vec.add(Test(0, 0.0));
vec.remove(id2);
let id4 = vec.add(Test(1, 0.25));
assert_eq!(id2, id4);
{
let ref4 = vec.get_component::<Test>(id4).unwrap();
assert_eq!(ref4.0, 1);
assert_eq!(ref4.1, 0.25); }
}
#[test]
#[should_panic]
fn type_check() {
struct Struct1(u8);
struct Struct2(u8);
let mut vec = DynVec::new::<Struct1>();
vec.add(Struct2(0));
}
#[test]
#[should_panic]
fn zero_sized_structs() {
let vec = DynVec::new::<()>();
}
}