use std::collections::BTreeMap;
use std::sync::{Mutex, OnceLock};
static LEDGER: OnceLock<Mutex<BTreeMap<String, u64>>> = OnceLock::new();
fn ledger() -> &'static Mutex<BTreeMap<String, u64>> {
LEDGER.get_or_init(|| Mutex::new(BTreeMap::new()))
}
pub fn ran(key: &str) {
if let Ok(mut g) = ledger().lock() {
*g.entry(key.to_string()).or_insert(0) += 1;
}
}
pub fn snapshot() -> serde_json::Value {
let g = match ledger().lock() {
Ok(g) => g,
Err(_) => return serde_json::json!({}),
};
let map: serde_json::Map<String, serde_json::Value> =
g.iter().map(|(k, v)| (k.clone(), serde_json::json!(v))).collect();
serde_json::Value::Object(map)
}
pub fn distinct() -> usize {
ledger().lock().map(|g| g.len()).unwrap_or(0)
}
pub fn count(key: &str) -> u64 {
ledger().lock().map(|g| g.get(key).copied().unwrap_or(0)).unwrap_or(0)
}
pub fn reset() {
if let Ok(mut g) = ledger().lock() {
g.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn records_and_snapshots_real_counts() {
reset();
ran("PopGraphTab::ui");
ran("PopGraphTab::ui");
ran("PopGraphTab::ctl:11M");
let s = snapshot();
assert_eq!(s["PopGraphTab::ui"].as_u64(), Some(2), "ui ran twice");
assert_eq!(s["PopGraphTab::ctl:11M"].as_u64(), Some(1), "the 11M button handler ran once");
assert_eq!(count("PopGraphTab::ctl:11M"), 1);
assert_eq!(count("never"), 0, "an unrun key reads 0");
assert_eq!(distinct(), 2, "two distinct keys ran");
assert!(s.is_object());
}
#[test]
fn reset_clears_the_ledger() {
ran("a::b");
reset();
assert_eq!(distinct(), 0);
assert_eq!(count("a::b"), 0);
}
}