use super::asked::Asked;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
pub struct RateRow {
pub key: String,
pub count: u64,
pub bytes: u64,
#[serde(skip_serializing_if = "Asked::is_not_asked", default)]
pub sn_gaps: Asked<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub latency: Option<crate::report::LatencyReport>,
#[serde(skip_serializing_if = "Asked::is_not_asked", default)]
pub unstamped: Asked<u64>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RateReport {
pub selector: String,
pub window_s: f64,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub rows: Vec<RateRow>,
pub total_count: u64,
pub total_bytes: u64,
pub keys: usize,
pub evicted: u64,
pub max_keys: usize,
#[serde(skip_serializing_if = "Asked::is_not_asked", default)]
pub sn_gaps: Asked<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize)]
pub struct LatencySummary {
pub min_us: i64,
pub median_us: i64,
pub p95_us: i64,
pub max_us: i64,
pub samples: usize,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize)]
pub struct LatencyReport {
#[serde(skip_serializing_if = "Option::is_none")]
pub self_stamped: Option<LatencySummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub foreign: Option<LatencySummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unattributable: Option<LatencySummary>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub stampers: Vec<String>,
#[serde(skip_serializing_if = "is_zero", default)]
pub stampers_dropped: u64,
}
fn is_zero(n: &u64) -> bool {
*n == 0
}
impl LatencyReport {
pub fn is_empty(&self) -> bool {
self.self_stamped.is_none() && self.foreign.is_none() && self.unattributable.is_none()
}
pub fn populations(&self) -> Vec<(&'static str, LatencySummary)> {
[
("publisher-stamped", self.self_stamped),
("router-stamped", self.foreign),
("stamper unknown", self.unattributable),
]
.into_iter()
.filter_map(|(label, s)| s.map(|s| (label, s)))
.collect()
}
pub fn caveat(&self) -> String {
let clock = match (self.self_stamped.is_some(), self.foreign.is_some()) {
(true, false) => "the publisher's own HLC",
(false, true) => "an HLC stamped in transit, not the publisher's",
(true, true) => "two different clocks, kept apart below",
(false, false) => "an HLC whose stamper did not identify itself",
};
let mut note = format!(
"arrival wall-clock − {clock}: observed *skewed* latency — it contains \
clock skew, and negative values are the skew evidence, not an error \
(RFC 09 §5.1)"
);
if !self.stampers.is_empty() {
note.push_str(&format!("\nstamped by: {}", self.stampers.join(", ")));
if self.stampers_dropped > 0 {
note.push_str(&format!(" (+{} more not retained)", self.stampers_dropped));
}
}
note
}
}