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