use core::marker::PhantomData;
use core::ptr::NonNull;
use allocator_api2::alloc::Allocator;
use super::local_chunk::LocalChunk;
use super::mask::{local_chunk_of, shared_chunk_of};
use super::shared_chunk::SharedChunk;
mod sealed {
pub trait Sealed {}
}
pub(crate) trait ChunkRecover: sealed::Sealed {
unsafe fn recover_chunk<T: ?Sized>(value: NonNull<T>) -> NonNull<Self>;
}
impl<A: Allocator + Clone> sealed::Sealed for LocalChunk<A> {}
impl<A: Allocator + Clone> ChunkRecover for LocalChunk<A> {
#[inline]
unsafe fn recover_chunk<T: ?Sized>(value: NonNull<T>) -> NonNull<Self> {
unsafe { local_chunk_of::<T, A>(value) }
}
}
impl<A: Allocator + Clone> sealed::Sealed for SharedChunk<A> {}
impl<A: Allocator + Clone> ChunkRecover for SharedChunk<A> {
#[inline]
unsafe fn recover_chunk<T: ?Sized>(value: NonNull<T>) -> NonNull<Self> {
unsafe { shared_chunk_of::<T, A>(value) }
}
}
pub(crate) struct InChunk<T: ?Sized, K: ChunkRecover + ?Sized> {
ptr: NonNull<T>,
_marker: PhantomData<*const K>,
}
impl<T: ?Sized, K: ChunkRecover + ?Sized> InChunk<T, K> {
#[inline]
pub(crate) const unsafe fn new(ptr: NonNull<T>) -> Self {
Self { ptr, _marker: PhantomData }
}
#[inline]
#[must_use]
pub(crate) const fn as_non_null(self) -> NonNull<T> {
self.ptr
}
#[inline]
#[must_use]
pub(crate) const fn as_ptr(self) -> *mut T {
self.ptr.as_ptr()
}
#[inline]
pub(crate) unsafe fn as_ref<'a>(&self) -> &'a T {
unsafe { self.ptr.as_ref() }
}
#[inline]
pub(crate) unsafe fn as_mut<'a>(&mut self) -> &'a mut T {
unsafe { self.ptr.as_mut() }
}
#[inline]
#[must_use]
pub(crate) fn chunk_ptr(self) -> NonNull<K> {
unsafe { K::recover_chunk(self.ptr) }
}
}
impl<T: ?Sized, K: ChunkRecover + ?Sized> Clone for InChunk<T, K> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized, K: ChunkRecover + ?Sized> Copy for InChunk<T, K> {}
pub(crate) type InLocalChunk<T, A> = InChunk<T, LocalChunk<A>>;
pub(crate) type InSharedChunk<T, A> = InChunk<T, SharedChunk<A>>;
#[cfg(test)]
mod tests {
use super::{InLocalChunk, InSharedChunk};
use crate::Arena;
#[test]
fn in_local_chunk_explicit_clone_runs_clone_body() {
let arena = Arena::new();
let rc = arena.alloc_rc(7_u32);
let raw = core::ptr::NonNull::new(rc.as_ptr().cast_mut()).unwrap();
let in_chunk: InLocalChunk<u32, allocator_api2::alloc::Global> = unsafe { InLocalChunk::new(raw) };
let cloned = Clone::clone(&in_chunk);
assert_eq!(cloned.as_ptr(), in_chunk.as_ptr());
}
#[test]
fn in_shared_chunk_explicit_clone_runs_clone_body() {
let arena = Arena::new();
let arc = arena.alloc_arc(11_u32);
let raw = core::ptr::NonNull::new(arc.as_ptr().cast_mut()).unwrap();
let in_chunk: InSharedChunk<u32, allocator_api2::alloc::Global> = unsafe { InSharedChunk::new(raw) };
let cloned = Clone::clone(&in_chunk);
assert_eq!(cloned.as_ptr(), in_chunk.as_ptr());
}
}