futures_signals/
atomic.rs

1use std::sync::atomic::{AtomicPtr, Ordering};
2
3
4/*#[derive(Debug)]
5pub(crate) struct Atomic<A> {
6    // TODO only box if the value is too big
7    ptr: AtomicPtr<A>,
8}
9
10impl<A> Atomic<A> {
11    pub(crate) fn new(value: A) -> Self {
12        Self {
13            ptr: AtomicPtr::new(Box::into_raw(Box::new(value))),
14        }
15    }
16
17    fn ptr_swap(&self, value: A) -> *mut A {
18        let new_ptr = Box::into_raw(Box::new(value));
19        self.ptr.swap(new_ptr, Ordering::AcqRel)
20    }
21
22    pub(crate) fn swap(&self, value: A) -> A {
23        let ptr = self.ptr_swap(value);
24        unsafe { *Box::from_raw(ptr) }
25    }
26
27    #[inline]
28    pub(crate) fn store(&self, value: A) {
29        // TODO make this more efficient by using drop_in_place ?
30        drop(self.swap(value));
31    }
32}
33
34impl<A> Atomic<A> where A: Default {
35    #[inline]
36    pub(crate) fn take(&self) -> A {
37        self.swap(Default::default())
38    }
39}
40
41impl<A> Drop for Atomic<A> {
42    fn drop(&mut self) {
43        let ptr = self.ptr.load(Ordering::Acquire);
44
45        // TODO verify the safety of this
46        unsafe { drop(Box::from_raw(ptr)); }
47    }
48}*/
49
50
51/// The same as `Atomic<Option<A>>` except faster and uses less memory.
52///
53/// This is because it represents `None` as a null pointer, which avoids boxing.
54#[derive(Debug)]
55pub(crate) struct AtomicOption<A> {
56    ptr: AtomicPtr<A>,
57}
58
59impl<A> AtomicOption<A> {
60    fn to_ptr(value: Option<A>) -> *mut A {
61        match value {
62            // TODO only box if the value is too big
63            Some(value) => Box::into_raw(Box::new(value)),
64            None => std::ptr::null_mut(),
65        }
66    }
67
68    fn from_ptr(ptr: *mut A) -> Option<A> {
69        if ptr.is_null() {
70            None
71
72        } else {
73            // This is safe because we only do this for pointers created with `Box::into_raw`
74            unsafe { Some(*Box::from_raw(ptr)) }
75        }
76    }
77
78    #[inline]
79    pub(crate) fn new(value: Option<A>) -> Self {
80        Self {
81            ptr: AtomicPtr::new(Self::to_ptr(value)),
82        }
83    }
84
85    pub(crate) fn swap(&self, value: Option<A>) -> Option<A> {
86        let new_ptr = Self::to_ptr(value);
87        let old_ptr = self.ptr.swap(new_ptr, Ordering::AcqRel);
88        Self::from_ptr(old_ptr)
89    }
90
91    #[inline]
92    pub(crate) fn store(&self, value: Option<A>) {
93        // TODO make this more efficient by using drop_in_place ?
94        drop(self.swap(value));
95    }
96
97    #[inline]
98    pub(crate) fn take(&self) -> Option<A> {
99        self.swap(None)
100    }
101}
102
103impl<A> Drop for AtomicOption<A> {
104    fn drop(&mut self) {
105        let ptr = self.ptr.load(Ordering::Acquire);
106
107        if !ptr.is_null() {
108            // This is safe because we only do this for pointers created with `Box::into_raw`
109            unsafe { drop(Box::from_raw(ptr)); }
110        }
111    }
112}