use core::alloc::Layout;
use core::cell::Cell;
use core::marker::PhantomData;
use core::ops::Deref;
use core::ptr::NonNull;
use super::Owner;
#[cfg(all(test, not(loom)))]
mod tests;
pub(crate) struct BlockRc<T> {
ptr: NonNull<Block<T>>,
owns: PhantomData<Block<T>>,
}
struct Block<T> {
count: Cell<usize>,
owner: Owner,
value: T,
}
impl<T> Unpin for BlockRc<T> {}
impl<T> BlockRc<T> {
#[inline]
pub(crate) fn new(value: T) -> Self {
let (ptr, owner) = super::alloc(Layout::new::<Block<T>>());
let ptr = ptr.cast::<Block<T>>();
unsafe {
ptr.as_ptr().write(Block {
count: Cell::new(1),
owner,
value,
});
}
Self {
ptr,
owns: PhantomData,
}
}
fn block(&self) -> &Block<T> {
unsafe { self.ptr.as_ref() }
}
}
impl<T> Clone for BlockRc<T> {
#[inline]
fn clone(&self) -> Self {
let count = self.block().count.get();
if count == usize::MAX {
std::process::abort();
}
self.block().count.set(count + 1);
Self {
ptr: self.ptr,
owns: PhantomData,
}
}
}
impl<T> Deref for BlockRc<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.block().value
}
}
impl<T> Drop for BlockRc<T> {
#[inline]
fn drop(&mut self) {
let count = self.block().count.get() - 1;
self.block().count.set(count);
if count == 0 {
self.drop_last();
}
}
}
impl<T> BlockRc<T> {
#[inline(never)]
fn drop_last(&mut self) {
let owner = self.block().owner;
unsafe {
core::ptr::drop_in_place(self.ptr.as_ptr());
super::free(self.ptr.cast(), Layout::new::<Block<T>>(), owner);
}
}
}