use std::mem;
use stable_id_traits::{Maximum, Predecessor, Successor};
use crate::Eids;
impl<IndexT> Eids<IndexT>
where
IndexT: Successor + Predecessor + Clone + Copy + Ord + Maximum,
{
pub fn claim(&mut self) -> IndexT {
assert!(
self.next < IndexT::max_value(),
"storing more items than you can address"
);
self.freed
.iter()
.next()
.cloned()
.map(|id| {
let is_removed = self.freed.remove(&id);
debug_assert!(is_removed, "freeing something not in the database");
id
})
.unwrap_or_else(|| {
let next = self.next.next_value();
mem::replace(&mut self.next, next)
})
}
pub fn unclaim(&mut self, val: IndexT) {
assert!(val < self.next, "not a valid entity");
let is_double_inserted = self.freed.insert(val);
debug_assert!(is_double_inserted, "double-freeing entity")
}
pub fn coalesce<F>(&mut self, mut f: F)
where
F: FnMut(IndexT, IndexT),
{
if self.freed.is_empty() {
return;
}
while let Some(freed) = self.freed.pop_last() {
let target = self.next.prev_value();
self.next = target;
if target != freed {
f(target, freed);
}
}
}
}
#[cfg(test)]
mod eid_tests {
use super::Eids;
#[test]
fn claim_ids() {
let mut entities: Eids<u8> = Default::default();
for i in 0..100 {
let id = entities.claim();
assert_eq!(id, i);
}
fn is_multiple_of_3(i: &u8) -> bool {
i % 3 == 0
}
(0..60u8)
.filter(is_multiple_of_3)
.for_each(|i| entities.unclaim(i));
(0..60u8)
.filter(is_multiple_of_3)
.all(|i| entities.claim() == i);
}
#[test]
#[should_panic]
fn unclaim_invalid() {
let mut entities: Eids<u8> = Default::default();
entities.unclaim(123u8)
}
#[test]
#[should_panic]
fn double_free() {
let mut entities: Eids<u8> = Default::default();
let id = entities.claim();
entities.unclaim(id);
entities.unclaim(id);
}
#[test]
#[should_panic]
fn claim_over_max() {
let mut entities: Eids<u8> = Default::default();
(0..257).for_each(|_| {
entities.claim();
});
}
}