1use crate::{deadline::TimedOutError, Deadline};
4use core::future::Future;
5use core::pin::Pin;
6
7use pin_project_lite::pin_project;
8use std::task::{Context, Poll};
9
10pub trait FutureExt: Future {
12 fn timeout_at<T>(self, target: T) -> TimeoutAt<Self>
14 where
15 Self: Sized,
16 T: Into<Deadline>,
17 {
18 TimeoutAt {
19 deadline: target.into(),
20 future: self,
21 }
22 }
23}
24
25impl<F: Future> FutureExt for F {}
26
27pin_project! {
28 #[must_use = "Futures do nothing unless polled or .awaited"]
32 #[derive(Debug)]
33 pub struct TimeoutAt<F> {
34 #[pin]
35 future: F,
36 #[pin]
37 deadline: Deadline,
38 }
39}
40
41impl<F> Future for TimeoutAt<F>
42where
43 F: Future,
44{
45 type Output = Result<F::Output, TimedOutError>;
46
47 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
48 let this = self.project();
49 if let Poll::Ready(()) = this.deadline.poll(cx) {
50 return Poll::Ready(Err(TimedOutError::new()));
51 }
52 match this.future.poll(cx) {
53 Poll::Pending => Poll::Pending,
54 Poll::Ready(it) => Poll::Ready(Ok(it)),
55 }
56 }
57}