deadlock 0.10.0

Thread-safe slot map and slot min-heap with stable RAII handle
Documentation
use std::{
    alloc::{self, Layout},
    mem::{self, MaybeUninit},
    ptr::NonNull,
};

pub struct SlotMap<T> {
    entries: NonNull<Entry<T>>,
    capacity: usize,
    len: usize,
    next: usize,
}

pub struct Entry<T> {
    pub value: MaybeUninit<T>,
    pub index: usize,
    pub id: usize,
}

impl<T> SlotMap<T> {
    pub fn new() -> Self {
        Self {
            entries: NonNull::dangling(),
            capacity: 0,
            len: 0,
            next: 0,
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn insert(&mut self, value: T) -> usize {
        if self.next == self.capacity {
            unsafe { self.grow() }
        }

        let id = self.next;
        let value_entry = unsafe { self.entries.add(id).as_mut() };
        self.next = mem::replace(&mut value_entry.index, self.len);
        value_entry.value.write(value);
        let id_entry = unsafe { self.entries.add(self.len).as_mut() };
        id_entry.id = id;
        self.len += 1;
        id
    }

    pub unsafe fn remove_unchecked(&mut self, id: usize) -> T {
        let value_entry = unsafe { self.entries.add(id).as_mut() };
        let value = unsafe { value_entry.value.assume_init_read() };
        let index = mem::replace(&mut value_entry.index, self.next);
        self.next = id;
        self.len -= 1;

        if index != self.len {
            let id_entry = unsafe { self.entries.add(index).as_mut() };
            let last_id_entry = unsafe { self.entries.add(self.len).as_mut() };
            let moved_id = last_id_entry.id;
            id_entry.id = moved_id;
            let moved_value_entry = unsafe { self.entries.add(moved_id).as_mut() };
            moved_value_entry.index = index
        }

        value
    }

    pub unsafe fn get_unchecked(&self, id: usize) -> &T {
        unsafe { self.entries.add(id).as_ref().value.assume_init_ref() }
    }

    pub unsafe fn get_unchecked_mut(&mut self, id: usize) -> &mut T {
        unsafe { self.entries.add(id).as_mut().value.assume_init_mut() }
    }

    pub unsafe fn get_unchecked_nth(&self, index: usize) -> &T {
        let id = unsafe { self.get_unchecked_nth_id(index) };
        unsafe { self.get_unchecked(id) }
    }

    pub unsafe fn get_unchecked_nth_id(&self, index: usize) -> usize {
        unsafe { self.entries.add(index).as_ref().id }
    }

    unsafe fn grow(&mut self) {
        let old_capacity = self.capacity;
        self.capacity = if self.capacity == 0 {
            1
        } else {
            self.capacity * 2
        };
        self.entries = unsafe {
            let new_layout = Layout::array::<Entry<T>>(self.capacity).unwrap_unchecked();
            let ptr = if old_capacity == 0 {
                alloc::alloc(new_layout)
            } else {
                let old_layout = Layout::array::<Entry<T>>(old_capacity).unwrap_unchecked();
                alloc::realloc(
                    self.entries.as_ptr() as *mut u8,
                    old_layout,
                    new_layout.size(),
                )
            };
            NonNull::new_unchecked(ptr as *mut Entry<T>)
        };

        for i in old_capacity..self.capacity {
            let entry = unsafe { self.entries.add(i).as_mut() };
            entry.index = i + 1
        }
    }
}

impl<T> Drop for SlotMap<T> {
    fn drop(&mut self) {
        if self.capacity == 0 {
            return;
        }

        for index in 0..self.len {
            let id = unsafe { self.entries.add(index).as_ref().id };
            let entry = unsafe { self.entries.add(id).as_mut() };
            unsafe { entry.value.assume_init_drop() }
        }

        unsafe {
            let layout = Layout::array::<Entry<T>>(self.capacity).unwrap_unchecked();
            alloc::dealloc(self.entries.as_ptr() as *mut u8, layout)
        }
    }
}