use core::ptr::NonNull;
use super::HeapSlot;
#[derive(Debug)]
pub struct SlabSlotList<const SLOT_SIZE: usize> {
head: Option<NonNull<u8>>,
}
unsafe impl<const SLOT_SIZE: usize> Sync for SlabSlotList<SLOT_SIZE> {}
unsafe impl<const SLOT_SIZE: usize> Send for SlabSlotList<SLOT_SIZE> {}
impl<const SLOT_SIZE: usize> Default for SlabSlotList<SLOT_SIZE> {
fn default() -> Self {
Self::new()
}
}
impl<const SLOT_SIZE: usize> SlabSlotList<SLOT_SIZE> {
pub const fn new() -> Self {
Self { head: None }
}
pub fn push(&mut self, slot: HeapSlot) {
let slot_ptr = slot.as_ptr();
let super::SlotInfo::SlabSlot(slot_size) = slot.info() else {
panic!("The slot does not come from a slab");
};
assert_eq!(slot_size, SLOT_SIZE);
const { assert!(SLOT_SIZE >= size_of::<usize>()) };
let original_head = self.head;
debug_assert!(!slot_ptr.is_null());
self.head = Some(unsafe { NonNull::new_unchecked(slot_ptr) });
unsafe {
slot_ptr
.cast::<usize>()
.write(original_head.map_or(0, |h| h.as_ptr() as usize));
}
}
pub fn pop(&mut self) -> Option<HeapSlot> {
let original_head = self.head?;
let next = unsafe { original_head.as_ptr().cast::<usize>().read() } as *mut u8;
self.head = if next.is_null() {
None
} else {
Some(unsafe { NonNull::new_unchecked(next) })
};
Some(unsafe { HeapSlot::new(original_head, super::SlotInfo::SlabSlot(SLOT_SIZE)) })
}
}