use alloc::alloc::Layout;
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::mem::{self, MaybeUninit};
use core::ptr::{addr_of_mut, NonNull};
struct Chunk<T, Array> {
items: MaybeUninit<Array>,
next: Option<ChunkRef<T, Array>>,
phantom: PhantomData<T>,
}
#[repr(transparent)]
pub struct ChunkRef<T, Array>(NonNull<Chunk<T, Array>>);
impl<T, Array> PartialEq for ChunkRef<T, Array> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T, Array> Eq for ChunkRef<T, Array> {}
impl<T, Array> Clone for ChunkRef<T, Array> {
fn clone(&self) -> Self {
Self(self.0)
}
}
impl<T, Array> ChunkRef<T, Array> {
pub const CAPACITY: usize = mem::size_of::<Array>() / mem::size_of::<T>();
pub const LAYOUT: Layout = Layout::new::<Chunk<T, Array>>();
pub fn new(prev: Option<Self>) -> Option<Self> {
assert!(mem::align_of::<Array>() >= mem::align_of::<T>());
assert!(mem::size_of::<Array>() % mem::size_of::<T>() == 0);
assert!(Self::LAYOUT.size() > 0);
let ptr: NonNull<Chunk<T, Array>> =
NonNull::new(unsafe { alloc::alloc::alloc(Self::LAYOUT) })?.cast();
unsafe {
addr_of_mut!((*ptr.as_ptr()).next).write(None);
}
let chunk = Self(ptr);
if let Some(mut prev) = prev {
prev.set_next(Some(chunk.clone()));
}
Some(chunk)
}
pub fn as_ptr(&self) -> NonNull<()> {
self.0.cast()
}
pub unsafe fn from_ptr(ptr: NonNull<()>) -> Self {
Self(ptr.cast())
}
pub fn next(&self) -> Option<Self> {
unsafe { &(*self.0.as_ptr()).next }.clone()
}
fn set_next(&mut self, next: Option<Self>) {
unsafe {
(*self.0.as_ptr()).next = next;
}
}
pub unsafe fn dealloc(self) {
drop(unsafe { Box::from_raw(self.0.as_ptr()) });
}
pub unsafe fn get(&self, i: usize) -> NonNull<T> {
unsafe { self.get_uninit(i).cast() }
}
unsafe fn get_uninit(&self, i: usize) -> NonNull<MaybeUninit<T>> {
debug_assert!(i <= Self::CAPACITY);
let ptr = unsafe { addr_of_mut!((*self.0.as_ptr()).items) };
unsafe { NonNull::new_unchecked(ptr.cast::<MaybeUninit<T>>().add(i)) }
}
pub unsafe fn drop_item(&mut self, i: usize) {
unsafe {
self.get(i).as_ptr().drop_in_place();
}
}
pub unsafe fn drop_all(&mut self) {
for i in 0..Self::CAPACITY {
unsafe {
self.drop_item(i);
}
}
}
}