mtop_client/
timeout.rs

1use crate::core::MtopError;
2use pin_project_lite::pin_project;
3use std::future::Future;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6use std::time::Duration;
7
8/// `Timeout` can be used to add a timeout to any future emitted by mtop.
9pub trait Timeout: Sized {
10    fn timeout<S>(self, t: Duration, operation: S) -> Timed<Self>
11    where
12        S: Into<String>;
13}
14
15impl<F, V> Timeout for F
16where
17    F: Future<Output = Result<V, MtopError>>,
18{
19    fn timeout<S>(self, t: Duration, operation: S) -> Timed<F>
20    where
21        S: Into<String>,
22    {
23        Timed {
24            operation: operation.into(),
25            time: t,
26            inner: tokio::time::timeout(t, self),
27        }
28    }
29}
30
31pin_project! {
32    #[derive(Debug)]
33    #[must_use = "futures do nothing unless you `.await` or poll them"]
34    pub struct Timed<T> {
35        operation: String,
36        time: Duration,
37        #[pin]
38        inner: tokio::time::Timeout<T>,
39    }
40}
41
42impl<F, V> Future for Timed<F>
43where
44    F: Future<Output = Result<V, MtopError>>,
45{
46    type Output = F::Output;
47
48    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
49        let this = self.project();
50        // Poll the inner Timeout future and unwrap one layer of Result it adds,
51        // converting a timeout into specific form of an MtopError
52        this.inner.poll(cx).map(|res| match res {
53            Ok(Ok(v)) => Ok(v),
54            Ok(Err(e)) => Err(e),
55            Err(_e) => Err(MtopError::timeout(*this.time, this.operation)),
56        })
57    }
58}