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))
}
#[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 large_delay_does_not_overflow() {
let huge = Duration::from_secs(u64::MAX);
let j = full_jitter(huge, u32::MAX / 4);
assert!(j <= huge);
}
}