1use std::time::{Duration, Instant};
2
3/// Keeps track of the elapsed time since the moment the polling started.
4#[derive(Debug, Clone)]
5pub struct PollTimeout {
6 timeout: Option<Duration>,
7 start: Instant,
8}
9
10impl PollTimeout {
11 /// Constructs a new `PollTimeout` with the given optional `Duration`.
12 pub fn new(timeout: Option<Duration>) -> PollTimeout {
13 PollTimeout {
14 timeout,
15 start: Instant::now(),
16 }
17 }
18
19 /// Returns whether the timeout has elapsed.
20 ///
21 /// It always returns `false` if the initial timeout was set to `None`.
22 pub fn elapsed(&self) -> bool {
23 self.timeout
24 .map(|timeout| self.start.elapsed() >= timeout)
25 .unwrap_or(false)
26 }
27
28 /// Returns the timeout leftover (initial timeout duration - elapsed duration).
29 pub fn leftover(&self) -> Option<Duration> {
30 self.timeout.map(|timeout| {
31 let elapsed = self.start.elapsed();
32
33 if elapsed >= timeout {
34 Duration::from_secs(0)
35 } else {
36 timeout - elapsed
37 }
38 })
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use std::time::{Duration, Instant};
45
46 use super::PollTimeout;
47
48 #[test]
49 pub fn test_timeout_without_duration_does_not_have_leftover() {
50 let timeout = PollTimeout::new(None);
51 assert_eq!(timeout.leftover(), None)
52 }
53
54 #[test]
55 pub fn test_timeout_without_duration_never_elapses() {
56 let timeout = PollTimeout::new(None);
57 assert!(!timeout.elapsed());
58 }
59
60 #[test]
61 pub fn test_timeout_elapses() {
62 const TIMEOUT_MILLIS: u64 = 100;
63
64 let timeout = PollTimeout {
65 timeout: Some(Duration::from_millis(TIMEOUT_MILLIS)),
66 start: Instant::now() - Duration::from_millis(2 * TIMEOUT_MILLIS),
67 };
68
69 assert!(timeout.elapsed());
70 }
71
72 #[test]
73 pub fn test_elapsed_timeout_has_zero_leftover() {
74 const TIMEOUT_MILLIS: u64 = 100;
75
76 let timeout = PollTimeout {
77 timeout: Some(Duration::from_millis(TIMEOUT_MILLIS)),
78 start: Instant::now() - Duration::from_millis(2 * TIMEOUT_MILLIS),
79 };
80
81 assert!(timeout.elapsed());
82 assert_eq!(timeout.leftover(), Some(Duration::from_millis(0)));
83 }
84
85 #[test]
86 pub fn test_not_elapsed_timeout_has_positive_leftover() {
87 let timeout = PollTimeout::new(Some(Duration::from_secs(60)));
88
89 assert!(!timeout.elapsed());
90 assert!(timeout.leftover().unwrap() > Duration::from_secs(0));
91 }
92}
93