use std::sync::OnceLock;
use crate::role::WorkerRole;
use crate::role::ALL_ROLES;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RoleGaugeSample {
pub role: WorkerRole,
pub idle: u64,
pub leased: u64,
pub running: u64,
pub pinned: u64,
pub draining: u64,
}
impl RoleGaugeSample {
#[must_use]
pub const fn busy(&self) -> u64 {
self.leased + self.running + self.pinned + self.draining
}
#[must_use]
pub const fn total(&self) -> u64 {
self.busy() + self.idle
}
}
type DashboardHook = fn(&[RoleGaugeSample]);
static DASHBOARD_HOOK: OnceLock<DashboardHook> = OnceLock::new();
pub fn set_dashboard_hook(hook: DashboardHook) -> bool {
DASHBOARD_HOOK.set(hook).is_ok()
}
pub fn export_dashboard(samples: &[RoleGaugeSample]) {
if let Some(hook) = DASHBOARD_HOOK.get() {
hook(samples);
}
}
#[must_use]
pub fn sample_table(
idle: &[u64; 8],
leased: &[u64; 8],
running: &[u64; 8],
pinned: &[u64; 8],
draining: &[u64; 8],
) -> Vec<RoleGaugeSample> {
ALL_ROLES
.iter()
.enumerate()
.map(|(i, role)| RoleGaugeSample {
role: *role,
idle: idle[i],
leased: leased[i],
running: running[i],
pinned: pinned[i],
draining: draining[i],
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn busy_is_everything_not_idle() {
let s = RoleGaugeSample {
role: WorkerRole::Solver,
idle: 2,
leased: 1,
running: 3,
pinned: 4,
draining: 2,
};
assert_eq!(s.busy(), 10);
assert_eq!(s.total(), 12);
}
#[test]
fn sample_table_covers_all_eight_roles_in_table_order() {
let table = sample_table(
&[1, 2, 3, 4, 0, 0, 0, 0],
&[0; 8],
&[0; 8],
&[0; 8],
&[0; 8],
);
assert_eq!(table.len(), ALL_ROLES.len());
for (row, role) in table.iter().zip(ALL_ROLES) {
assert_eq!(row.role, role);
}
}
#[test]
fn dashboard_hook_receives_the_full_busy_idle_table() {
static SEEN: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
fn hook(samples: &[RoleGaugeSample]) {
let _ = SEEN.set(samples.len());
}
if set_dashboard_hook(hook) {
let table = sample_table(&[1; 8], &[0; 8], &[0; 8], &[0; 8], &[0; 8]);
export_dashboard(&table);
assert_eq!(SEEN.get(), Some(&8), "hook receives all 8 role rows");
}
let table = sample_table(&[1; 8], &[0; 8], &[0; 8], &[0; 8], &[0; 8]);
for row in &table {
assert_eq!(row.busy() + row.idle, row.total());
}
}
}