use std::cell::Cell;
use std::cell::UnsafeCell;
use std::mem;
use std::mem::MaybeUninit;
#[derive(Debug)]
pub(crate) struct FastCell<T> {
value: UnsafeCell<MaybeUninit<T>>,
init: Cell<bool>,
}
impl<T> Drop for FastCell<T> {
fn drop(&mut self) {
if self.init.get() {
unsafe {
(*self.value.get()).assume_init_drop();
}
}
}
}
impl<T: Default> Default for FastCell<T> {
fn default() -> Self {
Self {
value: UnsafeCell::new(MaybeUninit::new(T::default())),
init: Cell::new(true),
}
}
}
impl<T> FastCell<T> {
pub(crate) fn borrow(&self) -> &T {
debug_assert!(self.init.get());
unsafe { (*self.value.get()).assume_init_ref() }
}
pub(crate) fn try_borrow(&self) -> Option<&T> {
if self.init.get() {
Some(self.borrow())
} else {
None
}
}
pub(crate) unsafe fn get_mut(&self) -> *mut T {
unsafe {
debug_assert!(self.init.get());
(*self.value.get()).as_mut_ptr()
}
}
pub(crate) unsafe fn take(&self) -> T {
unsafe {
assert!(self.init.get());
self.init.set(false);
mem::replace(&mut *self.value.get(), MaybeUninit::zeroed()).assume_init()
}
}
pub(crate) unsafe fn set(&self, value: T) {
unsafe {
assert!(!self.init.get());
self.init.set(true);
*self.value.get() = MaybeUninit::new(value);
}
}
}