use alloc::alloc::Layout;
use core::fmt::{self, Display, Formatter};
use core::mem::MaybeUninit;
use core::ptr::{self, NonNull};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AllocError;
impl Display for AllocError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "memory allocation failed")
}
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "std")))]
impl std::error::Error for AllocError {}
pub unsafe trait Allocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
fn allocate_zeroed(
&self,
layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
let ptr = self.allocate(layout)?;
unsafe {
let len = (&*(ptr.as_ptr() as *mut [MaybeUninit<u8>])).len();
(ptr.as_ptr() as *mut u8).write_bytes(0_u8, len);
}
Ok(ptr)
}
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
let new = self.allocate(new_layout)?;
unsafe {
(new.as_ptr() as *mut u8)
.copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size());
self.deallocate(ptr, old_layout);
}
Ok(new)
}
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
let new = self.allocate(new_layout)?;
unsafe {
let len = (&*(new.as_ptr() as *mut [MaybeUninit<u8>])).len();
(new.as_ptr() as *mut u8)
.copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size());
(new.as_ptr() as *mut u8)
.add(old_layout.size())
.write_bytes(0_u8, len - old_layout.size());
self.deallocate(ptr, old_layout);
}
Ok(new)
}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
let new = self.allocate(new_layout)?;
unsafe {
let len = (&*(new.as_ptr() as *mut [MaybeUninit<u8>])).len();
(new.as_ptr() as *mut u8)
.copy_from_nonoverlapping(ptr.as_ptr(), len);
self.deallocate(ptr, old_layout);
}
Ok(new)
}
fn by_ref(&self) -> &Self
where
Self: Sized,
{
self
}
}
unsafe impl<A> Allocator for &A
where
A: Allocator + ?Sized,
{
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
A::allocate(*self, layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe {
A::deallocate(*self, ptr, layout);
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Global;
unsafe impl Allocator for Global {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
assert!(layout.size() != 0);
NonNull::new(ptr::slice_from_raw_parts_mut(
unsafe { alloc::alloc::alloc(layout) },
layout.size(),
))
.ok_or(AllocError)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { alloc::alloc::dealloc(ptr.as_ptr(), layout) };
}
}