Documentation
use core::mem;

use alloc::vec::Vec;

pub struct Slab<T> {
    // Storage for all entries
    entries: Vec<Entry<T>>,
    // Head of the free list
    next_free: Option<usize>,
    // Number of occupied entries
    len: usize,
}

unsafe impl<T: Send> Send for Slab<T> {}

enum Entry<T> {
    Occupied(T),
    Vacant(usize), // Next free index
}

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;
    }
}