#[cfg(feature = "alloc")]
mod global;
#[cfg(feature = "std")]
mod system;
use core::{alloc::Layout, error::Error, fmt, ptr::NonNull};
use crate::polyfill::non_null;
#[cfg(feature = "alloc")]
pub use global::Global;
pub mod compat {
#[cfg(feature = "allocator-api2-02")]
pub use crate::features::allocator_api2_02::AllocatorApi2V02Compat;
#[cfg(feature = "allocator-api2-03")]
pub use crate::features::allocator_api2_03::AllocatorApi2V03Compat;
#[cfg(feature = "allocator-api2-04")]
pub use crate::features::allocator_api2_04::AllocatorApi2V04Compat;
#[cfg(all(feature = "alloc", feature = "nightly-allocator-api"))]
pub use crate::features::nightly_allocator_api::AllocatorNightlyCompat;
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError;
impl Error for AllocError {}
impl fmt::Display for AllocError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("memory allocation failed")
}
}
pub unsafe trait Allocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
let ptr = self.allocate(layout)?;
unsafe { non_null::as_non_null_ptr(ptr).write_bytes(0, ptr.len()) }
Ok(ptr)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout);
unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
);
let new_ptr = self.allocate(new_layout)?;
unsafe {
ptr.copy_to_nonoverlapping(new_ptr.cast(), old_layout.size());
self.deallocate(ptr, old_layout);
}
Ok(new_ptr)
}
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() >= old_layout.size(),
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
);
let new_ptr = self.allocate_zeroed(new_layout)?;
unsafe {
ptr.copy_to_nonoverlapping(new_ptr.cast(), old_layout.size());
self.deallocate(ptr, old_layout);
}
Ok(new_ptr)
}
unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
debug_assert!(
new_layout.size() <= old_layout.size(),
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
);
let new_ptr = self.allocate(new_layout)?;
unsafe {
ptr.copy_to_nonoverlapping(new_ptr.cast(), new_layout.size());
self.deallocate(ptr, old_layout);
}
Ok(new_ptr)
}
#[inline(always)]
fn by_ref(&self) -> &Self
where
Self: Sized,
{
self
}
}
unsafe impl<A> Allocator for &A
where
A: Allocator + ?Sized,
{
#[inline]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate(layout)
}
#[inline]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate_zeroed(layout)
}
#[inline]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { (**self).deallocate(ptr, layout) }
}
#[inline]
unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
unsafe { (**self).grow(ptr, old_layout, new_layout) }
}
#[inline]
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
}
#[inline]
unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
unsafe { (**self).shrink(ptr, old_layout, new_layout) }
}
}
unsafe impl<A> Allocator for &mut A
where
A: Allocator + ?Sized,
{
#[inline]
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate(layout)
}
#[inline]
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
(**self).allocate_zeroed(layout)
}
#[inline]
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { (**self).deallocate(ptr, layout) }
}
#[inline]
unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
unsafe { (**self).grow(ptr, old_layout, new_layout) }
}
#[inline]
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) }
}
#[inline]
unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
unsafe { (**self).shrink(ptr, old_layout, new_layout) }
}
}
#[cfg(test)]
#[derive(Default, Clone)]
pub(crate) struct NoopAllocator;
#[cfg(test)]
unsafe impl Allocator for NoopAllocator {
fn allocate(&self, _layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
Err(AllocError)
}
unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
}
pub(crate) mod box_like {
pub trait Sealed {
type T: ?Sized;
type A;
unsafe fn from_raw_in(ptr: *mut Self::T, allocator: Self::A) -> Self;
}
}
pub trait BoxLike: box_like::Sealed {}