use std::cell::UnsafeCell;
use std::fmt::{Debug, Display, Formatter};
use std::ptr;
use std::sync::atomic::{AtomicPtr, Ordering};
pub(crate) struct Entry<V> {
value: AtomicPtr<V>,
}
unsafe impl<V: Send> Send for Entry<V> {}
unsafe impl<V: Sync> Sync for Entry<V> {}
impl<V> Entry<V> {
pub fn new(value: V) -> Self {
Self {
value: AtomicPtr::new(Box::into_raw(Box::new(value))),
}
}
#[inline]
pub fn load(&self) -> &V {
unsafe { &*self.value.load(Ordering::Acquire) }
}
#[inline]
pub fn get_mut(&mut self) -> &mut V {
unsafe { &mut **self.value.get_mut() }
}
pub fn swap(&self, value: V) -> *mut V {
self.value.swap(Box::into_raw(Box::new(value)), Ordering::AcqRel)
}
pub fn take(&self) -> V {
let p = self.value.swap(ptr::null_mut(), Ordering::AcqRel);
assert!(!p.is_null(), "entry already taken");
unsafe { *Box::from_raw(p) }
}
}
impl<V> Drop for Entry<V> {
fn drop(&mut self) {
let p = self.value.load(Ordering::Relaxed);
if !p.is_null() {
drop(unsafe { Box::from_raw(p) });
}
}
}
impl<V: Debug> Debug for Entry<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.load().fmt(f)
}
}
impl<V: Display> Display for Entry<V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.load().fmt(f)
}
}
pub(crate) struct Retired<V> {
inner: UnsafeCell<Vec<*mut V>>,
}
unsafe impl<V: Send> Send for Retired<V> {}
unsafe impl<V: Sync> Sync for Retired<V> {}
impl<V> Retired<V> {
pub fn new() -> Self {
Self {
inner: UnsafeCell::new(Vec::new()),
}
}
pub fn push(&self, p: *mut V) {
unsafe {
(*self.inner.get()).push(p);
}
}
}
impl<V> Default for Retired<V> {
fn default() -> Self {
Self::new()
}
}
impl<V> Drop for Retired<V> {
fn drop(&mut self) {
unsafe {
let retired = std::mem::take(&mut *self.inner.get());
for p in retired {
drop(Box::from_raw(p));
}
}
}
}