use core::ptr::NonNull;
use allocator_api2::alloc::Allocator;
use super::constants::CHUNK_ALIGN;
use super::local_chunk::LocalChunk;
use super::shared_chunk::SharedChunk;
pub(crate) unsafe trait ChunkHeader {
unsafe fn fat_from_header_bytes(header_byte_ptr: *mut u8) -> NonNull<Self>;
}
unsafe impl<A: Allocator + Clone> ChunkHeader for LocalChunk<A> {
#[inline]
unsafe fn fat_from_header_bytes(header_byte_ptr: *mut u8) -> NonNull<Self> {
unsafe {
let header_only: *const Self = core::ptr::slice_from_raw_parts(header_byte_ptr, 0) as *const Self;
let capacity = (*header_only).capacity;
let fat: *mut Self = core::ptr::slice_from_raw_parts_mut(header_byte_ptr, capacity) as *mut Self;
NonNull::new_unchecked(fat)
}
}
}
unsafe impl<A: Allocator + Clone> ChunkHeader for SharedChunk<A> {
#[inline]
unsafe fn fat_from_header_bytes(header_byte_ptr: *mut u8) -> NonNull<Self> {
unsafe {
let header_only: *const Self = core::ptr::slice_from_raw_parts(header_byte_ptr, 0) as *const Self;
let capacity = (*header_only).capacity;
let fat: *mut Self = core::ptr::slice_from_raw_parts_mut(header_byte_ptr, capacity) as *mut Self;
NonNull::new_unchecked(fat)
}
}
}
#[inline]
pub(crate) unsafe fn chunk_of<C: ChunkHeader + ?Sized, T: ?Sized>(value: NonNull<T>) -> NonNull<C> {
let raw = value.as_ptr().cast::<u8>();
let offset_within_chunk = (raw as usize) & (CHUNK_ALIGN - 1);
unsafe {
let header_byte_ptr = raw.byte_sub(offset_within_chunk);
C::fat_from_header_bytes(header_byte_ptr)
}
}
#[inline]
pub(crate) unsafe fn local_chunk_of<T: ?Sized, A: Allocator + Clone>(value: NonNull<T>) -> NonNull<LocalChunk<A>> {
unsafe { chunk_of::<LocalChunk<A>, T>(value) }
}
#[inline]
pub(crate) unsafe fn shared_chunk_of<T: ?Sized, A: Allocator + Clone>(value: NonNull<T>) -> NonNull<SharedChunk<A>> {
unsafe { chunk_of::<SharedChunk<A>, T>(value) }
}