#![feature(allocator_api)]
#![cfg_attr(test, feature(pointer_is_aligned_to))]
use std::{
alloc::{AllocError, Allocator, Global, Layout},
ptr::NonNull,
};
pub struct Align<const ALIGN: usize, A = Global> {
inner: A,
}
impl<const ALIGN: usize> Align<ALIGN, Global> {
pub const fn new() -> Self {
Self::wrap(Global)
}
}
impl<const ALIGN: usize, A> Align<ALIGN, A> {
pub const fn wrap(inner: A) -> Self {
Self { inner }
}
}
impl<const ALIGN: usize, A> Default for Align<ALIGN, A>
where
A: Default,
{
fn default() -> Self {
Self::wrap(A::default())
}
}
impl<const ALIGN: usize, A> Align<ALIGN, A> {
fn align_layout(layout: Layout) -> Layout {
layout.align_to(ALIGN).unwrap()
}
}
unsafe impl<const ALIGN: usize, A> Allocator for Align<ALIGN, A>
where
A: Allocator,
{
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.inner.allocate(Self::align_layout(layout))
}
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
self.inner.allocate_zeroed(Self::align_layout(layout))
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
unsafe { self.inner.deallocate(ptr, Self::align_layout(layout)) }
}
unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe {
self.inner.grow(
ptr,
Self::align_layout(old_layout),
Self::align_layout(new_layout),
)
}
}
unsafe fn grow_zeroed(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe {
self.inner.grow_zeroed(
ptr,
Self::align_layout(old_layout),
Self::align_layout(new_layout),
)
}
}
unsafe fn shrink(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError> {
unsafe {
self.inner.shrink(
ptr,
Self::align_layout(old_layout),
Self::align_layout(new_layout),
)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn aligned_vec() {
let mut vec = Vec::<u32, Align<4096, Global>>::new_in(Align::default());
vec.push(1);
assert!(vec.as_ptr().is_aligned_to(4096));
}
}