use std::{alloc::Layout, ptr::NonNull};
mod aligned;
mod bump;
mod poly;
mod traits;
pub use aligned::{AlignedAllocator, NotPowerOfTwo};
pub use bump::BumpAllocator;
pub use poly::{CompoundError, Poly, TrustedIter, poly};
pub use traits::{Allocator, AllocatorCore, AllocatorError};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GlobalAllocator;
unsafe impl AllocatorCore for GlobalAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocatorError> {
if layout.size() == 0 {
return Err(AllocatorError);
}
let ptr = unsafe { std::alloc::alloc(layout) };
let ptr = std::ptr::slice_from_raw_parts_mut(ptr, layout.size());
NonNull::new(ptr).ok_or(AllocatorError)
}
unsafe fn deallocate(&self, ptr: NonNull<[u8]>, layout: Layout) {
unsafe { std::alloc::dealloc(ptr.as_ptr().cast::<u8>(), layout) }
}
}
trait DebugAllocator: AllocatorCore + std::fmt::Debug {}
impl<T> DebugAllocator for T where T: AllocatorCore + std::fmt::Debug {}
#[derive(Debug, Clone, Copy)]
pub struct ScopedAllocator<'a> {
allocator: &'a dyn DebugAllocator,
}
impl<'a> ScopedAllocator<'a> {
pub const fn new<T>(allocator: &'a T) -> Self
where
T: AllocatorCore + std::fmt::Debug,
{
Self { allocator }
}
}
impl ScopedAllocator<'static> {
pub const fn global() -> Self {
Self {
allocator: &GlobalAllocator,
}
}
}
unsafe impl AllocatorCore for ScopedAllocator<'_> {
fn allocate(&self, layout: std::alloc::Layout) -> Result<NonNull<[u8]>, AllocatorError> {
self.allocator.allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<[u8]>, layout: std::alloc::Layout) {
unsafe { self.allocator.deallocate(ptr, layout) }
}
}
pub(crate) trait TryClone: Sized {
fn try_clone(&self) -> Result<Self, AllocatorError>;
}
#[cfg(test)]
mod tests {
use super::*;
fn test_alloc<T>() {
let alloc = GlobalAllocator;
let layout = Layout::new::<T>();
let ptr = alloc.allocate(layout).unwrap();
assert_eq!(ptr.len(), layout.size());
assert_eq!(ptr.len(), std::mem::size_of::<T>());
assert_eq!((ptr.as_ptr().cast::<u8>() as usize) % layout.align(), 0);
unsafe { alloc.deallocate(ptr, layout) };
}
#[test]
fn test_global_allocator() {
assert!(GlobalAllocator.allocate(Layout::new::<()>()).is_err());
test_alloc::<(u8,)>();
test_alloc::<(u8, u8)>();
test_alloc::<(u8, u8, u8)>();
test_alloc::<(u8, u8, u8, u8)>();
test_alloc::<(u8, u8, u8, u8, u8)>();
test_alloc::<(u8, u8, u8, u8, u8, u8)>();
test_alloc::<(u8, u8, u8, u8, u8, u8, u8)>();
test_alloc::<(u8, u8, u8, u8, u8, u8, u8, u8)>();
test_alloc::<(u8, u8, u8, u8, u8, u8, u8, u8, u8)>();
test_alloc::<(u16,)>();
test_alloc::<(u16, u16)>();
test_alloc::<(u16, u16, u16)>();
test_alloc::<(u16, u16, u16, u16)>();
test_alloc::<(u16, u16, u16, u16, u16)>();
test_alloc::<(u32,)>();
test_alloc::<(u32, u32)>();
test_alloc::<(u32, u32, u32)>();
test_alloc::<String>();
}
}