use crate::{NullTag, Shared, Shield, Tag};
use core::{
fmt,
marker::PhantomData,
mem,
sync::atomic::{AtomicUsize, Ordering},
};
fn map_both<T, U, F>(result: Result<T, T>, f: F) -> Result<U, U>
where
F: FnOnce(T) -> U + Copy,
{
result.map(f).map_err(f)
}
#[repr(transparent)]
pub struct Atomic<V, T1 = NullTag, T2 = NullTag>
where
T1: Tag,
T2: Tag,
{
pub(crate) data: AtomicUsize,
_m0: PhantomData<V>,
_m1: PhantomData<T1>,
_m2: PhantomData<T2>,
}
impl<V, T1, T2> Atomic<V, T1, T2>
where
T1: Tag,
T2: Tag,
{
pub unsafe fn from_raw(raw: usize) -> Self {
Self {
data: AtomicUsize::new(raw),
_m0: PhantomData,
_m1: PhantomData,
_m2: PhantomData,
}
}
pub fn new(shared: Shared<'_, V, T1, T2>) -> Self {
unsafe { Self::from_raw(shared.into_raw()) }
}
pub fn null() -> Self {
unsafe { Self::from_raw(0) }
}
pub fn null_vec(len: usize) -> Vec<Self> {
unsafe { mem::transmute(vec![0_usize; len]) }
}
pub fn load<'collector, 'shield, S>(
&self,
ordering: Ordering,
_shield: &'shield S,
) -> Shared<'shield, V, T1, T2>
where
S: Shield<'collector>,
{
let raw = self.data.load(ordering);
unsafe { Shared::from_raw(raw) }
}
pub fn store(&self, data: Shared<'_, V, T1, T2>, ordering: Ordering) {
let raw = data.into_raw();
self.data.store(raw, ordering);
}
pub fn swap<'collector, 'shield, S>(
&self,
new: Shared<'_, V, T1, T2>,
ordering: Ordering,
_shield: &'shield S,
) -> Shared<'shield, V, T1, T2>
where
S: Shield<'collector>,
{
let new_raw = new.into_raw();
let old_raw = self.data.swap(new_raw, ordering);
unsafe { Shared::from_raw(old_raw) }
}
pub fn compare_and_swap<'collector, 'shield, S>(
&self,
current: Shared<'_, V, T1, T2>,
new: Shared<'_, V, T1, T2>,
order: Ordering,
_shield: &'shield S,
) -> Shared<'shield, V, T1, T2>
where
S: Shield<'collector>,
{
let current_raw = current.into_raw();
let new_raw = new.into_raw();
let old_raw = self.data.compare_and_swap(current_raw, new_raw, order);
unsafe { Shared::from_raw(old_raw) }
}
pub fn compare_exchange<'collector, 'shield, S>(
&self,
current: Shared<'_, V, T1, T2>,
new: Shared<'_, V, T1, T2>,
success: Ordering,
failure: Ordering,
_shield: &'shield S,
) -> Result<Shared<'shield, V, T1, T2>, Shared<'shield, V, T1, T2>>
where
S: Shield<'collector>,
{
let current_raw = current.into_raw();
let new_raw = new.into_raw();
let result = self
.data
.compare_exchange(current_raw, new_raw, success, failure);
map_both(result, |raw| unsafe { Shared::from_raw(raw) })
}
pub fn compare_exchange_weak<'collector, 'shield, S>(
&self,
current: Shared<'_, V, T1, T2>,
new: Shared<'_, V, T1, T2>,
success: Ordering,
failure: Ordering,
_shield: &'shield S,
) -> Result<Shared<'shield, V, T1, T2>, Shared<'shield, V, T1, T2>>
where
S: Shield<'collector>,
{
let current_raw = current.into_raw();
let new_raw = new.into_raw();
let result = self
.data
.compare_exchange_weak(current_raw, new_raw, success, failure);
map_both(result, |raw| unsafe { Shared::from_raw(raw) })
}
}
unsafe impl<V, T1, T2> Send for Atomic<V, T1, T2>
where
T1: Tag,
T2: Tag,
{
}
unsafe impl<V, T1, T2> Sync for Atomic<V, T1, T2>
where
T1: Tag,
T2: Tag,
{
}
impl<V, T1, T2> Unpin for Atomic<V, T1, T2>
where
T1: Tag,
T2: Tag,
{
}
impl<V, T1, T2> fmt::Debug for Atomic<V, T1, T2>
where
T1: Tag,
T2: Tag,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::tag;
let data = self.data.load(Ordering::SeqCst);
let lo = tag::read_tag::<T1>(data, tag::TagPosition::Lo);
let hi = tag::read_tag::<T2>(data, tag::TagPosition::Hi);
f.debug_struct("Atomic")
.field("raw", &data)
.field("low_tag", &lo)
.field("high_tag", &hi)
.finish()
}
}