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
8pub 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 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}