basin2_lib/ilib/
atomic_set.rs1use std::ops::Deref;
2use std::fmt::{Debug, self};
3use std::sync::atomic::{ AtomicPtr, Ordering };
4use std::ptr::null_mut;
5
6pub struct AtomicSet<T: Send + Sync + Sized> {
9 item: AtomicPtr<T>,
10}
11
12impl<T: Send + Sync + Sized> Default for AtomicSet<T> {
13 fn default() -> AtomicSet<T> {
14 AtomicSet::new()
15 }
16}
17
18impl<T: Send + Sync + Sized> Deref for AtomicSet<T> {
19 type Target = T;
20 fn deref(&self) -> &T {
21 self.get()
22 }
23}
24
25impl<T: Debug + Send + Sync + Sized> Debug for AtomicSet<T> {
26 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27 (**self).fmt(f)
28 }
29}
30
31impl<T: Clone + Send + Sync + Sized> Clone for AtomicSet<T> {
32 fn clone(&self) -> Self {
33 let ptr = self.item.load(Ordering::Relaxed);
34 let ptr = if ptr == null_mut::<T>() {
35 ptr
36 } else {
37 Box::into_raw(Box::new(unsafe { ptr.as_ref() }.unwrap().clone()))
38 };
39 AtomicSet {
40 item: AtomicPtr::new(ptr),
41 }
42 }
43}
44
45impl<T: PartialEq + Send + Sync + Sized> PartialEq for AtomicSet<T> {
46 fn eq(&self, other: &Self) -> bool {
47 return **self == **other;
48 }
49}
50
51impl<T: Send + Sync + Sized> Drop for AtomicSet<T> {
52 fn drop(&mut self) {
53 let ptr = self.item.load(Ordering::Relaxed);
54 if ptr != null_mut::<T>() {
55 drop(unsafe { Box::from_raw(ptr) });
56 }
57 }
58}
59
60impl<T: Send + Sync + Sized> AtomicSet<T> {
61
62 pub fn new() -> AtomicSet<T> {
63 AtomicSet {
64 item: AtomicPtr::new(null_mut::<T>()),
65 }
66 }
67
68 pub fn try_set(&self, item: T) -> bool {
69 let boxed_item = Box::into_raw(Box::new(item));
70 let null_ptr = null_mut::<T>();
71 if self.item.compare_and_swap(null_ptr, boxed_item, Ordering::Relaxed) != null_ptr {
72 drop(unsafe { Box::from_raw(boxed_item) });
73 return false;
74 }
75 return true;
76 }
77
78 pub fn set(&self, item: T) {
79 let boxed_item = Box::into_raw(Box::new(item));
80 let null_ptr = null_mut::<T>();
81 if self.item.compare_and_swap(null_ptr, boxed_item, Ordering::Relaxed) != null_ptr {
82 drop(unsafe { Box::from_raw(boxed_item) });
83 panic!("attempted to re-set AtomicSet!");
84 }
85 }
86
87 pub fn get(&self) -> &T {
88 let ptr = self.item.load(Ordering::Relaxed);
89 if ptr == null_mut::<T>() {
90 panic!("attempt to get value of unset AtomicSet!");
91 }
92 unsafe { ptr.as_ref() }.unwrap()
93 }
94
95 pub fn is_set(&self) -> bool {
96 let ptr = self.item.load(Ordering::Relaxed);
97 ptr != null_mut::<T>()
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn test_can_set() {
107 let setter = AtomicSet::<u32>::new();
108 assert_eq!(setter.is_set(), false);
109 setter.set(12345);
110 assert_eq!(setter.is_set(), true);
111
112 assert_eq!(*setter.get(), 12345);
113 assert_eq!(*setter.get(), 12345);
114 assert_eq!(*setter, 12345);
115 assert_eq!(setter.is_set(), true);
116 }
117
118 #[test]
119 #[should_panic]
120 fn test_cannot_set_twice() {
121 let setter = AtomicSet::<u32>::new();
122 setter.set(12345);
123 setter.set(12345);
124 }
125}