use std::time::Duration;
use rand::RngExt;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RetryJitter {
None,
Factor(f64),
}
impl RetryJitter {
#[inline]
pub fn none() -> Self {
Self::None
}
#[inline]
pub fn factor(factor: f64) -> Self {
Self::Factor(factor)
}
pub fn apply(&self, base: Duration) -> Duration {
match self {
Self::None => base,
Self::Factor(factor) if *factor <= 0.0 || base.is_zero() => base,
Self::Factor(factor) => {
let base_nanos = base.as_nanos() as f64;
let span = base_nanos * factor;
let mut rng = rand::rng();
let jitter = rng.random_range(-span..=span);
Duration::from_nanos((base_nanos + jitter).max(0.0) as u64)
}
}
}
pub fn validate(&self) -> Result<(), String> {
match self {
Self::None => Ok(()),
Self::Factor(factor) => {
if !factor.is_finite() || *factor < 0.0 || *factor > 1.0 {
Err("jitter factor must be finite and in range [0.0, 1.0]".to_string())
} else {
Ok(())
}
}
}
}
}
impl Default for RetryJitter {
#[inline]
fn default() -> Self {
Self::None
}
}