crossterm/event/
timeout.rs

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}