use core::{
fmt,
mem::ManuallyDrop,
ops::Deref,
pin::Pin,
ptr::{NonNull, null_mut},
sync::atomic::{AtomicPtr, Ordering, fence},
};
use crate::traits::{Well, WellMut};
pub struct AtomicOption<T: Well>(AtomicPtr<<T as Deref>::Target>);
impl<T: Well> Default for AtomicOption<T> {
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn default() -> Self {
AtomicOption::none()
}
}
impl<T: Well> AtomicOption<T> {
#[inline]
pub fn none() -> AtomicOption<T> {
AtomicOption(AtomicPtr::new(null_mut()))
}
#[inline]
pub fn some(well: T) -> AtomicOption<T> {
AtomicOption(AtomicPtr::new(well.remove().as_ptr()))
}
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
pub unsafe fn as_raw_unchecked(&self) -> &AtomicPtr<<T as Deref>::Target> {
&self.0
}
#[inline]
fn load_value(&self, ordering: Ordering) -> ManuallyDrop<Option<T>> {
let loaded = self.0.load(ordering);
ManuallyDrop::new(NonNull::new(loaded).map(|ptr| unsafe { T::insert(ptr) }))
}
#[inline]
pub fn load(&self, ordering: Ordering) -> Option<&<T as Deref>::Target> {
let loaded = self.0.load(ordering);
match NonNull::new(loaded) {
Some(ptr) => Some(unsafe { ptr.as_ref() }),
None => None,
}
}
#[inline]
pub fn swap(&self, well: T, ordering: Ordering) -> Option<T> {
let old = self.0.swap(well.remove().as_ptr(), ordering);
NonNull::new(old).map(|old| unsafe { T::insert(old) })
}
#[inline]
pub fn take(&self, ordering: Ordering) -> Option<T> {
let old = self.0.swap(null_mut(), ordering);
NonNull::new(old).map(|old| unsafe { T::insert(old) })
}
#[inline]
pub fn insert(&self, well: T, success: Ordering, failure: Ordering) -> Result<(), T> {
let ptr = well.remove();
if self
.0
.compare_exchange(null_mut(), ptr.as_ptr(), success, failure)
.is_err()
{
Err(unsafe { T::insert(ptr) })
} else {
Ok(())
}
}
#[inline]
pub fn insert_weak(&self, well: T, success: Ordering, failure: Ordering) -> Result<(), T> {
let ptr = well.remove();
if self
.0
.compare_exchange_weak(null_mut(), ptr.as_ptr(), success, failure)
.is_err()
{
Err(unsafe { T::insert(ptr) })
} else {
Ok(())
}
}
}
impl<T: WellMut<Target: Unpin>> AtomicOption<T> {
#[inline]
pub fn load_mut(&mut self) -> Option<&mut <T as Deref>::Target> {
let loaded = self.0.get_mut();
match NonNull::new(*loaded) {
Some(mut ptr) => Some(unsafe { ptr.as_mut() }),
None => None,
}
}
}
impl<T: WellMut> AtomicOption<Pin<T>>
where
Pin<T>: Well,
{
#[inline]
pub fn load_mut_pinned(&mut self) -> Option<Pin<&mut <Pin<T> as Deref>::Target>> {
let loaded = self.0.get_mut();
match NonNull::new(*loaded) {
Some(mut ptr) => Some(unsafe { Pin::new_unchecked(ptr.as_mut()) }),
None => None,
}
}
}
impl<T: Well> From<T> for AtomicOption<T> {
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn from(well: T) -> Self {
AtomicOption::some(well)
}
}
impl<T: Well> From<Option<T>> for AtomicOption<T> {
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn from(well: Option<T>) -> Self {
match well {
Some(well) => AtomicOption::some(well),
None => AtomicOption::none(),
}
}
}
impl<T: Well + Clone> AtomicOption<T> {
#[inline]
pub fn load_clone(&self, ordering: Ordering) -> Option<T> {
(*self.load_value(ordering)).clone()
}
}
impl<T: Well> Drop for AtomicOption<T> {
#[inline]
fn drop(&mut self) {
fence(Ordering::SeqCst);
unsafe {
ManuallyDrop::drop(&mut self.load_value(Ordering::SeqCst));
}
}
}
impl<T: Well<Target: fmt::Debug>> fmt::Debug for AtomicOption<T> {
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
}
}
pub struct Atomic<T: Well>(AtomicPtr<<T as Deref>::Target>);
impl<T: Well + Default> Default for Atomic<T> {
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn default() -> Self {
Atomic::new(Default::default())
}
}
impl<T: Well> Atomic<T> {
#[inline]
pub fn new(well: T) -> Atomic<T> {
Atomic(AtomicPtr::new(well.remove().as_ptr()))
}
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
pub unsafe fn as_raw_unchecked(&self) -> &AtomicPtr<<T as Deref>::Target> {
&self.0
}
#[inline]
fn load_value(&self, ordering: Ordering) -> ManuallyDrop<T> {
let loaded = self.0.load(ordering);
ManuallyDrop::new(unsafe { T::insert(NonNull::new_unchecked(loaded)) })
}
#[inline]
pub fn load(&self, ordering: Ordering) -> &<T as Deref>::Target {
let loaded = self.0.load(ordering);
unsafe { NonNull::new_unchecked(loaded).as_ref() }
}
#[inline]
pub fn swap(&self, well: T, ordering: Ordering) -> T {
let old = self.0.swap(well.remove().as_ptr(), ordering);
unsafe { T::insert(NonNull::new_unchecked(old)) }
}
}
impl<T: WellMut<Target: Unpin>> Atomic<T> {
#[inline]
pub fn load_mut(&mut self) -> &mut <T as Deref>::Target {
let loaded = self.0.get_mut();
unsafe { NonNull::new_unchecked(*loaded).as_mut() }
}
}
impl<T: WellMut> Atomic<Pin<T>>
where
Pin<T>: Well,
{
#[inline]
pub fn load_mut_pinned(&mut self) -> Pin<&mut <Pin<T> as Deref>::Target> {
let loaded = self.0.get_mut();
unsafe { Pin::new_unchecked(NonNull::new_unchecked(*loaded).as_mut()) }
}
}
impl<T: Well> From<T> for Atomic<T> {
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn from(well: T) -> Self {
Atomic::new(well)
}
}
impl<T: Well + Clone> Atomic<T> {
#[inline]
pub fn load_clone(&self, ordering: Ordering) -> T {
(*self.load_value(ordering)).clone()
}
}
impl<T: Well> Drop for Atomic<T> {
#[inline]
fn drop(&mut self) {
fence(Ordering::SeqCst);
unsafe {
ManuallyDrop::drop(&mut self.load_value(Ordering::SeqCst));
}
}
}
impl<T: Well<Target: fmt::Debug>> fmt::Debug for Atomic<T> {
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.load(Ordering::Relaxed), f)
}
}