use core::time::Duration;
const NANOS_PER_SEC: u128 = 1_000_000_000;
fn duration_from_nanos(nanos: u128) -> Duration {
let secs = nanos / NANOS_PER_SEC;
if secs > u64::MAX as u128 {
Duration::MAX
} else {
Duration::new(secs as u64, (nanos % NANOS_PER_SEC) as u32)
}
}
fn scale(delay: Duration, rand: u32) -> Duration {
let nanos = delay.as_nanos().saturating_mul(rand as u128) / u32::MAX as u128;
duration_from_nanos(nanos)
}
pub fn full_jitter(delay: Duration, rand: u32) -> Duration {
scale(delay, rand)
}
pub fn equal_jitter(delay: Duration, rand: u32) -> Duration {
let half = delay / 2;
half.saturating_add(scale(half, rand))
}
pub fn decorrelated_jitter(base: Duration, prev: Duration, cap: Duration, rand: u32) -> Duration {
let high = base.max(prev.saturating_mul(3));
let span = high.saturating_sub(base);
let delay = base.saturating_add(scale(span, rand));
delay.min(cap)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn full_jitter_bounds() {
let d = Duration::from_millis(1000);
assert_eq!(full_jitter(d, 0), Duration::ZERO);
assert_eq!(full_jitter(d, u32::MAX), d);
let mid = full_jitter(d, u32::MAX / 2);
assert!(mid > Duration::ZERO && mid < d);
}
#[test]
fn equal_jitter_bounds() {
let d = Duration::from_millis(1000);
assert_eq!(equal_jitter(d, 0), Duration::from_millis(500));
assert_eq!(equal_jitter(d, u32::MAX), d);
let mid = equal_jitter(d, u32::MAX / 2);
assert!(mid > Duration::from_millis(500) && mid < d);
}
#[test]
fn zero_delay_stays_zero() {
assert_eq!(full_jitter(Duration::ZERO, u32::MAX), Duration::ZERO);
assert_eq!(equal_jitter(Duration::ZERO, u32::MAX), Duration::ZERO);
}
#[test]
fn decorrelated_jitter_bounds() {
let base = Duration::from_millis(100);
let cap = Duration::from_secs(10);
assert_eq!(decorrelated_jitter(base, base, cap, 0), base);
assert_eq!(
decorrelated_jitter(base, base, cap, u32::MAX),
Duration::from_millis(300)
);
let mid = decorrelated_jitter(base, base, cap, u32::MAX / 2);
assert!(mid > base && mid < Duration::from_millis(300));
}
#[test]
fn decorrelated_jitter_caps() {
let base = Duration::from_millis(100);
let cap = Duration::from_secs(1);
let d = decorrelated_jitter(base, Duration::from_secs(100), cap, u32::MAX);
assert_eq!(d, cap);
}
#[test]
fn decorrelated_jitter_edges() {
let base = Duration::from_millis(100);
let cap = Duration::from_secs(10);
assert_eq!(
decorrelated_jitter(base, Duration::ZERO, cap, u32::MAX),
base
);
assert_eq!(
decorrelated_jitter(base, base, Duration::from_millis(50), u32::MAX),
Duration::from_millis(50)
);
let d = decorrelated_jitter(base, Duration::from_secs(u64::MAX), cap, u32::MAX / 4);
assert!(d <= cap);
}
#[test]
fn large_delay_does_not_overflow() {
let huge = Duration::from_secs(u64::MAX);
let j = full_jitter(huge, u32::MAX / 4);
assert!(j <= huge);
}
}