timeout.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. error::Error,
  20. fmt,
  21. future::Future,
  22. io,
  23. pin::Pin,
  24. task::{Context, Poll},
  25. time::Duration,
  26. };
  27. use pin_project_lite::pin_project;
  28. use smol::Timer;
  29. /// Awaits an I/O future or times out after a duration of time.
  30. ///
  31. /// If you want to await a non I/O future consider using
  32. /// `timeout()` instead.
  33. ///
  34. /// # Examples
  35. ///
  36. /// ```no_run
  37. /// # fn main() -> std::io::Result<()> { smol::block_on(async {
  38. /// #
  39. /// use std::time::Duration;
  40. /// use std::io;
  41. ///
  42. /// io_timeout(Duration::from_secs(5), async {
  43. /// let stdin = io::stdin();
  44. /// let mut line = String::new();
  45. /// let n = stdin.read_line(&mut line)?;
  46. /// Ok(())
  47. /// })
  48. /// .await?;
  49. /// #
  50. /// # Ok(()) }) }
  51. pub async fn io_timeout<F, T>(dur: Duration, f: F) -> io::Result<T>
  52. where
  53. F: Future<Output = io::Result<T>>,
  54. {
  55. Timeout { timeout: Timer::after(dur), future: f }.await
  56. }
  57. pin_project! {
  58. #[derive(Debug)]
  59. pub struct Timeout<F, T>
  60. where
  61. F: Future<Output = io::Result<T>>,
  62. {
  63. #[pin]
  64. future: F,
  65. #[pin]
  66. timeout: Timer,
  67. }
  68. }
  69. impl<F, T> Future for Timeout<F, T>
  70. where
  71. F: Future<Output = io::Result<T>>,
  72. {
  73. type Output = io::Result<T>;
  74. fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
  75. let this = self.project();
  76. match this.future.poll(cx) {
  77. Poll::Pending => {}
  78. other => return other,
  79. }
  80. if this.timeout.poll(cx).is_ready() {
  81. let err = Err(io::Error::new(io::ErrorKind::TimedOut, "future timed out"));
  82. Poll::Ready(err)
  83. } else {
  84. Poll::Pending
  85. }
  86. }
  87. }
  88. /// Awaits a future or times out after a duration of time.
  89. ///
  90. /// If you want to await an I/O future consider using
  91. /// `io_timeout` instead.
  92. ///
  93. /// # Examples
  94. ///
  95. /// ```
  96. /// # fn main() -> std::io::Result<()> { smol::block_on(async {
  97. /// #
  98. /// use std::time::Duration;
  99. /// use smol::future;
  100. ///
  101. /// let never = future::pending::<()>();
  102. /// let dur = Duration::from_millis(5);
  103. /// assert!(timeout(dur, never).await.is_err());
  104. /// #
  105. /// # Ok(()) }) }
  106. /// ```
  107. pub async fn timeout<F, T>(dur: Duration, f: F) -> Result<T, TimeoutError>
  108. where
  109. F: Future<Output = T>,
  110. {
  111. TimeoutFuture::new(f, dur).await
  112. }
  113. pin_project! {
  114. /// A future that times out after a duration of time.
  115. pub struct TimeoutFuture<F> {
  116. #[pin]
  117. future: F,
  118. #[pin]
  119. delay: Timer,
  120. }
  121. }
  122. impl<F> TimeoutFuture<F> {
  123. #[allow(dead_code)]
  124. pub(super) fn new(future: F, dur: Duration) -> TimeoutFuture<F> {
  125. TimeoutFuture { future, delay: Timer::after(dur) }
  126. }
  127. }
  128. impl<F: Future> Future for TimeoutFuture<F> {
  129. type Output = Result<F::Output, TimeoutError>;
  130. fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
  131. let this = self.project();
  132. match this.future.poll(cx) {
  133. Poll::Ready(v) => Poll::Ready(Ok(v)),
  134. Poll::Pending => match this.delay.poll(cx) {
  135. Poll::Ready(_) => Poll::Ready(Err(TimeoutError { _private: () })),
  136. Poll::Pending => Poll::Pending,
  137. },
  138. }
  139. }
  140. }
  141. /// An error returned when a future times out.
  142. #[derive(Clone, Copy, Debug, Eq, PartialEq)]
  143. pub struct TimeoutError {
  144. _private: (),
  145. }
  146. impl Error for TimeoutError {}
  147. impl fmt::Display for TimeoutError {
  148. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  149. "future has timed out".fmt(f)
  150. }
  151. }