#[cfg(debug_assertions)]
use std::cell::Cell;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ArenaStamp {
#[cfg(debug_assertions)]
arena: u64,
#[cfg(debug_assertions)]
generation: u64,
}
impl ArenaStamp {
#[cfg(not(debug_assertions))]
pub(super) const RELEASE: Self = Self {};
}
#[cfg(debug_assertions)]
#[derive(Debug)]
pub(super) struct ArenaIdentity {
id: u64,
generation: Cell<u64>,
}
#[cfg(debug_assertions)]
impl Default for ArenaIdentity {
fn default() -> Self {
static NEXT_ID: AtomicU64 = AtomicU64::new(0);
Self {
id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
generation: Cell::new(0),
}
}
}
#[cfg(debug_assertions)]
impl ArenaIdentity {
pub(super) fn stamp(&self) -> ArenaStamp {
ArenaStamp {
arena: self.id,
generation: self.generation.get(),
}
}
pub(super) fn advance(&mut self) {
let next = self.generation.get() + 1;
self.generation.set(next);
}
pub(super) fn assert_current(&self, stamp: ArenaStamp) {
let current = self.stamp();
assert_eq!(
stamp, current,
"arena-backed value outlived its compile: stamped arena #{} generation {}, \
read against arena #{} generation {}. Every value that crosses a compile \
boundary must be converted to its owned form before `Allocator::reset`.",
stamp.arena, stamp.generation, current.arena, current.generation
);
}
}