use std::alloc;
#[derive(Clone, Copy)]
pub struct LayoutHelper {
layout: alloc::Layout,
}
impl LayoutHelper {
pub const fn new<T: Sized>() -> Self {
Self::from_layout(alloc::Layout::new::<T>())
}
pub const fn size(&self) -> usize {
self.layout.size()
}
pub const fn align(&self) -> usize {
self.layout.align()
}
pub const fn from_layout(layout: alloc::Layout) -> Self {
Self { layout }
}
pub const fn into_layout(self) -> alloc::Layout {
self.layout
}
pub const fn from_size_alignment(size: usize, alignment: usize) -> Self {
match alloc::Layout::from_size_align(size, alignment) {
Ok(layout) => Self::from_layout(layout),
Err(_) => panic!("Invalid layout"),
}
}
pub const 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)
}
pub const fn extend(self, next: Self) -> (Self, usize) {
let new_align = match (self.align(), next.align()) {
(l, r) if l < r => r,
(l, _) => l,
};
let pad = self.padding_needed_for(next.align());
let Some(offset) = self.size().checked_add(pad) else {
panic!("Invalid layout: offset overflow");
};
let Some(new_size) = offset.checked_add(next.size()) else {
panic!("Invalid layout: size overflow");
};
let layout = Self::from_size_alignment(new_size, new_align);
(layout, offset)
}
}