#![allow(clippy::struct_field_names)]
use core::{alloc::Layout, marker::PhantomData, sync::atomic::AtomicU32};
pub struct HeapObjectLayout<TAllocator> {
pub allocator_offset: usize,
pub strong_offset: usize,
pub weak_offset: usize,
pub data_offset: usize,
_phantom: PhantomData<TAllocator>,
}
#[inline(always)]
const fn max(left: usize, right: usize) -> usize {
if left < right { right } else { left }
}
impl<TAllocator> HeapObjectLayout<TAllocator> {
pub const fn calculate_for_data_size(&self, data_size: usize) -> Layout {
let align = const {
let tmp_align = max(align_of::<u8>(), align_of::<AtomicU32>());
max(tmp_align, align_of::<TAllocator>())
};
unsafe { Layout::from_size_align_unchecked(self.data_offset + data_size, align) }
}
}
#[inline(always)]
const fn layout_for<T>() -> Layout {
unsafe { Layout::from_size_align_unchecked(size_of::<T>(), align_of::<T>()) }
}
pub const fn heap_object_layout<TAllocator>() -> HeapObjectLayout<TAllocator> {
const {
let layout = Layout::new::<()>();
let Ok((layout, allocator_offset)) = layout.extend(layout_for::<TAllocator>()) else {
panic!("Couldn't calculate HeapObjectLayout for TAllocator.");
};
let Ok((layout, strong_offset)) = layout.extend(layout_for::<AtomicU32>()) else {
panic!("Couldn't calculate HeapObjectLayout for AtomicU32.");
};
let Ok((layout, weak_offset)) = layout.extend(layout_for::<AtomicU32>()) else {
panic!("Couldn't calculate HeapObjectLayout for AtomicU32.");
};
let data_layout = unsafe { Layout::from_size_align_unchecked(1, align_of::<u8>()) };
let Ok((_, data_offset)) = layout.extend(data_layout) else {
panic!("Couldn't calculate HeapObjectLayout for u8.");
};
assert!(data_offset <= 1024);
HeapObjectLayout {
allocator_offset,
strong_offset,
weak_offset,
data_offset,
_phantom: PhantomData,
}
}
}