#![warn(missing_docs)]
extern crate num;
use std::{result::Result,
hash::Hash,
vec::Vec,
ops::AddAssign,
marker::Copy,
sync::Arc,
sync::Mutex};
use num::{Num, zero, one};
#[derive(Hash, Debug, PartialEq, Copy, Clone)]
pub struct GenIndex<I: Num + AddAssign + Copy,
G: Num + AddAssign + Copy> {
index: I,
generation: G
}
impl<I: Num + AddAssign + Copy,
G: Num + AddAssign + Copy> GenIndex<I, G> {
pub fn get_index(&self) -> I { self.index }
pub fn get_generation(&self) -> G { self.generation }
}
#[derive(Hash, Debug, PartialEq, Clone)]
pub struct GenIndexEntitySet<I: Num + AddAssign + Copy,
G: Num + AddAssign + Copy> {
index_note: I,
deleted: Vec<GenIndex<I, G>>,
}
impl<I: Num + AddAssign + Copy,
G: Num + AddAssign + Copy> GenIndexEntitySet<I, G> {
pub fn new() -> Arc<Mutex<GenIndexEntitySet<I, G>>> {
Arc::new(Mutex::new(GenIndexEntitySet {
index_note: zero(),
deleted: vec!{}
}))
}
pub fn next_index(&mut self) -> GenIndex<I, G> {
if self.deleted.is_empty() {
let g = GenIndex{index: self.index_note, generation: zero()};
self.index_note += one();
g
} else {
let mut oldidx = self.deleted.pop().unwrap();
oldidx.generation += one();
oldidx
}
}
pub fn delete_index(&mut self, gi: GenIndex<I, G>) -> Result<(), &'static str> {
self.deleted.push(gi);
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::thread::*;
use std::vec::*;
use super::*;
const THREADS: u32 = 100;
#[test]
fn test_gen_index_generation() {
let gi = GenIndexEntitySet::<u64, u64>::new();
let chk = GenIndex::<u64, u64> {index: zero(), generation: zero()};
let idx1 = gi.lock().unwrap().next_index();
assert_eq!(chk, idx1);
let mut chk2 = chk.clone();
chk2.index += 1;
let idx2 = gi.lock().unwrap().next_index();
assert_eq!(chk2, idx2);
let mut chk3 = chk.clone();
chk3.generation += 1;
if let Err(e) = gi.lock().unwrap().delete_index(idx1) {
println!("Error: {}", e);
}
let idx3 = gi.lock().unwrap().next_index();
assert_eq!(chk3, idx3);
}
#[test]
fn test_multithreaded_index_generation() {
let gi = GenIndexEntitySet::<u64, u64>::new();
let mut threads = Vec::new();
for _ in 0..THREADS {
let cgi = gi.clone();
threads.push(spawn(move || {
let idx = {
let mut gi = cgi.lock().unwrap();
gi.next_index()
};
if let Err(e) = cgi.lock().unwrap().delete_index(idx) {
println!("error: {:?}", e);
}
}));
}
for j in threads {
if let Err(e) = j.join() {
println!("thead_error: {:?}", e);
}
}
}
}