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
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! A base trait represents a request.
use core::ops::{Deref, DerefMut};
use core::pin::Pin;

use crate::oneshot::Oneshot;
use crate::response::Response;

#[cfg(feature = "backoff")]
use crate::retry::{Backoff, RetrialPredicate, Retrying, Timer};
#[cfg(all(feature = "backoff", feature = "tokio-timer"))]
use crate::retry::{ExponentialBackoff, RetryingTokio};

/// Trait to represent types of the request, and their expected output and
/// error types.
pub trait BaseRequest {
    /// The type of successful values from the corresponding response.
    type Ok;
    /// The type of failures from the corresponding response.
    type Error;
}

impl<R> BaseRequest for &R
where
    R: BaseRequest,
{
    type Ok = R::Ok;
    type Error = R::Error;
}

impl<P> BaseRequest for Pin<P>
where
    P: Deref,
    P::Target: BaseRequest,
{
    type Ok = <P::Target as BaseRequest>::Ok;
    type Error = <P::Target as BaseRequest>::Error;
}

/// A generalized request-response interface, regardless how client works.
///
/// Because that the type of a client is parametrized, it can be implemented
/// to work with various kind of clients for the same type of the request.
pub trait Request<C>: BaseRequest {
    /// The type of corresponding responses of this request.
    type Response: Response<Ok = Self::Ok, Error = Self::Error>;

    fn send(self: Pin<&mut Self>, client: C) -> Self::Response;

    fn oneshot(self) -> Oneshot<Self>
    where
        Self: Sized,
    {
        Oneshot::from(self)
    }

    /// Wrap this request to retry if the given predicate returns `true`.
    ///
    /// It should be called within the tokio execution context,
    /// because the default timer is implemented using [`tokio_timer`].
    #[cfg(all(feature = "backoff", feature = "tokio-timer"))]
    fn retry_if<F>(self, pred: F) -> RetryingTokio<Self, ExponentialBackoff, F>
    where
        Self: Sized,
        F: RetrialPredicate<Self>,
    {
        RetryingTokio::from_default(self).with_predicate(pred)
    }

    /// Wrap this request to retry with customizable options, including the timer implementation.
    #[cfg(feature = "backoff")]
    fn retry_with_config<T, B, F>(self, timer: T, pred: F, backoff: B) -> Retrying<Self, T, B, F>
    where
        Self: Sized,
        T: Timer + Unpin,
        B: Backoff,
        F: RetrialPredicate<Self>,
    {
        Retrying::new(self, timer, backoff).with_predicate(pred)
    }
}

impl<P, C> Request<C> for Pin<P>
where
    P: DerefMut + Unpin,
    <P as Deref>::Target: Request<C>,
{
    type Response = <<P as Deref>::Target as Request<C>>::Response;
    fn send(self: Pin<&mut Self>, client: C) -> Self::Response {
        <<P as Deref>::Target>::send(self.get_mut().as_mut(), client)
    }
}

#[cfg(feature = "alloc")]
mod feature_alloc {
    use alloc::{boxed::Box, rc::Rc, sync::Arc};

    use super::*;

    impl<R> BaseRequest for Box<R>
    where
        R: BaseRequest,
    {
        type Ok = R::Ok;
        type Error = R::Error;
    }

    impl<R> BaseRequest for Rc<R>
    where
        R: BaseRequest,
    {
        type Ok = R::Ok;
        type Error = R::Error;
    }

    impl<R> BaseRequest for Arc<R>
    where
        R: BaseRequest,
    {
        type Ok = R::Ok;
        type Error = R::Error;
    }

    impl<R, C> Request<C> for Box<R>
    where
        R: Request<C>,
    {
        type Response = R::Response;
        fn send(self: Pin<&mut Self>, client: C) -> Self::Response {
            let pinned: Pin<&mut R> = unsafe { self.map_unchecked_mut(|b| b.as_mut()) };
            R::send(pinned, client)
        }
    }
}