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