use crate::{
error::{ArithOp, InvLayout, LayoutErr, RepeatLayoutError},
helpers::{align_up_unchecked, checked_op},
type_props::USIZE_MAX_NO_HIGH_BIT,
};
use alloc::alloc::Layout;
#[cfg(feature = "metadata")]
#[must_use = "this returns a new pointer"]
pub const fn with_meta<T: ?Sized, U: ?Sized>(ptr: *mut T, meta: *const U) -> *mut U {
core::ptr::from_raw_parts_mut(ptr.cast::<()>(), core::ptr::metadata(meta))
}
#[cfg(feature = "metadata")]
#[must_use = "this returns a new pointer"]
pub const fn with_meta_const<T: ?Sized, U: ?Sized>(ptr: *const T, meta: *const U) -> *const U {
core::ptr::from_raw_parts(ptr.cast::<()>(), core::ptr::metadata(meta))
}
#[must_use]
#[inline]
pub const fn layout_padding_for(layout: Layout, align: usize) -> usize {
if !align.is_power_of_two() {
return usize::MAX;
}
let sz = layout.size();
unsafe { align_up_unchecked(sz, align) - sz }
}
#[must_use]
#[inline]
pub const fn pad_layout_to_align(layout: Layout) -> Layout {
unsafe {
Layout::from_size_align_unchecked(
align_up_unchecked(layout.size(), layout.align()),
layout.align(),
)
}
}
#[inline]
pub const fn repeat_layout(
layout: Layout,
count: usize,
) -> Result<(Layout, usize), RepeatLayoutError> {
let padded = pad_layout_to_align(layout);
match repeat_layout_packed(padded, count) {
Ok(repeated) => Ok((repeated, padded.size())),
Err(e) => Err(e),
}
}
#[inline]
pub const fn repeat_layout_packed(
layout: Layout,
count: usize,
) -> Result<Layout, RepeatLayoutError> {
#[allow(clippy::option_if_let_else)]
let size = match checked_op(layout.size(), ArithOp::Mul, count) {
Ok(s) => s,
Err(e) => return Err(RepeatLayoutError::ArithmeticOverflow(e)),
};
let align = layout.align();
match layout_from_size_align(size, align) {
Ok(layout) => Ok(layout),
Err(r) => Err(RepeatLayoutError::InvalidLayout(InvLayout(size, align, r))),
}
}
#[inline]
const fn layout_from_size_align(size: usize, align: usize) -> Result<Layout, LayoutErr> {
if align == 0 {
return Err(LayoutErr::ZeroAlign);
} else if !align.is_power_of_two() {
return Err(LayoutErr::NonPowerOfTwoAlign);
} else if size > USIZE_MAX_NO_HIGH_BIT + 1 - align {
return Err(LayoutErr::Overflow);
}
Ok(unsafe { Layout::from_size_align_unchecked(size, align) })
}