use std::collections::BTreeSet;
use std::io::Write;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Mutex;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum Table {
Tcl,
TclInt,
TclPlat,
TclIntPlat,
}
impl Table {
pub fn as_str(self) -> &'static str {
match self {
Table::Tcl => "Tcl",
Table::TclInt => "TclInt",
Table::TclPlat => "TclPlat",
Table::TclIntPlat => "TclIntPlat",
}
}
pub fn names(self) -> &'static [&'static str] {
match self {
Table::Tcl => &super::generated::TCL_NAMES,
Table::TclInt => &super::generated::TCL_INT_NAMES,
Table::TclPlat => &super::generated::TCL_PLAT_NAMES,
Table::TclIntPlat => &super::generated::TCL_INT_PLAT_NAMES,
}
}
pub fn name_of(self, slot: usize) -> &'static str {
self.names().get(slot).copied().unwrap_or("<out of range>")
}
}
static SERVED: AtomicU64 = AtomicU64::new(0);
static LOGGING: AtomicBool = AtomicBool::new(true);
pub fn set_logging(on: bool) {
LOGGING.store(on, Ordering::Relaxed);
}
static TOUCHED: Mutex<BTreeSet<(u8, u16)>> = Mutex::new(BTreeSet::new());
fn touch(table: Table, slot: usize) -> usize {
let mut set = TOUCHED.lock().expect("trace set poisoned");
set.insert((table as u8, slot as u16));
set.len()
}
pub fn record(table: Table, slot: usize) {
let n = SERVED.fetch_add(1, Ordering::Relaxed);
touch(table, slot);
if !LOGGING.load(Ordering::Relaxed) {
return;
}
let mut err = std::io::stderr().lock();
let _ = writeln!(
err,
"tkslot {} {} {} {}",
n,
table.as_str(),
slot,
table.name_of(slot)
);
}
pub fn unimplemented(table: Table, slot: usize) -> ! {
let n = SERVED.load(Ordering::Relaxed);
let distinct = touch(table, slot);
{
let mut err = std::io::stderr().lock();
let _ = writeln!(
err,
"tktrap {} {} {} {}",
n,
table.as_str(),
slot,
table.name_of(slot)
);
let _ = writeln!(
err,
"tkdone {n} calls, {distinct} distinct slots, stopped at {} slot {slot} {}",
table.as_str(),
table.name_of(slot)
);
let _ = err.flush();
}
std::process::abort()
}
pub fn served() -> u64 {
SERVED.load(Ordering::Relaxed)
}
pub fn note(what: &str, text: &str) {
if std::env::var_os("TCLRS_TK_STRINGS").is_none() {
return;
}
let mut err = std::io::stderr().lock();
let _ = writeln!(err, "tktext {what} {text:?}");
}