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}