macro_rules! totals {
(
$(#[$meta:meta])*
$name:ident: $counts:ty => $totals:ty { $($field:ident),+ $(,)? }
) => {
$(#[$meta])*
#[derive(Debug, Default)]
pub(crate) struct $name {
$($field: std::sync::atomic::AtomicU64,)+
}
impl $name {
const FIELDS: usize = [$(stringify!($field)),+].len();
pub(crate) fn add(&self, counts: &$counts) {
use std::sync::atomic::Ordering;
$(
if counts.$field != 0 {
let added = u64::from(counts.$field);
let _ = self.$field.try_update(
Ordering::Release,
Ordering::Relaxed,
|total| Some(total.saturating_add(added)),
);
}
)+
}
pub(crate) fn load(&self) -> $totals {
use std::sync::atomic::Ordering;
let mut totals = <$totals>::default();
$(totals.$field = self.$field.load(Ordering::Acquire);)+
totals
}
}
const _: () = assert!(
std::mem::size_of::<$counts>() == $name::FIELDS * std::mem::size_of::<u32>(),
"total every count the core keeps"
);
const _: () = assert!(
std::mem::size_of::<$totals>() == $name::FIELDS * std::mem::size_of::<u64>(),
"publish every total"
);
};
}
pub(crate) use totals;