#[cfg(feature = "base-mmap")]
mod mmap;
#[cfg(feature = "base-static")]
mod static_;
use core::{
alloc::{AllocError, Allocator, Layout},
mem::ManuallyDrop,
ptr::NonNull,
};
#[cfg(feature = "base-mmap")]
pub use self::mmap::Mmap;
#[cfg(feature = "base-static")]
pub use self::static_::Static;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StaticHandle;
pub unsafe trait BaseAlloc: Sized {
const IS_ZEROED: bool;
type Handle;
type Error;
fn allocate(&self, layout: Layout, commit: bool) -> Result<Chunk<Self>, Self::Error>;
unsafe fn deallocate(chunk: &mut Chunk<Self>);
unsafe fn commit(&self, ptr: NonNull<[u8]>) -> Result<(), Self::Error> {
let _ = ptr;
Ok(())
}
unsafe fn decommit(&self, ptr: NonNull<[u8]>) {
let _ = ptr;
}
}
unsafe impl<A: Allocator + Clone> BaseAlloc for A {
const IS_ZEROED: bool = false;
type Handle = ManuallyDrop<Self>;
type Error = AllocError;
fn allocate(&self, layout: Layout, _commit: bool) -> Result<Chunk<Self>, Self::Error> {
let ptr = Allocator::allocate(self, layout)?;
Ok(unsafe { Chunk::new(ptr.cast(), layout, ManuallyDrop::new(self.clone())) })
}
unsafe fn deallocate(chunk: &mut Chunk<Self>) {
let ptr = chunk.pointer().cast();
chunk.handle.deallocate(ptr, chunk.layout());
ManuallyDrop::drop(&mut chunk.handle);
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Zeroed<A: Allocator>(pub A);
unsafe impl<A: Allocator + Clone> BaseAlloc for Zeroed<A> {
const IS_ZEROED: bool = true;
type Handle = ManuallyDrop<A>;
type Error = AllocError;
fn allocate(&self, layout: Layout, _commit: bool) -> Result<Chunk<Self>, Self::Error> {
let ptr = Allocator::allocate_zeroed(&self.0, layout)?;
Ok(unsafe { Chunk::new(ptr.cast(), layout, ManuallyDrop::new(self.0.clone())) })
}
unsafe fn deallocate(chunk: &mut Chunk<Self>) {
let ptr = chunk.pointer().cast();
chunk.handle.deallocate(ptr, chunk.layout());
ManuallyDrop::drop(&mut chunk.handle);
}
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Chunk<B: BaseAlloc> {
ptr: NonNull<u8>,
layout: Layout,
pub handle: B::Handle,
}
unsafe impl<B: BaseAlloc> Send for Chunk<B> where B::Handle: Send {}
unsafe impl<B: BaseAlloc> Sync for Chunk<B> where B::Handle: Sync {}
impl<B: BaseAlloc> Chunk<B> {
pub unsafe fn new(ptr: NonNull<u8>, layout: Layout, handle: B::Handle) -> Self {
Chunk { ptr, layout, handle }
}
pub unsafe fn from_static(ptr: NonNull<u8>, layout: Layout) -> Self
where
B: BaseAlloc<Handle = StaticHandle>,
{
Self::new(ptr, layout, StaticHandle)
}
pub fn layout(&self) -> Layout {
self.layout
}
pub fn pointer(&self) -> NonNull<[u8]> {
NonNull::from_raw_parts(self.ptr.cast(), self.layout.size())
}
}
impl<B: BaseAlloc> Drop for Chunk<B> {
fn drop(&mut self) {
unsafe { B::deallocate(self) }
}
}