use crate::{deadline::TimedOutError, Deadline};
use core::future::Future;
use core::pin::Pin;
use pin_project_lite::pin_project;
use std::task::{Context, Poll};
pub trait FutureExt: Future {
fn timeout_at<T>(self, target: T) -> TimeoutAt<Self>
where
Self: Sized,
T: Into<Deadline>,
{
TimeoutAt {
deadline: target.into(),
future: self,
}
}
}
impl<F: Future> FutureExt for F {}
pin_project! {
#[must_use = "Futures do nothing unless polled or .awaited"]
#[derive(Debug)]
pub struct TimeoutAt<F> {
#[pin]
future: F,
#[pin]
deadline: Deadline,
}
}
impl<F> Future for TimeoutAt<F>
where
F: Future,
{
type Output = Result<F::Output, TimedOutError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
if let Poll::Ready(()) = this.deadline.poll(cx) {
return Poll::Ready(Err(TimedOutError::new()));
}
match this.future.poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(it) => Poll::Ready(Ok(it)),
}
}
}