#[deny(missing_docs)]
use std::fmt;
pub trait Id: Copy + fmt::Display + fmt::Debug {
fn initial() -> Self;
fn as_usize(self) -> usize;
fn increment(self) -> Self;
fn take(&mut self) -> Self;
fn expect(self, m: &str) -> Self;
fn none() -> Self;
fn is_none(self) -> bool;
}
macro_rules! impl_primitive_index {
($ty:ident) => {
impl Id for $ty {
#[inline(always)]
fn initial() -> Self {
0
}
#[inline(always)]
fn as_usize(self) -> usize {
self as usize
}
#[inline(always)]
fn increment(self) -> Self {
if self.is_none() {
panic!("index `{}` is out of bounds: 0-{}", self, std::$ty::MAX);
}
self + 1
}
#[inline(always)]
fn take(&mut self) -> Self {
std::mem::replace(self, Self::none())
}
#[inline(always)]
fn expect(self, m: &str) -> Self {
if self.is_none() {
panic!("{}", m);
}
self
}
#[inline(always)]
fn none() -> Self {
std::$ty::MAX
}
#[inline(always)]
fn is_none(self) -> bool {
self == Self::none()
}
}
};
}
impl_primitive_index!(u8);
impl_primitive_index!(u16);
impl_primitive_index!(u32);
impl_primitive_index!(u64);
impl_primitive_index!(u128);
pub struct Slab<I>
where
I: Id,
{
data: Vec<I>,
next: I,
}
impl<I> Slab<I>
where
I: Id,
{
pub fn new() -> Self {
Self {
data: Vec::new(),
next: I::initial(),
}
}
pub fn next(&mut self) -> I {
let index = self.next;
self.next = if let Some(entry) = self.data.get_mut(self.next.as_usize()) {
entry.take().expect("next index is null")
} else {
self.data.push(I::none());
self.next.increment()
};
index
}
pub fn free(&mut self, index: I) -> bool {
if let Some(entry) = self.data.get_mut(index.as_usize()) {
if entry.is_none() {
*entry = self.next;
self.next = index;
return true;
}
}
false
}
}
impl<I> Default for Slab<I>
where
I: Id,
{
fn default() -> Self {
Self::new()
}
}