future_wrap/lib.rs
1use std::future::Future;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use pin_project::pin_project;
6
7#[pin_project]
8pub struct WrappedFuture<Fut, F, O>
9 where
10 Fut: Future,
11 F: FnMut(Pin<&mut Fut>, &mut Context) -> Poll<O>,
12{
13 #[pin]
14 inner: Fut,
15 f: F,
16}
17
18impl<Fut, F, O> Future for WrappedFuture<Fut, F, O>
19 where
20 Fut: Future,
21 F: FnMut(Pin<&mut Fut>, &mut Context) -> Poll<O>,
22{
23 type Output = O;
24
25 fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
26 let this = self.project();
27
28 (this.f)(this.inner, cx)
29 }
30}
31
32/// Adds a `wrap` function to all types that implement `Future`
33/// Lets you track each poll, interrupt the execution of the Future and change the return type
34/// ```
35/// use future_wrap::WrapFuture;
36/// use std::future::Future;
37/// use std::task::Poll;
38/// use std::time::{Duration, Instant};
39///
40/// let fut = some_async_fn();
41///
42/// let mut remaining_time = Duration::from_millis(10);
43/// fut.wrap(|fut, cx| {
44/// let poll_start = Instant::now();
45///
46/// println!("Poll start");
47/// let res = fut.poll(cx);
48/// println!("Poll end");
49///
50/// remaining_time = remaining_time.saturating_sub(poll_start.elapsed());
51/// if remaining_time.is_zero() {
52/// println!("Too much time spent on polls :(");
53/// Poll::Ready(None)
54/// } else {
55/// res.map(|v| Some(v))
56/// }
57/// }).await;
58/// ```
59pub trait WrapFuture<O>: Sized + Future {
60 fn wrap<F>(self, f: F) -> WrappedFuture<Self, F, O>
61 where
62 F: FnMut(Pin<&mut Self>, &mut Context) -> Poll<O>,
63 {
64 WrappedFuture {
65 inner: self,
66 f,
67 }
68 }
69}
70
71impl<F: Future, O> WrapFuture<O> for F {}