use core::alloc::Layout;
use core::error::Error;
use core::fmt;
use core::ptr::NonNull;
pub unsafe trait Allocator {
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<u8>, AllocError>;
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
fn allocate_internal(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
self.allocate_zeroed(layout)
}
unsafe fn deallocate_internal(&self, page: NonNull<u8>, layout: Layout) {
unsafe { self.deallocate(page, layout) }
}
fn allocate_leaf(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
self.allocate_zeroed(layout)
}
unsafe fn deallocate_leaf(&self, page: NonNull<u8>, layout: Layout) {
unsafe { self.deallocate(page, layout) }
}
fn allocate_root(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
self.allocate_zeroed(layout)
}
unsafe fn deallocate_root(&self, page: NonNull<u8>, layout: Layout) {
unsafe { self.deallocate(page, layout) }
}
fn allocate_heap(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
self.allocate_zeroed(layout)
}
unsafe fn deallocate_heap(&self, page: NonNull<u8>, layout: Layout) {
unsafe { self.deallocate(page, layout) }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum PageKind {
Internal,
Leaf,
Root,
}
impl PageKind {
pub(crate) fn allocate(
self,
alloc: &(impl Allocator + ?Sized),
layout: Layout,
) -> Result<NonNull<u8>, AllocError> {
match self {
Self::Internal => alloc.allocate_internal(layout),
Self::Leaf => alloc.allocate_leaf(layout),
Self::Root => alloc.allocate_root(layout),
}
}
pub(crate) unsafe fn deallocate(
self,
alloc: &(impl Allocator + ?Sized),
page: NonNull<u8>,
layout: Layout,
) {
unsafe {
match self {
Self::Internal => alloc.deallocate_internal(page, layout),
Self::Leaf => alloc.deallocate_leaf(page, layout),
Self::Root => alloc.deallocate_root(page, layout),
}
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Global;
unsafe impl Allocator for Global {
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
if layout.size() == 0 {
return Err(AllocError);
}
NonNull::new(unsafe { alloc::alloc::alloc_zeroed(layout) }).ok_or(AllocError)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { alloc::alloc::dealloc(ptr.as_ptr(), layout) }
}
}
unsafe impl<A: Allocator + ?Sized> Allocator for &A {
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
(**self).allocate_zeroed(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { (**self).deallocate(ptr, layout) }
}
fn allocate_internal(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
(**self).allocate_internal(layout)
}
unsafe fn deallocate_internal(&self, page: NonNull<u8>, layout: Layout) {
unsafe { (**self).deallocate_internal(page, layout) }
}
fn allocate_leaf(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
(**self).allocate_leaf(layout)
}
unsafe fn deallocate_leaf(&self, page: NonNull<u8>, layout: Layout) {
unsafe { (**self).deallocate_leaf(page, layout) }
}
fn allocate_root(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
(**self).allocate_root(layout)
}
unsafe fn deallocate_root(&self, page: NonNull<u8>, layout: Layout) {
unsafe { (**self).deallocate_root(page, layout) }
}
fn allocate_heap(&self, layout: Layout) -> Result<NonNull<u8>, AllocError> {
(**self).allocate_heap(layout)
}
unsafe fn deallocate_heap(&self, page: NonNull<u8>, layout: Layout) {
unsafe { (**self).deallocate_heap(page, layout) }
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AllocError;
impl fmt::Display for AllocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("memory allocation failed")
}
}
impl Error for AllocError {}
pub struct InsertError<K, V> {
key: K,
value: V,
layout: Layout,
}
impl<K, V> InsertError<K, V> {
pub(crate) fn new(key: K, value: V, layout: Layout) -> Self {
Self { key, value, layout }
}
pub fn into_entry(self) -> (K, V) {
(self.key, self.value)
}
pub(crate) fn handle_alloc_error(self) -> ! {
alloc::alloc::handle_alloc_error(self.layout)
}
}
impl<K, V> From<InsertError<K, V>> for AllocError {
fn from(_: InsertError<K, V>) -> Self {
AllocError
}
}
impl<K, V> fmt::Debug for InsertError<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("InsertError").finish_non_exhaustive()
}
}
impl<K, V> fmt::Display for InsertError<K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&AllocError, f)
}
}
impl<K, V> Error for InsertError<K, V> {}