lockfree/removable.rs
1use std::{
2 fmt,
3 mem::{replace, uninitialized, ManuallyDrop},
4 sync::atomic::{
5 AtomicBool,
6 Ordering::{self, *},
7 },
8};
9
10/// A shared removable value. You can only take values from this type (no
11/// insertion allowed). No extra allocation is necessary. It may be useful for
12/// things like shared `thread::JoinHandle`s.
13pub struct Removable<T> {
14 item: ManuallyDrop<T>,
15 present: AtomicBool,
16}
17
18impl<T> Removable<T> {
19 /// Creates a removable item with the passed argument as a present value.
20 pub fn new(val: T) -> Self {
21 Self { item: ManuallyDrop::new(val), present: AtomicBool::new(true) }
22 }
23
24 /// Creates a removable item with no present value.
25 pub fn empty() -> Self {
26 Self {
27 // This is safe because we will only read from the item if present
28 // is true. Present will only be true if we write to it.
29 item: ManuallyDrop::new(unsafe { uninitialized() }),
30 present: AtomicBool::new(false),
31 }
32 }
33
34 /// Replaces the stored value with a given one and returns the old value.
35 /// Requires a mutable reference since the type of the value might not be
36 /// atomic.
37 pub fn replace(&mut self, val: Option<T>) -> Option<T> {
38 let present = self.present.get_mut();
39
40 match val {
41 Some(val) => {
42 if *present {
43 Some(replace(&mut *self.item, val))
44 } else {
45 // Safe because we get the pointer from a valid reference
46 // and present will only be false if item is uninitialized.
47 *present = true;
48 unsafe { (&mut *self.item as *mut T).write(val) };
49 None
50 }
51 },
52
53 None if *present => {
54 // Safe because we get the pointer from a valid reference
55 // and present will only be false if item is uninitialized.
56 *present = false;
57 Some(unsafe { (&*self.item as *const T).read() })
58 },
59
60 None => None,
61 }
62 }
63
64 /// Tries to get a mutable reference to the stored value. If the value was
65 /// not present, `None` is returned.
66 pub fn get_mut(&mut self) -> Option<&mut T> {
67 if *self.present.get_mut() {
68 Some(&mut *self.item)
69 } else {
70 None
71 }
72 }
73
74 /// Tests if the stored value is present. Note that there are no guarantees
75 /// that `take` will be successful if this method returns `true` because
76 /// some other thread could take the value meanwhile.
77 pub fn is_present(&self, ordering: Ordering) -> bool {
78 self.present.load(ordering)
79 }
80
81 /// Tries to take the value. If no value was present in first place, `None`
82 /// is returned. In terms of memory ordering, `AcqRel` should be enough.
83 pub fn take(&self, ordering: Ordering) -> Option<T> {
84 if self.present.swap(false, ordering) {
85 // Safe because if present was true, the memory was initialized. All
86 // other reads won't happen because we set present to false.
87 Some(unsafe { (&*self.item as *const T).read() })
88 } else {
89 None
90 }
91 }
92}
93
94impl<T> fmt::Debug for Removable<T> {
95 fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
96 write!(
97 fmtr,
98 "Removable {} present: {:?} {}",
99 '{',
100 self.is_present(Relaxed),
101 '}'
102 )
103 }
104}
105
106impl<T> Default for Removable<T> {
107 fn default() -> Self {
108 Self::empty()
109 }
110}
111
112impl<T> Drop for Removable<T> {
113 fn drop(&mut self) {
114 if *self.present.get_mut() {
115 // Safe because present will only be true when the memory is
116 // initialized. And now we are at drop.
117 unsafe { ManuallyDrop::drop(&mut self.item) }
118 }
119 }
120}
121
122impl<T> From<Option<T>> for Removable<T> {
123 fn from(opt: Option<T>) -> Self {
124 match opt {
125 Some(item) => Self::new(item),
126 None => Self::empty(),
127 }
128 }
129}
130
131unsafe impl<T> Send for Removable<T> where T: Send {}
132unsafe impl<T> Sync for Removable<T> where T: Send {}