use std::cmp;
use std::mem;
use std::usize;
use std::alloc::{self, LayoutErr};
#[inline]
fn layout_err() -> LayoutErr {
alloc::Layout::from_size_align(usize::MAX, usize::MAX).unwrap_err()
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) struct Layout {
inner: alloc::Layout,
}
impl Layout {
#[inline]
pub(crate) fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
alloc::Layout::from_size_align(size, align).map(Layout::from)
}
#[inline]
pub(crate) unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
Layout::from(alloc::Layout::from_size_align_unchecked(size, align))
}
#[inline]
pub(crate) fn size(&self) -> usize { self.inner.size() }
#[inline]
pub(crate) fn align(&self) -> usize { self.inner.align() }
#[inline]
pub(crate) fn new<T>() -> Self {
Layout::from(alloc::Layout::new::<T>())
}
#[inline]
pub(crate) 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(crate) fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
let padded_size = self.size().checked_add(self.padding_needed_for(self.align()))
.ok_or(layout_err())?;
let alloc_size = padded_size.checked_mul(n)
.ok_or(layout_err())?;
unsafe {
Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size))
}
}
#[inline]
pub(crate) fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
let new_align = cmp::max(self.align(), next.align());
let pad = self.padding_needed_for(next.align());
let offset = self.size().checked_add(pad)
.ok_or(layout_err())?;
let new_size = offset.checked_add(next.size())
.ok_or(layout_err())?;
let layout = Layout::from_size_align(new_size, new_align)?;
Ok((layout, offset))
}
#[inline]
pub(crate) fn array<T>(n: usize) -> Result<Self, LayoutErr> {
Layout::new::<T>()
.repeat(n)
.map(|(k, offs)| {
debug_assert!(offs == mem::size_of::<T>());
k
})
}
}
impl From<alloc::Layout> for Layout {
#[inline]
fn from(inner: alloc::Layout) -> Layout {
Layout { inner }
}
}
impl From<Layout> for alloc::Layout {
#[inline]
fn from(layout: Layout) -> alloc::Layout {
layout.inner
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum CollectionAllocErr {
CapacityOverflow,
AllocErr,
}
impl From<LayoutErr> for CollectionAllocErr {
#[inline]
fn from(_: LayoutErr) -> Self {
CollectionAllocErr::CapacityOverflow
}
}