atomptr 3.2.0

A safe copy-on-write wrapper around `AtomicPtr` with some extra tricks
Documentation
#![doc = include_str!("../README.md")]

pub mod compare;
mod pointer;
mod snapshot;

pub use crate::pointer::AtomPtr;
pub use crate::snapshot::Ref;

#[cfg(test)]
use std::sync::Arc;

#[cfg(test)]
#[derive(Clone, Debug, PartialEq)]
struct TestStruct {
    name: String,
}

#[test]
fn cloned() {
    let ts = TestStruct {
        name: "Hello".into(),
    };

    let ptr1 = AtomPtr::new(ts);
    let ptr2 = ptr1.clone();

    assert_eq!(ptr1, ptr2);
}

#[test]
fn swap() {
    let ts1 = TestStruct {
        name: "Hello 1".into(),
    };

    let ts2 = TestStruct {
        name: "Hello 2".into(),
    };

    // Make an AtomPtr with some data
    let ptr = AtomPtr::new(ts1.clone());
    assert_eq!(ptr.get_ref().name, "Hello 1".to_string());

    // Swap the data
    let still_ts1 = ptr.swap(ts2);
    assert_eq!(ptr.get_ref().name, "Hello 2".to_string());

    // But the old ref is still valid
    assert_eq!(ts1, still_ts1.take_clone());
}

#[test]
fn compare_exchange() {
    let ts1 = TestStruct {
        name: "Hello 1".into(),
    };

    let ts2 = TestStruct {
        name: "Hello 2".into(),
    };

    let ts3 = TestStruct {
        name: "Hello 3".into(),
    };

    // Make an AtomPtr with some data
    let ptr = AtomPtr::new(ts1.clone());
    assert_eq!(ptr.get_ref().name, "Hello 1".to_string());

    // Swap the data
    let still_ts1 = ptr.compare_exchange(ptr.get_ref(), ts2.clone()).inner();
    assert_eq!(ptr.get_ref().name, "Hello 2".to_string());

    let still_ts2 = ptr.compare_exchange(ptr.get_ref(), ts3).inner();
    assert_eq!(ptr.get_ref().name, "Hello 3".to_string());

    // But the old ref is still valid
    assert_eq!(ts1, still_ts1.take_clone());
    assert_eq!(ts2, still_ts2.take_clone());
}

#[test]
fn take_from_swap() {
    let ts1 = TestStruct {
        name: "Hello 1".into(),
    };

    let ts2 = TestStruct {
        name: "Hello 2".into(),
    };

    // Make an AtomPtr with some data
    let ptr = AtomPtr::new(ts1.clone());
    assert_eq!(ptr.get_ref().name, "Hello 1".to_string());

    // Swap the data
    let still_ts1 = ptr.swap(ts2);
    assert_eq!(ptr.get_ref().name, "Hello 2".to_string());
    assert_eq!(Arc::strong_count(&*still_ts1.inner), 1);

    // We can now also take ownership of the Arc
    let ts1_again = Arc::try_unwrap(*still_ts1.inner).unwrap();
    assert_eq!(ts1_again, ts1);
}

#[test]
fn release() {
    let ts1 = TestStruct {
        name: "Hello world!".into(),
    };
    let ts2 = TestStruct {
        name: "Isn't it lovely outside?".into(),
    };

    let ptr = AtomPtr::new(ts1);

    let first = ptr.get_ref();
    println!("Pointer: {:?}", *first);

    let prev = ptr.compare_exchange(first, ts2);
    if prev.is_success() {
        println!("Successfully swapped pointer values!");

        let second = ptr.get_ref();
        println!("First: {:?}, Second: {:?}", *prev.inner(), *second);
    }
}

#[test]
fn unsafe_mut_ptr() {
    let p: AtomPtr<i32> = AtomPtr::new(5);
    let p_diddy: &mut i32 = unsafe { p.inplace_mut() }.unwrap();
    *p_diddy = 11;

    let p2 = p.get_ref();
    assert!(p2.take_copy() == 11);
}