use alloc::rc::Rc;
use core::{
marker::PhantomData,
sync::atomic::{AtomicU32, Ordering},
};
pub(crate) struct UserMemoryAccessDepth(AtomicU32);
impl UserMemoryAccessDepth {
pub(crate) const fn new() -> Self {
Self(AtomicU32::new(0))
}
pub(crate) fn enter(&self) -> UserMemoryAccessGuard<'_> {
self.0
.try_update(Ordering::AcqRel, Ordering::Acquire, |depth| {
depth.checked_add(1)
})
.expect("user-memory access nesting overflow");
UserMemoryAccessGuard {
depth: self,
_not_send: PhantomData,
}
}
pub(crate) fn is_active(&self) -> bool {
self.0.load(Ordering::Acquire) != 0
}
fn leave(&self) {
self.0
.try_update(Ordering::AcqRel, Ordering::Acquire, |depth| {
depth.checked_sub(1)
})
.expect("unbalanced user-memory access scope");
}
}
#[must_use = "dropping the guard closes the user-memory access scope"]
pub(crate) struct UserMemoryAccessGuard<'depth> {
depth: &'depth UserMemoryAccessDepth,
_not_send: PhantomData<Rc<()>>,
}
impl Drop for UserMemoryAccessGuard<'_> {
fn drop(&mut self) {
self.depth.leave();
}
}