pub use core::alloc::Layout;
use core::{
convert::{TryFrom, TryInto},
fmt,
mem,
};
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutErr {
private: (),
}
impl From<core::alloc::LayoutErr> for LayoutErr {
fn from(_: core::alloc::LayoutErr) -> Self {
Self { private: () }
}
}
impl fmt::Display for LayoutErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("invalid parameters to Layout::from_size_align")
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct NonZeroLayout(Layout);
impl NonZeroLayout {
#[inline]
pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
Layout::from_size_align(size, align)?.try_into()
}
#[inline]
pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
Self(Layout::from_size_align_unchecked(size, align))
}
#[inline]
pub fn size(&self) -> usize {
self.0.size()
}
#[inline]
pub fn align(&self) -> usize {
self.0.align()
}
#[inline]
pub fn new<T>() -> Result<Self, LayoutErr> {
Layout::new::<T>().try_into()
}
#[inline]
pub const unsafe fn new_unchecked<T>() -> Self {
Self::from_size_align_unchecked(mem::size_of::<T>(), mem::align_of::<T>())
}
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Result<Self, LayoutErr> {
Layout::for_value(t).try_into()
}
#[inline]
pub fn padding_needed_for(&self, align: usize) -> usize {
let len = self.size();
let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
len_rounded_up.wrapping_sub(len)
}
#[inline]
pub unsafe fn for_value_unchecked<T: ?Sized>(t: &T) -> Self {
Self::from_size_align_unchecked(mem::size_of_val(t), mem::align_of_val(t))
}
#[inline]
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
let padded_size = self
.size()
.checked_add(self.padding_needed_for(self.align()))
.ok_or(LayoutErr { private: () })?;
let alloc_size = padded_size
.checked_mul(n)
.ok_or(LayoutErr { private: () })?;
unsafe {
Ok((
Self::from_size_align_unchecked(alloc_size, self.align()),
padded_size,
))
}
}
#[inline]
pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
Self::new::<T>()?.repeat(n).map(|(k, offs)| {
debug_assert!(offs == mem::size_of::<T>());
k
})
}
}
impl Into<Layout> for NonZeroLayout {
fn into(self) -> Layout {
unsafe { Layout::from_size_align_unchecked(self.size(), self.align()) }
}
}
impl TryFrom<Layout> for NonZeroLayout {
type Error = LayoutErr;
fn try_from(layout: Layout) -> Result<Self, Self::Error> {
let size = layout.size();
if size == 0 {
Err(LayoutErr { private: () })
} else {
unsafe { Ok(Self::from_size_align_unchecked(size, layout.align())) }
}
}
}