use std::time::Duration;
mod random;
pub use random::{jitter, jitter_rng, Range};
#[derive(Debug)]
pub struct Bounded<T> {
inner: T,
acc: Duration,
max: Duration,
}
impl<T> Bounded<T>
where
T: Iterator<Item = Duration>,
{
pub fn new<U>(inner: U, max: Duration) -> Self
where
U: IntoIterator<Item = Duration, IntoIter = T>,
{
Self {
inner: inner.into_iter(),
max,
acc: Default::default(),
}
}
}
impl<T> Iterator for Bounded<T>
where
T: Iterator<Item = Duration>,
{
type Item = Duration;
fn next(&mut self) -> Option<Duration> {
self.inner.next().filter(|next| {
if let Some(acc) = self.acc.checked_add(*next) {
self.acc = acc;
self.acc <= self.max
} else {
false
}
})
}
}
#[derive(Debug, Clone)]
pub struct Exponential {
current: Duration,
factor: f64,
}
impl Exponential {
pub fn new(duration: Duration) -> Self {
Self::with_factor(duration, duration.as_millis() as f64)
}
pub fn with_factor(base: Duration, factor: f64) -> Self {
Self {
current: jitter(base),
factor,
}
}
pub fn exact(duration: Duration) -> Self {
Self::exact_with_factor(duration, duration.as_millis() as f64)
}
pub fn exact_with_factor(base: Duration, factor: f64) -> Self {
Self {
current: base,
factor,
}
}
pub fn bounded(self, max: Duration) -> Bounded<Self> {
Bounded::new(self, max)
}
}
impl Iterator for Exponential {
type Item = Duration;
fn next(&mut self) -> Option<Duration> {
fn try_from_secs_f64(secs: f64) -> Option<Duration> {
const NANOS_PER_SEC: u32 = 1_000_000_000;
const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
let nanos = secs * (NANOS_PER_SEC as f64);
if !nanos.is_finite() || nanos >= MAX_NANOS_F64 || nanos < 0.0 {
None
} else {
Some(Duration::from_secs_f64(secs))
}
}
let duration = self.current;
let next_secs = self.current.as_secs_f64() * self.factor;
self.current = try_from_secs_f64(next_secs).unwrap_or(self.current);
Some(duration)
}
}
impl From<Duration> for Exponential {
fn from(duration: Duration) -> Self {
Self::new(duration)
}
}
#[test]
fn exponential_with_factor() {
let mut iter = Exponential::exact_with_factor(Duration::from_secs(1), 2.0);
assert_eq!(iter.next(), Some(Duration::from_secs(1)));
assert_eq!(iter.next(), Some(Duration::from_secs(2)));
assert_eq!(iter.next(), Some(Duration::from_secs(4)));
assert_eq!(iter.next(), Some(Duration::from_secs(8)));
assert_eq!(iter.next(), Some(Duration::from_secs(16)));
assert_eq!(iter.next(), Some(Duration::from_secs(32)));
}
#[test]
fn exponential_overflow() {
let mut iter = Exponential::exact(Duration::MAX);
assert_eq!(iter.next(), Some(Duration::MAX));
assert_eq!(iter.next(), Some(Duration::MAX));
}
#[test]
fn exponential_with_upper_bound() {
let mut iter =
Exponential::exact_with_factor(Duration::from_secs(1), 2.0).bounded(Duration::from_secs(4));
assert_eq!(iter.next(), Some(Duration::from_secs(1)));
assert_eq!(iter.next(), Some(Duration::from_secs(2)));
assert_eq!(iter.next(), None);
}
#[derive(Debug, Clone)]
pub struct Fibonacci {
curr: Duration,
next: Duration,
}
impl Fibonacci {
pub fn new(duration: Duration) -> Fibonacci {
let duration = jitter(duration);
Fibonacci {
curr: duration,
next: duration,
}
}
pub fn exact(duration: Duration) -> Fibonacci {
Fibonacci {
curr: duration,
next: duration,
}
}
}
impl Iterator for Fibonacci {
type Item = Duration;
fn next(&mut self) -> Option<Duration> {
let duration = self.curr;
let next = self.curr.saturating_add(self.next);
self.curr = self.next;
self.next = next;
Some(duration)
}
}
impl From<Duration> for Fibonacci {
fn from(duration: Duration) -> Self {
Self::new(duration)
}
}
#[test]
fn fibonacci() {
let mut iter = Fibonacci::exact(Duration::from_millis(10));
assert_eq!(iter.next(), Some(Duration::from_millis(10)));
assert_eq!(iter.next(), Some(Duration::from_millis(10)));
assert_eq!(iter.next(), Some(Duration::from_millis(20)));
assert_eq!(iter.next(), Some(Duration::from_millis(30)));
assert_eq!(iter.next(), Some(Duration::from_millis(50)));
assert_eq!(iter.next(), Some(Duration::from_millis(80)));
}
#[test]
fn fibonacci_saturated() {
let mut iter = Fibonacci::exact(Duration::MAX);
assert_eq!(iter.next(), Some(Duration::MAX));
assert_eq!(iter.next(), Some(Duration::MAX));
}
#[derive(Debug, Clone)]
pub struct Fixed {
duration: Duration,
}
impl Fixed {
pub fn new(duration: Duration) -> Self {
Fixed {
duration: jitter(duration),
}
}
pub fn exact(duration: Duration) -> Self {
Fixed { duration }
}
}
impl Iterator for Fixed {
type Item = Duration;
fn next(&mut self) -> Option<Duration> {
Some(self.duration)
}
}
impl From<Duration> for Fixed {
fn from(duration: Duration) -> Self {
Self { duration }
}
}
#[derive(Debug, Clone)]
pub struct NoDelay;
impl Iterator for NoDelay {
type Item = Duration;
fn next(&mut self) -> Option<Duration> {
Some(Duration::default())
}
}
#[cfg(test)]
mod test {
use crate::delay::Exponential;
use std::time::Duration;
#[test]
fn test_bounded_overflow() {
let mut delays = Exponential::exact_with_factor(Duration::MAX, 1.0).bounded(Duration::MAX);
assert_eq!(delays.next(), Some(Duration::MAX));
assert_eq!(delays.next(), None);
}
}