use std::{cell::UnsafeCell, mem::MaybeUninit, ptr::NonNull};
pub(crate) const BLOCK_CAP: usize = 4 * 1024;
thread_local! {
pub(crate) static BLOCK_MANAGER: UnsafeCell<BlockManager> = UnsafeCell::new(BlockManager::new());
}
#[derive(Debug)]
pub(crate) struct Block {
pub(crate) ref_count: usize,
pub(crate) buf: [MaybeUninit<u8>; BLOCK_CAP],
}
impl Block {
pub(crate) const fn new() -> Self {
Block {
ref_count: 0,
buf: unsafe { MaybeUninit::uninit().assume_init() },
}
}
pub(crate) fn new_ptr() -> NonNull<Self> {
let block = Self::new();
unsafe { NonNull::new_unchecked(Box::leak(Box::new(block))) }
}
pub(crate) fn get_buf(&self) -> &[u8] {
unsafe { std::mem::transmute(self.buf.as_ref()) }
}
pub(crate) fn get_mut_buf(&mut self) -> &mut [u8] {
unsafe { std::mem::transmute(self.buf.as_mut()) }
}
}
#[derive(Debug)]
pub(crate) struct BlockNode {
pub(crate) block: NonNull<Block>,
pub(crate) next: Option<NonNull<BlockNode>>,
}
impl BlockNode {
pub(crate) fn new_ptr() -> NonNull<Self> {
let block = Block::new_ptr();
let node = Self { block, next: None };
unsafe { NonNull::new_unchecked(Box::leak(Box::new(node))) }
}
pub(crate) fn alloc() -> NonNull<Self> {
let mut node = BLOCK_MANAGER.with(|m| unsafe { (&mut *m.get()).alloc_node() });
unsafe { node.as_mut() }.ref_inc();
node
}
pub(crate) fn ref_inc(&mut self) {
unsafe { self.block.as_mut() }.ref_count += 1;
}
}
pub(crate) struct BlockManager {
head: Option<NonNull<BlockNode>>,
}
impl Drop for BlockManager {
fn drop(&mut self) {
let mut maybe_node = self.head.take();
while let Some(mut node) = maybe_node {
let mut block = unsafe { node.as_ref() }.block;
maybe_node = unsafe { node.as_ref() }.next;
unsafe { std::ptr::drop_in_place(block.as_mut()) };
unsafe { std::ptr::drop_in_place(node.as_mut()) };
}
}
}
impl BlockManager {
pub(crate) const fn new() -> Self {
Self { head: None }
}
pub(crate) fn alloc_node(&mut self) -> NonNull<BlockNode> {
if let Some(mut node) = self.head {
self.head = unsafe { node.as_mut() }.next.take();
node
} else {
BlockNode::new_ptr()
}
}
pub(crate) unsafe fn free_node(&mut self, mut node: NonNull<BlockNode>) {
debug_assert!(node.as_ref().block.as_ref().ref_count == 0);
node.as_mut().next = self.head;
self.head = Some(node);
}
}
pub(crate) unsafe fn free_block_node(node: NonNull<BlockNode>) {
BLOCK_MANAGER.with(|m| unsafe { (&mut *m.get()).free_node(node) });
}
pub(crate) unsafe fn free_node(mut node: NonNull<BlockNode>) {
std::ptr::drop_in_place(node.as_mut());
}
pub(crate) unsafe fn drop_node(mut node: NonNull<BlockNode>) {
let block_rc = &mut node.as_mut().block.as_mut().ref_count;
*block_rc -= 1;
if *block_rc == 0 {
free_block_node(node);
} else {
free_node(node);
}
}