use std::panic::UnwindSafe;
use std::ptr::null_mut;
#[cfg(not(feature = "loom"))]
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;
#[cfg(feature = "loom")]
use loom::sync::atomic::AtomicPtr;
use super::ref_counted::RefCounted;
use super::{Guard, RawPtr, Tag};
#[derive(Debug)]
pub struct AtomicRaw<T> {
ptr: AtomicPtr<RefCounted<T>>,
}
impl<T> AtomicRaw<T> {
#[cfg(not(feature = "loom"))]
#[inline]
#[must_use]
pub const fn new(ptr: RawPtr<'_, T>) -> Self {
let ptr: std::sync::atomic::AtomicPtr<RefCounted<T>> =
AtomicPtr::new(ptr.underlying_ptr().cast_mut());
Self { ptr }
}
#[cfg(feature = "loom")]
#[inline]
#[must_use]
pub fn new(ptr: RawPtr<'_, T>) -> Self {
let ptr: loom::sync::atomic::AtomicPtr<RefCounted<T>> =
AtomicPtr::new(ptr.underlying_ptr().cast_mut());
Self { ptr }
}
#[cfg(not(feature = "loom"))]
#[inline]
#[must_use]
pub const fn null() -> Self {
let ptr: std::sync::atomic::AtomicPtr<RefCounted<T>> = AtomicPtr::new(null_mut());
Self { ptr }
}
#[cfg(feature = "loom")]
#[inline]
#[must_use]
pub fn null() -> Self {
let ptr: loom::sync::atomic::AtomicPtr<RefCounted<T>> = AtomicPtr::new(null_mut());
Self { ptr }
}
#[inline]
#[must_use]
pub fn is_null(&self, order: Ordering) -> bool {
Tag::unset_tag(self.ptr.load(order)).is_null()
}
#[inline]
#[must_use]
pub fn load<'g>(&self, order: Ordering, _guard: &'g Guard) -> RawPtr<'g, T> {
RawPtr::from(self.ptr.load(order))
}
#[inline]
pub fn store(&self, ptr: RawPtr<'_, T>, order: Ordering) {
self.ptr.store(ptr.underlying_ptr().cast_mut(), order);
}
#[inline]
pub fn swap<'g>(
&self,
new: RawPtr<'g, T>,
order: Ordering,
_guard: &'g Guard,
) -> RawPtr<'g, T> {
let desired = new.underlying_ptr().cast_mut();
RawPtr::from(self.ptr.swap(desired, order))
}
#[inline]
#[must_use]
pub fn tag(&self, order: Ordering) -> Tag {
Tag::into_tag(self.ptr.load(order))
}
#[inline]
pub fn fetch_update<'g, F: FnMut(RawPtr<'g, T>) -> Option<RawPtr<'g, T>>>(
&self,
set_order: Ordering,
fetch_order: Ordering,
mut f: F,
_guard: &'g Guard,
) -> Result<RawPtr<'g, T>, RawPtr<'g, T>> {
self.ptr
.fetch_update(
set_order,
fetch_order,
#[inline]
|raw| {
let result = f(RawPtr::from(raw));
result.map(|ptr| ptr.underlying_ptr().cast_mut())
},
)
.map_err(|raw| RawPtr::from(raw))
.map(|raw| RawPtr::from(raw))
}
#[inline]
pub fn compare_exchange<'g>(
&self,
current: RawPtr<'g, T>,
new: RawPtr<'g, T>,
success: Ordering,
failure: Ordering,
_guard: &'g Guard,
) -> Result<RawPtr<'g, T>, RawPtr<'g, T>> {
self.ptr
.compare_exchange(
current.underlying_ptr().cast_mut(),
new.underlying_ptr().cast_mut(),
success,
failure,
)
.map_err(|raw| RawPtr::from(raw))
.map(|raw| RawPtr::from(raw))
}
}
impl<T> Default for AtomicRaw<T> {
#[inline]
fn default() -> Self {
Self::null()
}
}
unsafe impl<T: Send> Send for AtomicRaw<T> {}
unsafe impl<T: Send + Sync> Sync for AtomicRaw<T> {}
impl<T: UnwindSafe> UnwindSafe for AtomicRaw<T> {}