use std::alloc::{AllocError, Allocator, Global, Layout}; use std::cmp; use std::ptr::NonNull; /// Aligned memory allocator, using the global allocator as default. #[derive(Clone, Copy, Debug, Default)] pub struct AlignedAlloc { alloc: A, } impl AlignedAlloc { /// Creates a new aligned allocator based on the specified allocator. pub fn new(alloc: A) -> Self { assert!(N.is_power_of_two(), "alignment must be power of two"); Self { alloc } } } unsafe impl Allocator for AlignedAlloc { fn allocate(&self, layout: Layout) -> Result, AllocError> { self.alloc.allocate(aligned_layout::(layout)) } unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { self.alloc.deallocate(ptr, aligned_layout::(layout)) } fn allocate_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc.allocate_zeroed(aligned_layout::(layout)) } unsafe fn grow( &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, ) -> Result, AllocError> { self.alloc.grow(ptr, aligned_layout::(old_layout), aligned_layout::(new_layout)) } unsafe fn grow_zeroed( &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, ) -> Result, AllocError> { self.alloc.grow_zeroed( ptr, aligned_layout::(old_layout), aligned_layout::(new_layout), ) } unsafe fn shrink( &self, ptr: NonNull, old_layout: Layout, new_layout: Layout, ) -> Result, AllocError> { self.alloc.shrink(ptr, aligned_layout::(old_layout), aligned_layout::(new_layout)) } } fn aligned_layout(layout: Layout) -> Layout { // Align to the specified value, but not larger than the layout size rounded // to the next power of two and not smaller than the layout alignment. let align = cmp::min(N, layout.size().next_power_of_two()); unsafe { Layout::from_size_align_unchecked(layout.size(), cmp::max(layout.align(), align)) } }