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