arc-swap-simple 0.1.0

Atomically swappable Arc
Documentation
use std::sync::{atomic::{AtomicPtr, Ordering}, Arc, RwLock};

#[derive(Debug)]
struct Holder<T>{
    ptr: AtomicPtr<T>,
}
#[derive(Debug)]
pub struct AtomicSwap<T> {
    holder: Arc<Holder<T>>,
}

impl<T> Clone for AtomicSwap<T> {
    fn clone(&self) -> Self {
        Self { holder: self.holder.clone() }
    }
}

impl<T> AtomicSwap<T> {
    pub fn from_value(v: T) -> Self{
        let ptr = Arc::into_raw(Arc::new(v)) as * mut _;
        AtomicSwap { holder: Arc::new(Holder{ptr: AtomicPtr::new(ptr)})}
    }
    
    pub fn load(&self) -> Arc<T> {
        let ptr = self.holder.as_ref().ptr.load(Ordering::Acquire);
        let v = unsafe {Arc::from_raw(ptr)};
        let v2 = v.clone();
        assert_eq!(ptr, Arc::into_raw(v) as * mut _);
        v2
    }
    
    pub fn swap(&self, v: T) -> Arc<T> {
        let new_ptr = Arc::into_raw(Arc::new(v)) as * mut _;
        let ptr = self.holder.as_ref().ptr.swap(new_ptr, Ordering::AcqRel);
        let v = unsafe {Arc::from_raw(ptr)};
        v
    }
}

impl<T> Drop for Holder<T> {
    fn drop(&mut self) {
        let _arc = unsafe {Arc::from_raw(self.ptr.load(Ordering::Acquire))};
    }
}
#[derive(Debug)]
pub struct V{
    pub v: u32
}
impl Drop for V{
    fn drop(&mut self) {
        println!("drop V: {:?}", self);
    }
}
#[inline(never)]
pub fn load_test2(v: &Arc<RwLock<V>>) -> u32{
    v.read().unwrap().v
}

#[cfg(test)]
mod test {
    use std::time::Duration;

    use super::*;
    #[test]
    fn multiple_threads(){
        let v = AtomicSwap::from_value(V{v: 3});
        let v2 = v.clone();
        let t1 = std::thread::spawn(move || {
            println!("t1: {:?}", v2.load());
            std::thread::sleep(Duration::from_millis(100));
            println!("t1: {:?}", v2.load());
        });
        std::thread::sleep(Duration::from_millis(50));
        v.swap(V{v: 10});
        t1.join().unwrap();
    }
}