use alloc::alloc::Layout;
use core::mem;
use core::ptr::{addr_of_mut, NonNull};
struct ChunkHeader {
prev: Option<Chunk>,
}
#[repr(transparent)]
pub struct Chunk(NonNull<ChunkHeader>);
impl Chunk {
pub fn new(layout: Layout, prev: Option<Self>) -> Option<Self> {
let layout = Self::full_layout(layout);
assert!(layout.size() > 0);
let ptr: NonNull<ChunkHeader> =
NonNull::new(unsafe { alloc::alloc::alloc(layout) })?.cast();
unsafe {
addr_of_mut!((*ptr.as_ptr()).prev).write(prev);
}
Some(Self(ptr))
}
pub fn layout(layout: Layout) -> Layout {
let size = layout.size();
let align = layout.align().max(mem::align_of::<ChunkHeader>());
Layout::from_size_align(size, align).unwrap()
}
pub fn full_layout(layout: Layout) -> Layout {
let size =
layout.size().checked_add(mem::size_of::<ChunkHeader>()).unwrap();
let align = layout.align().max(mem::align_of::<ChunkHeader>());
Layout::from_size_align(size, align).unwrap()
}
pub fn storage(&self) -> NonNull<u8> {
let end = unsafe { self.0.as_ptr().add(1) };
unsafe { NonNull::new_unchecked(end) }.cast()
}
pub fn take_prev(&mut self) -> Option<Self> {
unsafe { &mut (*self.0.as_ptr()).prev }.take()
}
pub unsafe fn drop(self, layout: Layout) {
unsafe {
alloc::alloc::dealloc(
self.0.as_ptr().cast(),
Self::full_layout(layout),
);
}
}
}