1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
use futures::future::Ready;
use std::{convert::Infallible, future::Future, time::Duration};

/// Trait allowing you to run some future when a retry occurs. Could for example to be used for
/// logging or other kinds of telemetry.
///
/// You wont have to implement this trait manually. It is implemented for functions with the right
/// signature. See [`RetryFuture::on_retry`](struct.RetryFuture.html#method.on_retry) for more details.
pub trait OnRetry<E> {
    /// The type of the future you want to run.
    type Future: Future<Output = ()> + Send + 'static;

    /// Create another future to run.
    ///
    /// If `next_delay` is `None` then your future is out of retries and wont be called again.
    fn on_retry(
        &mut self,
        attempt: u32,
        next_delay: Option<Duration>,
        previous_error: &E,
    ) -> Self::Future;
}

/// A sentinel value that represents doing nothing in between retries.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NoOnRetry {
    cannot_exist: Infallible,
}

impl<E> OnRetry<E> for NoOnRetry {
    type Future = Ready<()>;

    #[inline]
    fn on_retry(&mut self, _: u32, _: Option<Duration>, _: &E) -> Self::Future {
        match self.cannot_exist {}
    }
}

impl<F, E, FutureT> OnRetry<E> for F
where
    F: Fn(u32, Option<Duration>, &E) -> FutureT,
    FutureT: Future<Output = ()> + Send + 'static,
    FutureT::Output: Send + 'static,
{
    type Future = FutureT;

    #[inline]
    fn on_retry(
        &mut self,
        attempts: u32,
        next_delay: Option<Duration>,
        previous_error: &E,
    ) -> Self::Future {
        self(attempts, next_delay, previous_error)
    }
}