use crate::{
lich::{Lich, increment},
shroud::Shroud,
sync::{self, AtomicU32, Ordering},
};
use core::{
borrow::Borrow,
marker::PhantomPinned,
mem::ManuallyDrop,
ops::Deref,
pin::Pin,
ptr::{self, NonNull, addr_of, read},
};
pub(crate) const SEVERED: u32 = u32::MAX;
#[derive(Debug, Default)]
pub struct Soul<T: ?Sized> {
_marker: PhantomPinned,
count: AtomicU32,
value: T,
}
impl<T> Soul<T> {
#[cfg(not(loom))]
pub const fn new(value: T) -> Self {
Self {
value,
count: AtomicU32::new(0),
_marker: PhantomPinned,
}
}
#[cfg(loom)]
pub fn new(value: T) -> Self {
Self {
value,
count: AtomicU32::new(0),
_marker: PhantomPinned,
}
}
#[must_use = "discarding the value drops it silently"]
pub fn into_value(self) -> T {
unsafe { read(&ManuallyDrop::new(self).value) }
}
}
impl<T: ?Sized> Soul<T> {
#[must_use = "the Lich is immediately dropped if not used"]
pub fn bind<S: Shroud<T> + ?Sized>(self: Pin<&Self>) -> Lich<S> {
increment(&self.count);
Lich {
count: self.count_ptr(),
value: S::shroud(self.value_ptr()),
}
}
#[must_use]
pub fn is_bound<S: ?Sized>(&self, lich: &Lich<S>) -> bool {
ptr::eq(&self.count, lich.count.as_ptr())
}
#[must_use]
pub fn bindings(&self) -> usize {
let raw = self.count.load(Ordering::Relaxed);
raw.wrapping_add(1).saturating_sub(1) as _
}
pub fn sever<S: Deref<Target = Self>>(this: Pin<S>) -> S {
if sever::<true>(&this.count) {
unsafe { Self::unpin(this) }
} else {
unreachable!()
}
}
#[must_use = "if Err, the Soul has not been severed"]
pub fn try_sever<S: Deref<Target = Self>>(this: Pin<S>) -> Result<S, Pin<S>> {
if sever::<false>(&this.count) {
Ok(unsafe { Self::unpin(this) })
} else {
Err(this)
}
}
unsafe fn unpin<S: Deref<Target = Self>>(this: Pin<S>) -> S {
debug_assert_eq!(this.bindings(), 0);
unsafe { Pin::into_inner_unchecked(this) }
}
fn value_ptr(self: Pin<&Self>) -> NonNull<T> {
unsafe { NonNull::new_unchecked(addr_of!(self.value) as _) }
}
fn count_ptr(self: Pin<&Self>) -> NonNull<AtomicU32> {
unsafe { NonNull::new_unchecked(addr_of!(self.count) as _) }
}
}
impl<T> From<T> for Soul<T> {
fn from(value: T) -> Self {
Self::new(value)
}
}
impl<T: ?Sized> Deref for Soul<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T: ?Sized> AsRef<T> for Soul<T> {
fn as_ref(&self) -> &T {
&self.value
}
}
impl<T: ?Sized> Borrow<T> for Soul<T> {
fn borrow(&self) -> &T {
&self.value
}
}
impl<T: ?Sized> Drop for Soul<T> {
fn drop(&mut self) {
sever::<true>(&self.count);
}
}
fn sever<const FORCE: bool>(count: &AtomicU32) -> bool {
loop {
match count.compare_exchange(0, SEVERED, Ordering::Acquire, Ordering::Relaxed) {
Ok(0) | Err(SEVERED) => break true,
Ok(value) | Err(value) if FORCE => sync::wait(count, value),
Ok(_) | Err(_) => break false,
}
}
}