use std::cell::Cell;
use std::thread::LocalKey;
struct ReentranceGuard {
cell: &'static LocalKey<Cell<bool>>,
}
impl ReentranceGuard {
fn new(cell: &'static LocalKey<Cell<bool>>, fn_name: &str) -> Self {
cell.with(|b| {
assert!(
!b.get(),
"reentrant {fn_name} call detected — this would create aliased &mut references"
);
b.set(true);
});
ReentranceGuard { cell }
}
}
impl Drop for ReentranceGuard {
fn drop(&mut self) {
self.cell.with(|b| b.set(false));
}
}
#[inline]
pub(crate) fn with_active_ptr<T, R>(
ptr_cell: &'static LocalKey<Cell<*mut T>>,
borrow_cell: &'static LocalKey<Cell<bool>>,
fn_name: &str,
missing_msg: &str,
f: impl FnOnce(&mut T) -> R,
) -> R {
let _guard = ReentranceGuard::new(borrow_cell, fn_name);
ptr_cell.with(|cell| {
let ptr = cell.get();
assert!(!ptr.is_null(), "{missing_msg}");
let target = unsafe { &mut *ptr };
f(target)
})
}