pub const ANNOUNCE_SAMPLE_MAX: usize = 12;
pub const INCOMING_ANNOUNCE_MIN_SAMPLE: usize = 8;
#[derive(Debug, Clone, Default)]
pub struct InterfaceStats {
pub rxb: u64,
pub txb: u64,
pub rx_packets: u64,
pub tx_packets: u64,
pub started: f64,
pub ia_timestamps: Vec<f64>,
pub oa_timestamps: Vec<f64>,
}
impl InterfaceStats {
pub fn record_incoming_announce(&mut self, now: f64) {
self.ia_timestamps.push(now);
if self.ia_timestamps.len() > ANNOUNCE_SAMPLE_MAX {
self.ia_timestamps.remove(0);
}
}
pub fn record_outgoing_announce(&mut self, now: f64) {
self.oa_timestamps.push(now);
if self.oa_timestamps.len() > ANNOUNCE_SAMPLE_MAX {
self.oa_timestamps.remove(0);
}
}
fn compute_frequency(timestamps: &[f64], min_sample: usize) -> f64 {
let sample_count = timestamps.len();
if sample_count <= min_sample {
return 0.0;
}
let span = timestamps[sample_count - 1] - timestamps[0];
if span <= 0.0 {
return 0.0;
}
sample_count as f64 / span
}
pub fn incoming_announce_freq(&self) -> f64 {
Self::compute_frequency(&self.ia_timestamps, INCOMING_ANNOUNCE_MIN_SAMPLE)
}
pub fn outgoing_announce_freq(&self) -> f64 {
Self::compute_frequency(&self.oa_timestamps, 1)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn incoming_frequency_waits_for_minimum_sample_count() {
let mut stats = InterfaceStats::default();
for i in 0..8 {
stats.record_incoming_announce(i as f64);
}
assert_eq!(
stats.incoming_announce_freq(),
0.0,
"incoming announce frequency must stay zero until more than 8 samples exist"
);
}
#[test]
fn announce_frequency_keeps_twelve_samples() {
let mut stats = InterfaceStats::default();
for i in 0..12 {
stats.record_incoming_announce(i as f64);
stats.record_outgoing_announce(i as f64);
}
assert_eq!(stats.ia_timestamps.len(), 12);
assert_eq!(stats.oa_timestamps.len(), 12);
stats.record_incoming_announce(12.0);
stats.record_outgoing_announce(12.0);
assert_eq!(stats.ia_timestamps.len(), 12);
assert_eq!(stats.oa_timestamps.len(), 12);
assert_eq!(stats.ia_timestamps[0], 1.0);
assert_eq!(stats.oa_timestamps[0], 1.0);
}
#[test]
fn incoming_frequency_uses_sample_count_over_oldest_span() {
let mut stats = InterfaceStats::default();
for i in 0..12 {
stats.record_incoming_announce(i as f64);
}
let expected = 12.0 / 11.0;
assert!(
(stats.incoming_announce_freq() - expected).abs() < f64::EPSILON,
"incoming frequency should be samples / span, got {} expected {}",
stats.incoming_announce_freq(),
expected
);
}
}