use crate::{
locks::LockTrait,
mem_lay::get_layout,
prelude::*,
slab::{Slab, free_master},
slab_box::SlabBox,
};
use core::{alloc::Layout, ptr::NonNull};
pub struct SlabCache<T, LOCK, const SLAB_SIZE: usize>
where
LOCK: LockTrait,
{
master: Option<NonNull<Slab<T, LOCK>>>,
}
unsafe impl<T, LOCK, const SLAB_SIZE: usize> Sync for SlabCache<T, LOCK, SLAB_SIZE>
where
T: Send,
LOCK: LockTrait + Sync,
{
}
unsafe impl<T, LOCK, const SLAB_SIZE: usize> Send for SlabCache<T, LOCK, SLAB_SIZE>
where
T: Send,
LOCK: LockTrait + Sync,
{
}
impl<T, LOCK, const SLAB_SIZE: usize> Clone for SlabCache<T, LOCK, SLAB_SIZE>
where
LOCK: LockTrait,
{
fn clone(&self) -> Self {
let master_ptr = self
.master
.expect("can not clone non-initialized SlabCache");
Slab::<T, LOCK>::atomic_ref_up(master_ptr).expect("internal error");
Self {
master: Some(master_ptr),
}
}
}
impl<T, LOCK, const SLAB_SIZE: usize> Drop for SlabCache<T, LOCK, SLAB_SIZE>
where
LOCK: LockTrait,
{
fn drop(&mut self) {
self.free_self();
}
}
impl<T, LOCK, const SLAB_SIZE: usize> SlabCache<T, LOCK, SLAB_SIZE>
where
LOCK: LockTrait,
{
const SLAB_SIZE_CHECK: usize = const {
let size: usize = size_of::<T>();
assert!(
size >= size_of::<u32>(),
"Slot Type Smaller Than `u32` Not Allowed At SlabCache"
);
let slab_header_size = size_of::<Slab<T, LOCK>>();
let slot_per_slab = (SLAB_SIZE - slab_header_size) / size;
assert!(
slot_per_slab >= 2,
"Slot Type Size Is Greater Than SlabSize (must fit at least 2 slots per slab)"
);
size
};
const SLAB_LAYOUT: Layout = get_layout(SLAB_SIZE);
pub fn new() -> Result<SlabCache<T, LOCK, SLAB_SIZE>> {
let _ = Self::SLAB_SIZE_CHECK;
let slab_master = Slab::<T, LOCK>::alloc_slab_ptr(Self::SLAB_LAYOUT, None, free_master)?;
Slab::<T, LOCK>::atomic_ref_up(slab_master)?;
Ok(Self {
master: Some(slab_master),
})
}
fn free_self(&mut self) {
if let Some(master) = self.master.take() {
Slab::<T, LOCK>::atomic_release_master(master, Self::SLAB_LAYOUT)
.expect("internal curruption");
}
}
pub fn alloc(&mut self) -> Result<SlabBox<T, LOCK, SLAB_SIZE>> {
if let Some(master) = self.master {
let ptr = Slab::<T, LOCK>::alloc_slot(master, Self::SLAB_LAYOUT)?;
let ptr_box = SlabBox::<T, LOCK, SLAB_SIZE>::new(ptr);
Ok(ptr_box)
} else {
Err(SlabError::FatalError)
}
}
}