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();
}
}