1use core::time::Duration;
5use std::time::Instant;
6
7pub struct TimeoutManager {
8 start_time: Instant,
9 timeout: Duration,
10}
11
12impl TimeoutManager {
13 const MINIMUM_REAP_TIME: Duration = Duration::from_millis(160);
15
16 pub fn new(timeout: Duration) -> Self {
17 Self {
18 start_time: Instant::now(),
19 timeout,
20 }
21 }
22
23 pub fn remaining(&self) -> Duration {
24 let elapsed = self.start_time.elapsed();
26 if elapsed >= self.timeout {
27 Self::MINIMUM_REAP_TIME
28 } else {
29 (self.timeout - elapsed).max(Self::MINIMUM_REAP_TIME)
30 }
31 }
32
33 pub fn elapsed(&self) -> Duration {
34 self.start_time.elapsed()
35 }
36
37 pub fn timeout(&self) -> Duration {
38 self.timeout
39 }
40}
41
42impl core::fmt::Debug for TimeoutManager {
43 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44 f.debug_struct("TimeoutManager")
45 .field("start_time", &self.start_time)
46 .field("elapsed", &self.elapsed())
47 .field("timeout", &self.timeout)
48 .field("remaining", &self.remaining())
49 .finish()
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_timeout_manager_new() {
59 let timeout = Duration::from_secs(5);
60 let manager = TimeoutManager::new(timeout);
61
62 assert_eq!(manager.timeout(), timeout);
63 assert!(manager.remaining() >= TimeoutManager::MINIMUM_REAP_TIME);
64 }
65
66 #[test]
67 fn test_timeout_manager_remaining() {
68 let timeout = Duration::from_millis(100);
69 let manager = TimeoutManager::new(timeout);
70
71 let remaining = manager.remaining();
73 assert!(remaining >= TimeoutManager::MINIMUM_REAP_TIME);
74 std::thread::sleep(Duration::from_millis(10));
78 let remaining_after_sleep = manager.remaining();
79 assert!(remaining_after_sleep >= TimeoutManager::MINIMUM_REAP_TIME);
80 }
81
82 #[test]
83 fn test_timeout_manager_elapsed() {
84 let timeout = Duration::from_secs(1);
85 let manager = TimeoutManager::new(timeout);
86
87 assert!(manager.elapsed() < Duration::from_millis(100));
89
90 std::thread::sleep(Duration::from_millis(10));
92 let elapsed = manager.elapsed();
93 assert!(elapsed >= Duration::from_millis(10));
94 }
95
96 #[test]
97 fn test_timeout_manager_minimum_reap_time() {
98 let timeout = Duration::from_millis(50); let manager = TimeoutManager::new(timeout);
100
101 assert_eq!(manager.remaining(), TimeoutManager::MINIMUM_REAP_TIME);
103 }
104
105 #[test]
106 fn test_timeout_manager_debug() {
107 let timeout = Duration::from_secs(1);
108 let manager = TimeoutManager::new(timeout);
109
110 let debug_str = format!("{manager:?}");
111
112 assert!(debug_str.contains("TimeoutManager"));
114 assert!(debug_str.contains("start_time"));
115 assert!(debug_str.contains("elapsed"));
116 assert!(debug_str.contains("timeout"));
117 assert!(debug_str.contains("remaining"));
118 }
119
120 #[test]
121 fn test_timeout_manager_timeout_exceeded() {
122 let timeout = Duration::from_millis(10);
123 let manager = TimeoutManager::new(timeout);
124
125 std::thread::sleep(Duration::from_millis(50));
127
128 assert!(manager.elapsed() > timeout);
130
131 let remaining = manager.remaining();
133 assert_eq!(remaining, TimeoutManager::MINIMUM_REAP_TIME);
134 }
135}