1#![warn(clippy::all)]
16
17pub mod fast_timeout;
37pub mod timer;
38
39pub use fast_timeout::fast_sleep as sleep;
40pub use fast_timeout::fast_timeout as timeout;
41
42use pin_project_lite::pin_project;
43use std::future::Future;
44use std::pin::Pin;
45use std::task::{self, Poll};
46use tokio::time::{sleep as tokio_sleep, Duration};
47
48pub trait ToTimeout {
52 fn timeout(&self) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>>;
53 fn create(d: Duration) -> Self;
54}
55
56pub struct TokioTimeout(Duration);
60
61impl ToTimeout for TokioTimeout {
62 fn timeout(&self) -> Pin<Box<dyn Future<Output = ()> + Send + Sync>> {
63 Box::pin(tokio_sleep(self.0))
64 }
65
66 fn create(d: Duration) -> Self {
67 TokioTimeout(d)
68 }
69}
70
71#[derive(Debug)]
73pub struct Elapsed;
74
75impl std::fmt::Display for Elapsed {
76 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77 write!(f, "Timeout Elapsed")
78 }
79}
80
81impl std::error::Error for Elapsed {}
82
83pub fn tokio_timeout<T>(duration: Duration, future: T) -> Timeout<T, TokioTimeout>
89where
90 T: Future,
91{
92 Timeout::<T, TokioTimeout>::new_with_delay(future, duration)
93}
94
95pin_project! {
96 #[must_use = "futures do nothing unless you `.await` or poll them"]
98 pub struct Timeout<T, F> {
99 #[pin]
100 value: T,
101 #[pin]
102 delay: Option<Pin<Box<dyn Future<Output = ()> + Send + Sync>>>,
103 callback: F, }
105}
106
107impl<T, F> Timeout<T, F>
108where
109 F: ToTimeout,
110{
111 pub(crate) fn new_with_delay(value: T, d: Duration) -> Timeout<T, F> {
112 Self::new_with_callback(value, F::create(d))
113 }
114
115 pub(crate) fn new_with_callback(value: T, callback: F) -> Timeout<T, F> {
116 Timeout {
117 value,
118 delay: None,
119 callback,
120 }
121 }
122}
123
124impl<T, F> Future for Timeout<T, F>
125where
126 T: Future,
127 F: ToTimeout,
128{
129 type Output = Result<T::Output, Elapsed>;
130
131 fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
132 let mut me = self.project();
133
134 if let Poll::Ready(v) = me.value.poll(cx) {
136 return Poll::Ready(Ok(v));
137 }
138
139 let delay = me
140 .delay
141 .get_or_insert_with(|| Box::pin(me.callback.timeout()));
142
143 match delay.as_mut().poll(cx) {
144 Poll::Pending => Poll::Pending,
145 Poll::Ready(()) => Poll::Ready(Err(Elapsed {})),
146 }
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[tokio::test]
155 async fn test_timeout() {
156 let fut = tokio_sleep(Duration::from_secs(1000));
157 let to = timeout(Duration::from_secs(1), fut);
158 assert!(to.await.is_err())
159 }
160
161 #[tokio::test]
162 async fn test_instantly_return() {
163 let fut = async { 1 };
164 let to = timeout(Duration::from_secs(1), fut);
165 assert_eq!(to.await.unwrap(), 1)
166 }
167
168 #[tokio::test]
169 async fn test_delayed_return() {
170 let fut = async {
171 tokio_sleep(Duration::from_secs(1)).await;
172 1
173 };
174 let to = timeout(Duration::from_secs(1000), fut);
175 assert_eq!(to.await.unwrap(), 1)
176 }
177}