use std::alloc::{AllocError, Allocator, Global, Layout};
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use crate::Serialize;
pub struct AlignedAlloc<T: Serialize + ?Sized, A: Allocator = Global>(A, PhantomData<T>);
impl<T: Serialize + ?Sized, A: Allocator> AlignedAlloc<T, A> {
pub fn new_in(alloc: A) -> Self {
Self(alloc, PhantomData)
}
}
impl<T: Serialize + ?Sized> Default for AlignedAlloc<T, Global> {
fn default() -> AlignedAlloc<T, Global> {
Self(Global, PhantomData)
}
}
unsafe impl<T: Serialize + ?Sized, A: Allocator> Allocator for AlignedAlloc<T, A> {
fn allocate(&self, mut layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
if layout.align() < T::ALIGN.as_usize() {
if isize::MAX as usize + 1 - T::ALIGN.as_usize() < layout.size() {
return Err(AllocError);
}
layout =
unsafe { Layout::from_size_align_unchecked(layout.size(), T::ALIGN.as_usize()) };
}
self.0.allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, mut layout: Layout) {
unsafe {
if layout.align() < T::ALIGN.as_usize() {
layout = Layout::from_size_align_unchecked(layout.size(), T::ALIGN.as_usize());
}
self.0.deallocate(ptr, layout);
}
}
}
impl<T: Serialize + ?Sized, A: Allocator + Clone> Clone for AlignedAlloc<T, A> {
fn clone(&self) -> AlignedAlloc<T, A> {
AlignedAlloc(self.0.clone(), PhantomData)
}
}
pub fn new_uninit_boxed_slice<T: Serialize + ?Sized>(
heap_size: usize,
) -> Box<[MaybeUninit<u8>], AlignedAlloc<T>> {
Box::new_uninit_slice_in(
size_of::<T::Archived>() + heap_size,
AlignedAlloc(Global, PhantomData),
)
}