use std::sync::atomic::AtomicPtr;
use std::sync::Arc;
use std::mem;
use std::ptr;
use std::ops::Deref;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::sync::atomic::Ordering;
pub struct Atom<P> where P: IntoRawPtr + FromRawPtr {
inner: AtomicPtr<()>,
data: PhantomData<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(unsafe { value.into_raw() }),
data: PhantomData
}
}
pub fn swap(&self, v: P) -> Option<P> {
let new = unsafe { v.into_raw() };
let old = self.inner.swap(new, Ordering::AcqRel);
if !old.is_null() {
Some(unsafe { FromRawPtr::from_raw(old) })
} else {
None
}
}
pub fn take(&self) -> Option<P> {
let old = self.inner.swap(ptr::null_mut(), Ordering::Acquire);
if !old.is_null() {
Some(unsafe { FromRawPtr::from_raw(old) })
} else {
None
}
}
pub fn set_if_none(&self, v: P) -> Option<P> {
let new = unsafe { v.into_raw() };
let old = self.inner.compare_and_swap(ptr::null_mut(), new, Ordering::Release);
if !old.is_null() {
Some(unsafe { FromRawPtr::from_raw(new) })
} else {
None
}
}
pub fn replace_and_set_next(&self, mut value: P) -> bool
where P: GetNextMut<NextPtr=Option<P>> {
unsafe {
let next = value.get_next() as *mut Option<P>;
let raw = value.into_raw();
drop(ptr::read(next));
loop {
let pcurrent = self.inner.load(Ordering::Relaxed);
let current = if pcurrent.is_null() {
None
} else {
Some(FromRawPtr::from_raw(pcurrent))
};
ptr::write(next, current);
let last = self.inner.compare_and_swap(pcurrent, raw, Ordering::AcqRel);
if last == pcurrent {
return last.is_null();
}
}
}
}
pub fn is_none(&self) -> bool {
self.inner.load(Ordering::Relaxed).is_null()
}
}
impl<P> Drop for Atom<P> where P: IntoRawPtr + FromRawPtr {
fn drop(&mut self) {
unsafe {
let ptr = self.inner.load(Ordering::Relaxed);
if !ptr.is_null() {
let _: P = FromRawPtr::from_raw(ptr);
}
}
}
}
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 {
unsafe fn into_raw(self) -> *mut ();
}
pub trait FromRawPtr {
unsafe fn from_raw(ptr: *mut ()) -> Self;
}
impl<T> IntoRawPtr for Box<T> {
#[inline]
unsafe 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]
unsafe 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)
}
}
#[inline]
unsafe fn copy_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S,
ptr: &T) -> &'a T {
mem::transmute(ptr)
}
#[inline]
unsafe fn copy_mut_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S,
ptr: &mut T) -> &'a mut T {
mem::transmute(ptr)
}
#[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) -> Option<P> {
self.inner.set_if_none(v)
}
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) -> bool { self.inner.is_none() }
}
impl<T, P> AtomSetOnce<P>
where P: IntoRawPtr + FromRawPtr + Deref<Target=T> {
pub fn get<'a>(&'a self) -> Option<&'a T> {
let ptr = self.inner.inner.load(Ordering::Acquire);
if ptr.is_null() {
None
} else {
unsafe {
let v: P = FromRawPtr::from_raw(ptr);
let out = copy_lifetime(self, &*v);
mem::forget(v);
Some(out)
}
}
}
}
impl<T> AtomSetOnce<Box<T>> {
pub fn get_mut<'a>(&'a mut self) -> Option<&'a mut T> {
let ptr = self.inner.inner.load(Ordering::Acquire);
if ptr.is_null() {
None
} else {
unsafe {
let mut v: Box<T> = FromRawPtr::from_raw(ptr);
let out = copy_mut_lifetime(self, &mut *v);
mem::forget(v);
Some(out)
}
}
}
}
impl<T> AtomSetOnce<T> where T: Clone+IntoRawPtr+FromRawPtr {
pub fn dup<'a>(&self) -> Option<T> {
let ptr = self.inner.inner.load(Ordering::Acquire);
if ptr.is_null() {
None
} else {
unsafe {
let v: T = FromRawPtr::from_raw(ptr);
let out = v.clone();
mem::forget(v);
Some(out)
}
}
}
}
pub trait GetNextMut {
type NextPtr;
fn get_next(&mut self) -> &mut Self::NextPtr;
}