basin2_lib/ilib/
atomic.rs

1use std::fmt::{Debug, self};
2use std::sync::atomic::{ AtomicPtr, Ordering };
3use std::ptr::null_mut;
4
5// once-settable, any-readonly-gettable option
6// useful for read-only structs with after-initialization, one-time fill-in of data
7pub struct Atomic<T: Send + Sync + Clone + Copy + 'static> {
8    item: AtomicPtr<T>,
9}
10
11impl<T: Send + Sync + Clone + Copy + 'static> Default for Atomic<T> {
12    fn default() -> Atomic<T> {
13        Atomic::new()
14    }
15}
16
17impl<T: Debug + Send + Sync + Clone + Copy + 'static> Debug for Atomic<T> {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        self.get().fmt(f)
20    }
21}
22
23impl<T: Send + Sync + Clone + Copy + 'static> Clone for Atomic<T> {
24    fn clone(&self) -> Self {
25        let ptr = self.item.load(Ordering::Relaxed);
26        let ptr = if ptr == null_mut::<T>() {
27            ptr
28        } else {
29            Box::into_raw(Box::new(self.get())) as *mut T
30        };
31        Atomic {
32            item: AtomicPtr::new(ptr),
33        }
34    }
35}
36
37impl<T: PartialEq + Send + Sync + Clone + Copy + 'static> PartialEq for Atomic<T> {
38    fn eq(&self, other: &Self) -> bool {
39        return self.get() == other.get();
40    }
41}
42
43impl<T: Send + Sync + Clone + Copy + 'static> Drop for Atomic<T> {
44    fn drop(&mut self) {
45        let ptr = self.item.load(Ordering::Relaxed);
46        if ptr != null_mut() {
47            drop(unsafe { Box::from_raw(ptr) });
48        }
49    }
50}
51
52impl<T: Send + Sync + Clone + Copy + 'static> From<T> for Atomic<T> {
53    fn from(item: T) -> Atomic<T> {
54        return Atomic {
55            item: AtomicPtr::new(Box::into_raw(Box::new(item)) as *mut T),
56        };
57    }
58}
59
60impl<T: Send + Sync + Clone + Copy + 'static> Atomic<T> {
61    
62    pub fn new() -> Atomic<T> {
63        Atomic {
64            item: AtomicPtr::new(null_mut::<T>()),
65        }
66    }
67
68    pub fn set(&self, item: T) {
69        let boxed_item = Box::into_raw(Box::new(item)) as *mut T;
70        let old_item = self.item.swap(boxed_item, Ordering::Relaxed);
71        if old_item != null_mut() {
72            drop(unsafe { Box::from_raw(old_item) });
73        }
74    }
75
76    pub fn get(&self) -> T {
77        let ptr = self.item.load(Ordering::Relaxed);
78        if ptr == null_mut::<T>() {
79            panic!("attempt to get value of unset Atomic!");
80        }
81        return unsafe { *ptr };
82    }
83
84    pub fn is_set(&self) -> bool {
85        let ptr = self.item.load(Ordering::Relaxed);
86        ptr != null_mut::<T>()
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
95    struct TestStruct {
96        value: u32,
97    }
98
99    #[test]
100    fn test_ref_can_set() {
101        let setter = Atomic::<TestStruct>::new();
102        assert_eq!(setter.is_set(), false);
103        setter.set(TestStruct { value: 243523 });
104        assert_eq!(setter.is_set(), true);
105
106        assert_eq!(setter.get(), TestStruct { value: 243523 });
107        assert_eq!(setter.is_set(), true);
108        let gotten = setter.get();
109        drop(setter);
110        assert_eq!(gotten, TestStruct { value: 243523 });
111    }
112
113}