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