use core::cell::Cell;
std::thread_local! {
static LIVE_VALUE_MUTS: Cell<u32> = const { Cell::new(0) };
}
pub(crate) struct LiveGuard;
impl LiveGuard {
pub(crate) fn new() -> Self {
LIVE_VALUE_MUTS.with(|c| c.set(c.get() + 1));
Self
}
}
impl Drop for LiveGuard {
fn drop(&mut self) {
LIVE_VALUE_MUTS.with(|c| c.set(c.get() - 1));
}
}
pub(crate) fn assert_no_live_guards() {
let n = LIVE_VALUE_MUTS.with(|c| c.get());
if n == 0 {
return;
}
std::eprintln!(
"contract_return with {n} live deferred-write storage guard(s): on \
a real guest the terminal Return syscall skips Drop, silently \
discarding their storage writes. Drop the guard(s) before \
returning."
);
#[cfg(feature = "dev")]
std::panic::panic_any(
thruput_native_exec::invoke_error::unrecoverable_error(),
);
#[cfg(not(feature = "dev"))]
panic!("contract_return with {n} live deferred-write storage guard(s)");
}
pub(crate) struct FrameGuardReset(u32);
impl FrameGuardReset {
pub(crate) fn new() -> Self {
Self(LIVE_VALUE_MUTS.with(|c| c.replace(0)))
}
}
impl Drop for FrameGuardReset {
fn drop(&mut self) {
let saved = self.0;
LIVE_VALUE_MUTS.with(|c| c.set(saved));
}
}