use std::cell::UnsafeCell;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr;
use std::sync::atomic::AtomicPtr;
use std::sync::atomic::Ordering;
use std::sync::Arc;
pub struct Atom<P>
where
P: IntoRawPtr + FromRawPtr,
{
inner: AtomicPtr<()>,
data: PhantomData<UnsafeCell<P>>,
}
impl<P> Debug for Atom<P>
where
P: IntoRawPtr + FromRawPtr,
{
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
write!(f, "atom({:?})", self.inner.load(Ordering::Relaxed))
}
}
impl<P> Atom<P>
where
P: IntoRawPtr + FromRawPtr,
{
pub fn empty() -> Atom<P> {
Atom {
inner: AtomicPtr::new(ptr::null_mut()),
data: PhantomData,
}
}
pub fn new(value: P) -> Atom<P> {
Atom {
inner: AtomicPtr::new(value.into_raw()),
data: PhantomData,
}
}
pub fn swap(&self, v: P, order: Ordering) -> Option<P> {
let new = v.into_raw();
let old = self.inner.swap(new, order);
unsafe { Self::inner_from_raw(old) }
}
pub fn take(&self, order: Ordering) -> Option<P> {
let old = self.inner.swap(ptr::null_mut(), order);
unsafe { Self::inner_from_raw(old) }
}
pub fn set_if_none(&self, v: P, order: Ordering) -> Option<P> {
let new = v.into_raw();
let old = self.inner.compare_and_swap(ptr::null_mut(), new, order);
if !old.is_null() {
Some(unsafe { FromRawPtr::from_raw(new) })
} else {
None
}
}
pub fn replace_and_set_next(
&self,
mut value: P,
load_order: Ordering,
cas_order: Ordering,
) -> bool
where
P: GetNextMut<NextPtr = Option<P>>,
{
let next = value.get_next() as *mut Option<P>;
let raw = value.into_raw();
unsafe { ptr::drop_in_place(next) };
loop {
let pcurrent = self.inner.load(load_order);
let current = unsafe { Self::inner_from_raw(pcurrent) };
unsafe { ptr::write(next, current) };
let last = self.inner.compare_and_swap(pcurrent, raw, cas_order);
if last == pcurrent {
return last.is_null();
}
}
}
pub fn is_none(&self, order: Ordering) -> bool {
self.inner.load(order).is_null()
}
#[inline]
fn inner_into_raw(val: Option<P>) -> *mut () {
match val {
Some(val) => val.into_raw(),
None => ptr::null_mut(),
}
}
#[inline]
unsafe fn inner_from_raw(ptr: *mut ()) -> Option<P> {
if !ptr.is_null() {
Some(FromRawPtr::from_raw(ptr))
} else {
None
}
}
}
impl<P, T> Atom<P>
where
P: IntoRawPtr + FromRawPtr + Deref<Target = T>,
{
pub fn compare_and_swap(
&self,
current: Option<&P>,
new: Option<P>,
order: Ordering,
) -> Result<Option<P>, (Option<P>, *mut P)> {
let pcurrent = Self::inner_as_ptr(current);
let pnew = Self::inner_into_raw(new);
let pprev = self.inner.compare_and_swap(pcurrent, pnew, order);
if pprev == pcurrent {
Ok(unsafe { Self::inner_from_raw(pprev) })
} else {
Err((unsafe { Self::inner_from_raw(pnew) }, pprev as *mut P))
}
}
pub fn compare_exchange(
&self,
current: Option<&P>,
new: Option<P>,
success: Ordering,
failure: Ordering,
) -> Result<Option<P>, (Option<P>, *mut P)> {
let pnew = Self::inner_into_raw(new);
self.inner
.compare_exchange(Self::inner_as_ptr(current), pnew, success, failure)
.map(|pprev| unsafe { Self::inner_from_raw(pprev) })
.map_err(|pprev| (unsafe { Self::inner_from_raw(pnew) }, pprev as *mut P))
}
pub fn compare_exchange_weak(
&self,
current: Option<&P>,
new: Option<P>,
success: Ordering,
failure: Ordering,
) -> Result<Option<P>, (Option<P>, *mut P)> {
let pnew = Self::inner_into_raw(new);
self.inner
.compare_exchange_weak(Self::inner_as_ptr(current), pnew, success, failure)
.map(|pprev| unsafe { Self::inner_from_raw(pprev) })
.map_err(|pprev| (unsafe { Self::inner_from_raw(pnew) }, pprev as *mut P))
}
#[inline]
fn inner_as_ptr(val: Option<&P>) -> *mut () {
match val {
Some(val) => &**val as *const _ as *mut (),
None => ptr::null_mut(),
}
}
}
impl<P> Drop for Atom<P>
where
P: IntoRawPtr + FromRawPtr,
{
fn drop(&mut self) {
self.take(Ordering::Relaxed);
}
}
unsafe impl<P> Send for Atom<P>
where
P: IntoRawPtr + FromRawPtr + Send,
{
}
unsafe impl<P> Sync for Atom<P>
where
P: IntoRawPtr + FromRawPtr + Send,
{
}
pub trait IntoRawPtr {
fn into_raw(self) -> *mut ();
}
pub trait FromRawPtr {
unsafe fn from_raw(ptr: *mut ()) -> Self;
}
impl<T> IntoRawPtr for Box<T> {
#[inline]
fn into_raw(self) -> *mut () {
Box::into_raw(self) as *mut ()
}
}
impl<T> FromRawPtr for Box<T> {
#[inline]
unsafe fn from_raw(ptr: *mut ()) -> Box<T> {
Box::from_raw(ptr as *mut T)
}
}
impl<T> IntoRawPtr for Arc<T> {
#[inline]
fn into_raw(self) -> *mut () {
Arc::into_raw(self) as *mut T as *mut ()
}
}
impl<T> FromRawPtr for Arc<T> {
#[inline]
unsafe fn from_raw(ptr: *mut ()) -> Arc<T> {
Arc::from_raw(ptr as *const () as *const T)
}
}
impl<'a, T> IntoRawPtr for &'a T {
#[inline]
fn into_raw(self) -> *mut () {
self as *const _ as *mut ()
}
}
impl<'a, T> FromRawPtr for &'a T {
#[inline]
unsafe fn from_raw(ptr: *mut ()) -> &'a T {
&*(ptr as *mut T)
}
}
#[inline]
unsafe fn copy_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &T) -> &'a T {
&*(ptr as *const T)
}
#[inline]
#[allow(unknown_lints, mut_from_ref)]
unsafe fn copy_mut_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &mut T) -> &'a mut T {
&mut *(ptr as *mut T)
}
#[derive(Debug)]
pub struct AtomSetOnce<P>
where
P: IntoRawPtr + FromRawPtr,
{
inner: Atom<P>,
}
impl<P> AtomSetOnce<P>
where
P: IntoRawPtr + FromRawPtr,
{
pub fn empty() -> AtomSetOnce<P> {
AtomSetOnce {
inner: Atom::empty(),
}
}
pub fn new(value: P) -> AtomSetOnce<P> {
AtomSetOnce {
inner: Atom::new(value),
}
}
pub fn set_if_none(&self, v: P, order: Ordering) -> Option<P> {
self.inner.set_if_none(v, order)
}
pub fn into_atom(self) -> Atom<P> {
self.inner
}
pub fn atom(&mut self) -> &mut Atom<P> {
&mut self.inner
}
pub fn is_none(&self, order: Ordering) -> bool {
self.inner.is_none(order)
}
}
impl<T, P> AtomSetOnce<P>
where
P: IntoRawPtr + FromRawPtr + Deref<Target = T>,
{
pub fn get(&self, order: Ordering) -> Option<&T> {
let ptr = self.inner.inner.load(order);
let val = unsafe { Atom::inner_from_raw(ptr) };
val.map(|v: P| {
let out = unsafe { copy_lifetime(self, &*v) };
mem::forget(v);
out
})
}
}
impl<T> AtomSetOnce<Box<T>> {
pub fn get_mut(&mut self, order: Ordering) -> Option<&mut T> {
let ptr = self.inner.inner.load(order);
let val = unsafe { Atom::inner_from_raw(ptr) };
val.map(move |mut v: Box<T>| {
let out = unsafe { copy_mut_lifetime(self, &mut *v) };
mem::forget(v);
out
})
}
}
impl<T> AtomSetOnce<T>
where
T: Clone + IntoRawPtr + FromRawPtr,
{
pub fn dup(&self, order: Ordering) -> Option<T> {
let ptr = self.inner.inner.load(order);
let val = unsafe { Atom::inner_from_raw(ptr) };
val.map(|v: T| {
let out = v.clone();
mem::forget(v);
out
})
}
}
pub trait GetNextMut {
type NextPtr;
fn get_next(&mut self) -> &mut Self::NextPtr;
}