use std::cell::RefCell;
use super::backend::Backend;
use super::formula::{Formula, Precision};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Service {
pub formula: Formula,
pub precision: Precision,
pub backend: Option<Backend>,
pub count: u64,
}
thread_local! {
static TALLY: RefCell<Option<Vec<Service>>> = const { RefCell::new(None) };
}
pub(super) fn note(formula: Formula, precision: Precision, backend: Option<Backend>) {
TALLY.with(|cell| {
let mut tally = cell.borrow_mut();
let Some(rows) = tally.as_mut() else {
return;
};
if let Some(row) = rows.iter_mut().find(|row| {
row.formula == formula && row.precision == precision && row.backend == backend
}) {
row.count += 1;
return;
}
rows.push(Service {
formula,
precision,
backend,
count: 1,
});
});
}
pub(super) fn tallied<Output>(body: impl FnOnce() -> Output) -> (Output, Vec<Service>) {
struct Scope {
previous: Option<Vec<Service>>,
}
impl Drop for Scope {
fn drop(&mut self) {
TALLY.with(|cell| *cell.borrow_mut() = self.previous.take());
}
}
let scope = Scope {
previous: TALLY.with(|cell| cell.borrow_mut().replace(Vec::new())),
};
let output = body();
let rows = TALLY
.with(|cell| cell.borrow_mut().take())
.expect("the scope installed a tally");
drop(scope);
(output, rows)
}
#[cfg(test)]
#[path = "tests/service_tests.rs"]
mod tests;