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
//! A simple future that reports the duration of its inner future.

use std::{
    future::Future,
    time::{Duration, Instant},
    task::{Poll, Context},
    pin::Pin,
};
use futures::ready;
use pin_project::{pin_project, project};

pub async fn stopwatch<F: Future>(inner: F) -> (F::Output, Duration)
    where F: Future
{
    Stopwatch::new(inner).await
}
pub async fn try_stopwatch<F, T, E>(inner: F) -> Result<(T, Duration), E>
    where F: Future<Output=Result<T, E>>
{
    let (result, duration): (Result<T, E>, Duration) = Stopwatch::new(inner).await;
    result.map(|x| (x, duration))
}

#[pin_project]
pub struct Stopwatch<F> {
    start_time: Instant,
    #[pin]
    inner: F,
}
impl<F> Stopwatch<F> {
    fn new(inner: F) -> Self {
        Stopwatch {
            start_time: Instant::now(),
            inner,
        }
    }
}
impl<F: Future> Future for Stopwatch<F> {
    type Output = (F::Output, Duration);

    #[project]
    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        let this = self.project();
        let x = ready!(this.inner.poll(cx));
        Poll::Ready((x, this.start_time.elapsed()))
    }
}
#[cfg(test)]
mod test {
    use super::*;
    use std::time::Duration;
    use tokio::time::delay_for;
    #[tokio::test]
    async fn test_stopwatch() {
        let ((), time) = stopwatch(delay_for(Duration::from_secs(2))).await;
        println!("Timer duration: {:?}", time);
        assert!(time >= Duration::from_secs(2));
    }

    #[tokio::test]
    async fn test_try_stopwatch() {
        let future = async {
            Result::<(), u8>::Ok(delay_for(Duration::from_secs(2)).await)
        };
        let ((), time) = try_stopwatch(future).await.unwrap();
        println!("Timer duration: {:?}", time);
        assert!(time >= Duration::from_secs(2));
    }
}