use core::mem;
use alloc::vec::Vec;
pub struct Slab<T> {
entries: Vec<Entry<T>>,
next_free: Option<usize>,
len: usize,
}
unsafe impl<T: Send> Send for Slab<T> {}
enum Entry<T> {
Occupied(T),
Vacant(usize), }
impl<'a, T> From<&'a Entry<T>> for Option<&'a T> {
fn from(value: &'a Entry<T>) -> Self {
match value {
Entry::Occupied(x) => Some(&x),
Vacant(_) => None,
}
}
}
impl<'a, T> From<&'a mut Entry<T>> for Option<&'a mut T> {
fn from(value: &'a mut Entry<T>) -> Self {
match value {
Entry::Occupied(x) => Some(x),
Vacant(_) => None,
}
}
}
use Entry::*;
impl<T> Slab<T> {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> Self {
let mut entries = Vec::with_capacity(capacity);
for i in 0..capacity {
entries.push(Entry::Vacant(i + 1));
}
Self {
entries,
next_free: if capacity > 0 { Some(0) } else { None },
len: 0,
}
}
pub fn insert(&mut self, value: T) -> usize {
let Self {
entries,
next_free,
len,
} = self;
match *next_free {
Some(index) => {
match &entries[index] {
Vacant(next) => {
*next_free = if *next < entries.len() {
Some(*next)
} else {
None
}
}
_ => unreachable!(),
}
entries[index] = Occupied(value);
*len += 1;
index
}
None => {
let index = entries.len();
entries.push(Occupied(value));
*len += 1;
index
}
}
}
pub fn remove(&mut self, index: usize) -> Option<T> {
let Self {
entries,
next_free,
len,
} = self;
let len_entries = entries.len();
if index >= len_entries {
None?
}
match mem::replace(
&mut entries[index],
Vacant(next_free.unwrap_or(len_entries)),
) {
Occupied(value) => {
*next_free = Some(index);
*len -= 1;
Some(value)
}
Vacant(_) => None,
}
}
pub fn get(&self, index: usize) -> Option<&T> {
let Self { entries, .. } = self;
entries.get(index).and_then(Option::from)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
let Self { entries, .. } = self;
entries.get_mut(index).and_then(Option::from)
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn capacity(&self) -> usize {
self.entries.len()
}
pub fn clear(&mut self) {
self.entries.clear();
self.next_free = None;
self.len = 0;
}
}