use std::{
ptr,
sync::{
atomic::{AtomicPtr, Ordering},
Arc,
},
};
#[derive(Debug)]
pub struct AtomicT<T>(AtomicPtr<Arc<T>>);
impl<T> Drop for AtomicT<T> {
fn drop(&mut self) {
let data = self.0.swap(ptr::null_mut(), Ordering::SeqCst);
if !data.is_null() {
unsafe {
let _ = Box::from_raw(data);
}
}
}
}
impl<T> AtomicT<T> {
pub fn new(value: T) -> Self {
let ptr_data = Box::into_raw(Box::new(Arc::new(value)));
AtomicT(AtomicPtr::new(ptr_data))
}
pub fn null() -> AtomicT<T> {
AtomicT(AtomicPtr::new(ptr::null_mut()))
}
#[inline]
pub fn load(&self, order: Ordering) -> Option<Arc<T>> {
let temp = self.0.load(order);
if temp.is_null() {
None
} else {
Some(unsafe { (*temp).clone() })
}
}
#[inline]
pub fn replace(&self, data: Arc<T>, order: Ordering) {
let ptr_data = Box::into_raw(Box::new(data));
let t = self.0.swap(ptr_data, order);
if !t.is_null() {
unsafe {
let _ = Box::from_raw(t);
}
}
}
#[inline]
pub fn swap(&self, data: Arc<T>, order: Ordering) -> Option<Arc<T>> {
let ptr_data = Box::into_raw(Box::new(data));
let temp = self.0.swap(ptr_data, order);
if temp.is_null() {
None
} else {
let t = unsafe { Box::from_raw(temp) };
Some(t.as_ref().clone())
}
}
#[inline]
pub fn set_null(&self, order: Ordering) -> Option<Arc<T>> {
let t = self.0.swap(ptr::null_mut(), order);
if t.is_null() {
None
} else {
Some(unsafe { (*t).clone() })
}
}
}
impl<T> Default for AtomicT<T> {
fn default() -> Self {
AtomicT::null()
}
}
impl<T> From<Arc<T>> for AtomicT<T> {
fn from(data: Arc<T>) -> Self {
let ptr_data = Box::into_raw(Box::new(data));
AtomicT(AtomicPtr::new(ptr_data))
}
}
#[cfg(test)]
mod tests {
use std::{
mem,
sync::{atomic::Ordering, Arc},
};
use crate::syncx::AtomicT;
#[test]
fn drop_self_test() {
{
let p = AtomicT::new(1);
mem::drop(p);
}
{
let p = AtomicT::new(1);
let value_load = p.load(Ordering::SeqCst).expect("");
assert_eq!(1, *value_load.as_ref());
p.replace(Arc::new(2), Ordering::SeqCst);
let value_load = p.load(Ordering::SeqCst).expect("");
assert_eq!(2, *value_load.as_ref());
let value_swap = p.swap(Arc::new(3), Ordering::SeqCst).expect("");
assert_eq!(2, *value_swap.as_ref());
let value_load = p.load(Ordering::SeqCst).expect("");
assert_eq!(3, *value_load.as_ref());
}
}
}