use std::{collections::VecDeque, time::Duration};
pub struct DurationMonitor {
stored: VecDeque<Duration>,
total: Duration,
}
impl DurationMonitor {
pub fn try_filled_with(duration: Duration, size: usize) -> Result<Self, ()> {
if size > u32::MAX as usize {
Err(())
} else {
let mut stored = VecDeque::new();
stored.resize(size, duration);
Ok(Self {
stored,
total: duration * size as u32,
})
}
}
pub fn push(&mut self, duration: Duration) {
let removed = self.stored.pop_front().unwrap();
self.total -= removed;
self.stored.push_back(duration);
self.total += duration;
}
pub fn average_value(&self) -> Duration {
self.total / self.stored.len() as u32
}
}
pub struct RttProperties {
alpha: f64, beta: f64, }
impl RttProperties {
pub fn new(alpha: f64, beta: f64) -> Self {
Self { alpha, beta }
}
}
pub struct RttCalculator {
estimated: Duration,
var: Duration,
}
impl RttCalculator {
pub fn new(initial_rtt: Duration) -> Self {
RttCalculator {
estimated: initial_rtt,
var: initial_rtt / 2,
}
}
pub fn update_rtt(&mut self, properties: &RttProperties, new_rtt: Duration) -> Duration {
let new_rtt_secs = new_rtt.as_secs_f64();
let estimated_secs = self.estimated.as_secs_f64();
let var_secs = self.var.as_secs_f64();
let new_var = (1.0 - properties.beta) * var_secs
+ properties.beta * (new_rtt_secs - estimated_secs).abs();
let new_estimated =
(1.0 - properties.alpha) * estimated_secs + properties.alpha * new_rtt_secs;
self.var = Duration::from_secs_f64(new_var);
self.estimated = Duration::from_secs_f64(new_estimated);
self.estimated + self.var * 4
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_push_replaces_oldest_duration() {
let initial_duration = Duration::from_secs(1);
let mut monitor = DurationMonitor::try_filled_with(initial_duration, 3).unwrap();
monitor.push(Duration::from_secs(2));
assert_eq!(
monitor.average_value(),
Duration::from_millis(1000) + Duration::from_millis(1000) / 3
);
monitor.push(Duration::from_secs(3));
assert_eq!(monitor.average_value(), Duration::from_millis(2000));
monitor.push(Duration::from_secs(4));
assert_eq!(monitor.average_value(), Duration::from_millis(3000)); }
}