use std::{
fmt,
mem::{replace, uninitialized, ManuallyDrop},
sync::atomic::{
AtomicBool,
Ordering::{self, *},
},
};
pub struct Removable<T> {
item: ManuallyDrop<T>,
present: AtomicBool,
}
impl<T> Removable<T> {
pub fn new(val: T) -> Self {
Self { item: ManuallyDrop::new(val), present: AtomicBool::new(true) }
}
pub fn empty() -> Self {
Self {
item: ManuallyDrop::new(unsafe { uninitialized() }),
present: AtomicBool::new(false),
}
}
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 {
*present = true;
unsafe { (&mut *self.item as *mut T).write(val) };
None
}
},
None if *present => {
*present = false;
Some(unsafe { (&*self.item as *const T).read() })
},
None => None,
}
}
pub fn get_mut(&mut self) -> Option<&mut T> {
if *self.present.get_mut() {
Some(&mut *self.item)
} else {
None
}
}
pub fn is_present(&self, ordering: Ordering) -> bool {
self.present.load(ordering)
}
pub fn take(&self, ordering: Ordering) -> Option<T> {
if self.present.swap(false, ordering) {
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() {
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 {}