use crate::reentrant::error::Reentered;
use crate::reentrant::reset::Reset;
use core::cell::{Cell, UnsafeCell};
#[derive(Debug, Default)]
pub struct GuardedCell<T: ?Sized> {
active: Cell<bool>,
value: UnsafeCell<T>,
}
impl<T> GuardedCell<T> {
#[inline]
#[must_use]
pub const fn new(value: T) -> Self {
Self {
active: Cell::new(false),
value: UnsafeCell::new(value),
}
}
#[inline]
#[must_use]
pub fn into_inner(self) -> T {
self.value.into_inner()
}
}
impl<T: ?Sized> GuardedCell<T> {
#[inline]
#[must_use]
pub fn is_active(&self) -> bool {
self.active.get()
}
#[inline]
pub fn enter<R>(&self, f: impl FnOnce(&mut T) -> R) -> Result<R, Reentered> {
let _reset = Reset::acquire(&self.active)?;
let value = unsafe { &mut *self.value.get() };
Ok(f(value))
}
#[inline]
pub unsafe fn enter_unguarded<R>(&self, f: impl FnOnce(&mut T) -> R) -> Result<R, Reentered> {
if self.active.get() {
return Err(Reentered);
}
let value = unsafe { &mut *self.value.get() };
Ok(f(value))
}
#[inline]
#[must_use]
pub const fn as_ptr(&self) -> *mut T {
self.value.get()
}
#[inline]
pub fn get_mut(&mut self) -> &mut T {
self.value.get_mut()
}
}
unsafe impl<T: ?Sized + Send> Send for GuardedCell<T> {}