mettle 0.5.0

Retry for Rust, async and blocking: backoff, jitter, per-attempt timeouts, and a clock you can mock.
Documentation
//! A synchronous time source for [blocking retry](super).

use std::time::{Duration, Instant};

/// A synchronous time source: read "now", and block for a duration.
///
/// Injected so tests can supply a mock that advances a *virtual* clock and returns from
/// `sleep` instantly. Open on purpose: implement it for a mock or a simulation runtime.
///
/// This is the blocking counterpart of mettle's async `Clock` trait; the two are separate
/// because the async one's `sleep` returns a `Future` and this one just blocks.
pub trait Clock {
    /// The current instant.
    fn now(&self) -> Instant;

    /// Block the current thread for `dur`.
    fn sleep(&self, dur: Duration);
}

// Same reasoning as the async twin: a test wants to keep its mock so it can advance time and read
// back what was slept, and without these `.clock(&mock)` doesn't compile.
impl<C: Clock + ?Sized> Clock for &C {
    fn now(&self) -> Instant {
        (**self).now()
    }

    fn sleep(&self, dur: Duration) {
        (**self).sleep(dur);
    }
}

impl<C: Clock + ?Sized> Clock for std::sync::Arc<C> {
    fn now(&self) -> Instant {
        (**self).now()
    }

    fn sleep(&self, dur: Duration) {
        (**self).sleep(dur);
    }
}

/// A [`Clock`] backed by [`std::thread::sleep`] and [`std::time::Instant`].
#[derive(Debug, Clone, Copy, Default)]
pub struct StdClock;

impl Clock for StdClock {
    fn now(&self) -> Instant {
        Instant::now()
    }

    fn sleep(&self, dur: Duration) {
        std::thread::sleep(dur);
    }
}