pub use core::alloc::Layout;
use core::{
convert::{TryFrom, TryInto},
fmt,
mem,
num::NonZeroUsize,
};
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutErr {
private: (),
}
impl From<core::alloc::LayoutErr> for LayoutErr {
#[must_use]
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 {
size: NonZeroUsize,
align: NonZeroUsize,
}
impl NonZeroLayout {
#[inline]
pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
Layout::from_size_align(size, align)?.try_into()
}
#[inline]
#[must_use]
pub const unsafe fn from_size_align_unchecked(size: NonZeroUsize, align: NonZeroUsize) -> Self {
Self { size, align }
}
#[inline]
#[must_use]
pub const fn size(&self) -> NonZeroUsize {
self.size
}
#[inline]
#[must_use]
pub const fn align(&self) -> NonZeroUsize {
self.align
}
#[inline]
pub fn new<T>() -> Result<Self, LayoutErr> {
Layout::new::<T>().try_into()
}
#[inline]
#[must_use]
pub const unsafe fn new_unchecked<T>() -> Self {
Self::from_size_align_unchecked(
NonZeroUsize::new_unchecked(mem::size_of::<T>()),
NonZeroUsize::new_unchecked(mem::align_of::<T>()),
)
}
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Option<Self> {
Layout::for_value(t).try_into().ok()
}
#[inline]
#[must_use]
pub const fn padding_needed_for(&self, align: NonZeroUsize) -> usize {
let len = self.size().get();
let align = align.get();
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 {
debug_assert_ne!(mem::size_of_val(t), 0);
debug_assert_ne!(mem::align_of_val(t), 0);
Self::from_size_align_unchecked(
NonZeroUsize::new_unchecked(mem::size_of_val(t)),
NonZeroUsize::new_unchecked(mem::align_of_val(t)),
)
}
#[inline]
pub fn repeat(&self, n: NonZeroUsize) -> Result<(Self, NonZeroUsize), LayoutErr> {
let padded_size = self
.size()
.get()
.checked_add(self.padding_needed_for(self.align()))
.ok_or(LayoutErr { private: () })?;
let alloc_size = padded_size
.checked_mul(n.get())
.ok_or(LayoutErr { private: () })?;
unsafe {
debug_assert_ne!(alloc_size, 0);
debug_assert_ne!(padded_size, 0);
Ok((
Self::from_size_align_unchecked(
NonZeroUsize::new_unchecked(alloc_size),
self.align(),
),
NonZeroUsize::new_unchecked(padded_size),
))
}
}
#[inline]
pub fn array<T>(n: NonZeroUsize) -> Result<Self, LayoutErr> {
Self::new::<T>()?.repeat(n).map(|(k, offs)| {
debug_assert_eq!(offs.get(), mem::size_of::<T>());
k
})
}
}
impl Into<Layout> for NonZeroLayout {
#[must_use]
fn into(self) -> Layout {
let size = self.size().get();
let align = self.align().get();
debug_assert!(Layout::from_size_align(size, align).is_ok());
unsafe { Layout::from_size_align_unchecked(size, align) }
}
}
impl TryFrom<Layout> for NonZeroLayout {
type Error = LayoutErr;
fn try_from(layout: Layout) -> Result<Self, Self::Error> {
unsafe {
debug_assert_ne!(layout.align(), 0);
Ok(Self::from_size_align_unchecked(
NonZeroUsize::new(layout.size()).ok_or(LayoutErr { private: {} })?,
NonZeroUsize::new_unchecked(layout.align()),
))
}
}
}