use crate::{
transport::parameters::{AckDelayExponent, MaxAckDelay},
varint::VarInt,
};
use core::time::Duration;
const RECOMMENDED_ELICITATION_INTERVAL: u8 = 4;
const RECOMMENDED_RANGES_LIMIT: u8 = 10;
#[derive(Clone, Copy, Debug)]
pub struct Settings {
pub max_ack_delay: Duration,
pub ack_delay_exponent: u8,
pub ack_elicitation_interval: u8,
pub ack_ranges_limit: u8,
}
impl Default for Settings {
fn default() -> Self {
Self::RECOMMENDED
}
}
impl Settings {
pub const EARLY: Self = Self {
max_ack_delay: Duration::from_secs(0),
ack_delay_exponent: 0,
..Self::RECOMMENDED
};
pub const RECOMMENDED: Self = Self {
max_ack_delay: MaxAckDelay::RECOMMENDED.as_duration(),
ack_delay_exponent: AckDelayExponent::RECOMMENDED.as_u8(),
ack_elicitation_interval: RECOMMENDED_ELICITATION_INTERVAL,
ack_ranges_limit: RECOMMENDED_RANGES_LIMIT,
};
pub fn decode_ack_delay(&self, delay: VarInt) -> Duration {
Duration::from_micros(*delay) * self.scale()
}
pub fn encode_ack_delay(&self, delay: Duration) -> VarInt {
let micros = delay.as_micros();
let scale = self.scale() as u128;
(micros / scale).try_into().unwrap_or(VarInt::MAX)
}
fn scale(&self) -> u32 {
2u32.pow(self.ack_delay_exponent as u32)
}
}
#[cfg(test)]
mod ack_settings_tests {
use super::*;
#[test]
#[cfg_attr(miri, ignore)] fn ack_settings_test() {
for ack_delay_exponent in 0..=20 {
let settings = Settings {
ack_delay_exponent,
..Default::default()
};
let epsilon = settings.scale() as u128;
for delay in (0..1000).map(|v| v * 100).map(Duration::from_micros) {
let delay_varint = settings.encode_ack_delay(delay);
let expected_us = delay.as_micros();
let actual_us = settings.decode_ack_delay(delay_varint).as_micros();
let actual_difference = expected_us - actual_us;
assert!(actual_difference < epsilon);
}
let delay = settings.decode_ack_delay(VarInt::MAX);
let delay_varint = settings.encode_ack_delay(delay);
assert_eq!(VarInt::MAX, delay_varint);
}
}
}