#[cfg(debug_assertions)]
mod enabled {
use std::cell::RefCell;
thread_local! {
static HELD: RefCell<Vec<usize>> = const { RefCell::new(Vec::new()) };
}
pub struct HeldLock(usize);
impl HeldLock {
pub fn enter(address: usize) -> Self {
let already_held = HELD
.try_with(|held| held.borrow().contains(&address))
.unwrap_or(false);
assert!(
!already_held,
"this lock is already held by the current thread: the callback of a `with_mut` / \
`with_ref` must not take the same lock again. Take the value out of the lock and \
act on it afterwards - see the `mutable` module docs."
);
let _ = HELD.try_with(|held| held.borrow_mut().push(address));
Self(address)
}
}
impl Drop for HeldLock {
fn drop(&mut self) {
let _ = HELD.try_with(|held| {
let held = &mut *held.borrow_mut();
if let Some(index) = held.iter().rposition(|address| *address == self.0) {
held.remove(index);
}
});
}
}
}
#[cfg(debug_assertions)]
pub(super) fn held_lock<T>(lock: &T) -> enabled::HeldLock {
enabled::HeldLock::enter(std::ptr::from_ref(lock) as usize)
}
#[cfg(not(debug_assertions))]
pub(super) fn held_lock<T>(_lock: &T) {}