use core::{marker::PhantomData, mem, ptr::NonNull, sync::atomic::AtomicPtr};
use crate::track;
#[repr(transparent)]
#[must_use = "blocks must be used"]
pub(crate) struct BlockRef<'a>(NonNull<()>, PhantomData<&'a ()>);
unsafe impl<'a> Send for BlockRef<'a> {}
unsafe impl<'a> Sync for BlockRef<'a> {}
impl<'a> BlockRef<'a> {
const SLOT_SIZE: usize = mem::size_of::<Option<NonNull<()>>>();
#[must_use = "blocks must be used"]
pub(crate) fn into_raw(self) -> NonNull<()> {
self.0
}
pub(crate) fn as_ptr(&self) -> *mut () {
self.0.as_ptr()
}
pub(crate) unsafe fn from_raw(ptr: NonNull<()>) -> Self {
BlockRef(ptr, PhantomData)
}
pub(super) unsafe fn new(ptr: NonNull<()>) -> Self {
unsafe { Self::from_raw(ptr) }
}
pub fn set_next(&mut self, next: Option<Self>) {
track::undefined(self.0.cast(), Self::SLOT_SIZE);
unsafe { self.0.cast().write(next.map(Self::into_raw)) };
track::no_access(self.0.cast(), Self::SLOT_SIZE);
}
pub fn take_next(&mut self) -> Option<Self> {
let ptr = self.0.cast();
track::defined(self.0.cast(), Self::SLOT_SIZE);
let next = unsafe { ptr.read() };
unsafe { ptr.write(None) };
track::no_access(self.0.cast(), Self::SLOT_SIZE);
next.map(|ptr| unsafe { Self::from_raw(ptr) })
}
pub fn set_tail(&mut self, data: Option<Self>) -> usize {
let mut count = 1;
let mut ptr = self.0.cast();
loop {
track::defined(ptr.cast(), Self::SLOT_SIZE);
let next: Option<NonNull<()>> = unsafe { ptr.read() };
match next {
Some(next) => ptr = next.cast(),
None => {
unsafe { ptr.write(data.map(Self::into_raw)) };
track::no_access(ptr.cast(), Self::SLOT_SIZE);
break;
}
}
count += 1;
track::no_access(ptr.cast(), Self::SLOT_SIZE);
}
count
}
}
#[derive(Default)]
#[repr(transparent)]
pub(super) struct AtomicBlockRef<'a>(AtomicPtr<()>, PhantomData<&'a ()>);
impl<'a> AtomicBlockRef<'a> {
pub(super) fn get(&self) -> &AtomicPtr<()> {
&self.0
}
}