use core::{
ptr,
ptr::NonNull,
sync::atomic::{AtomicPtr, Ordering, fence},
};
pub(crate) fn from_nullable<T>(ptr: Nullable<T>) -> *mut T {
ptr.map_or(ptr::null_mut(), NonNull::as_ptr)
}
pub(crate) fn into_nullable<T>(ptr: *mut T) -> Nullable<T> {
NonNull::new(ptr)
}
pub(crate) type Nullable<T> = Option<NonNull<T>>;
#[repr(transparent)]
pub(crate) struct AtomicOption<T>(AtomicPtr<T>);
impl<T> AtomicOption<T> {
#[inline]
pub(crate) fn new(ptr: Nullable<T>) -> AtomicOption<T> {
AtomicOption(AtomicPtr::new(from_nullable(ptr)))
}
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
pub(crate) fn as_raw(&self) -> &AtomicPtr<T> {
&self.0
}
#[inline]
pub(crate) fn load(&self, ordering: Ordering) -> Nullable<T> {
into_nullable(self.0.load(ordering))
}
#[inline]
pub(crate) fn get_mut(&mut self) -> Nullable<T> {
into_nullable(*self.0.get_mut())
}
#[inline]
pub(crate) fn swap(&self, ptr: Nullable<T>, ordering: Ordering) -> Nullable<T> {
into_nullable(self.0.swap(from_nullable(ptr), ordering))
}
#[inline]
pub(crate) fn compare_exchange(
&self,
current: Nullable<T>,
new: Nullable<T>,
success: Ordering,
failure: Ordering,
) -> Result<Nullable<T>, Nullable<T>> {
self.0
.compare_exchange(from_nullable(current), from_nullable(new), success, failure)
.map(into_nullable)
.map_err(into_nullable)
}
#[inline]
pub(crate) fn compare_exchange_weak(
&self,
current: Nullable<T>,
new: Nullable<T>,
success: Ordering,
failure: Ordering,
) -> Result<Nullable<T>, Nullable<T>> {
self.0
.compare_exchange(from_nullable(current), from_nullable(new), success, failure)
.map(into_nullable)
.map_err(into_nullable)
}
#[inline]
pub(crate) fn load_debug(&self) -> Nullable<T> {
self.load(Ordering::Relaxed)
}
#[inline]
pub(crate) fn load_drop(&mut self) -> Nullable<T> {
fence(Ordering::SeqCst);
self.load(Ordering::SeqCst)
}
}
#[repr(transparent)]
pub(crate) struct Atomic<T>(AtomicOption<T>);
impl<T> Atomic<T> {
#[inline]
pub(crate) fn new(ptr: NonNull<T>) -> Atomic<T> {
Atomic(AtomicOption::new(Some(ptr)))
}
#[inline]
#[cfg_attr(any(coverage_nightly, feature = "nightly"), coverage(off))]
pub(crate) fn as_raw(&self) -> &AtomicPtr<T> {
self.0.as_raw()
}
#[inline]
pub(crate) fn load(&self, ordering: Ordering) -> NonNull<T> {
unsafe { self.0.load(ordering).unwrap_unchecked() }
}
#[inline]
pub(crate) fn get_mut(&mut self) -> NonNull<T> {
unsafe { self.0.get_mut().unwrap_unchecked() }
}
#[inline]
pub(crate) fn swap(&self, ptr: NonNull<T>, ordering: Ordering) -> NonNull<T> {
unsafe { self.0.swap(Some(ptr), ordering).unwrap_unchecked() }
}
#[inline]
#[expect(dead_code)]
pub(crate) fn compare_exchange(
&self,
current: NonNull<T>,
new: NonNull<T>,
success: Ordering,
failure: Ordering,
) -> Result<NonNull<T>, NonNull<T>> {
unsafe {
match self
.0
.compare_exchange(Some(current), Some(new), success, failure)
{
Ok(ptr) => Ok(ptr.unwrap_unchecked()),
Err(ptr) => Err(ptr.unwrap_unchecked()),
}
}
}
#[inline]
#[expect(dead_code)]
pub(crate) fn compare_exchange_weak(
&self,
current: NonNull<T>,
new: NonNull<T>,
success: Ordering,
failure: Ordering,
) -> Result<NonNull<T>, NonNull<T>> {
unsafe {
match self
.0
.compare_exchange_weak(Some(current), Some(new), success, failure)
{
Ok(ptr) => Ok(ptr.unwrap_unchecked()),
Err(ptr) => Err(ptr.unwrap_unchecked()),
}
}
}
#[inline]
pub(crate) fn load_debug(&self) -> NonNull<T> {
unsafe { self.0.load_debug().unwrap_unchecked() }
}
#[inline]
pub(crate) fn load_drop(&mut self) -> NonNull<T> {
unsafe { self.0.load_drop().unwrap_unchecked() }
}
}