duration_extender/
lib.rs

1use std::time::Duration;
2
3/// An extension trait that adds fluent time unit methods to integer primitives,
4/// allowing for highly readable time duration creation.
5/// 
6/// The functions return a standard Rust `std::time::Duration`.
7pub trait DurationExt {
8    /// Creates a Duration representing this many seconds.
9    fn seconds(self) -> Duration;
10    /// Creates a Duration representing this many minutes.
11    fn minutes(self) -> Duration;
12    /// Creates a Duration representing this many hours.
13    fn hours(self) -> Duration;
14    /// Creates a Duration representing this many days (24 hours).
15    fn days(self) -> Duration;
16    /// Creates a Duration representing this many weeks (7 days).
17    fn weeks(self) -> Duration;
18    /// Creates a Duration representing this many milliseconds.
19    fn milliseconds(self) -> Duration;
20    /// Creates a Duration representing this many microseconds.
21    fn microseconds(self) -> Duration;
22    /// Creates a Duration representing this many nanoseconds.
23    fn nanoseconds(self) -> Duration;
24}
25
26impl DurationExt for u64 {
27    fn seconds(self) -> Duration {
28        Duration::from_secs(self)
29    }
30
31    fn minutes(self) -> Duration {
32        Duration::from_secs(self.saturating_mul(60))
33    }
34
35    fn hours(self) -> Duration {
36        Duration::from_secs(self.saturating_mul(3600))
37    }
38
39    fn days(self) -> Duration {
40        Duration::from_secs(self.saturating_mul(86400))
41    }
42
43    fn weeks(self) -> Duration {
44        Duration::from_secs(self.saturating_mul(604800))
45    }
46    
47    fn milliseconds(self) -> Duration {
48        Duration::from_millis(self)
49    }
50
51    fn microseconds(self) -> Duration {
52        Duration::from_micros(self)
53    }
54
55    fn nanoseconds(self) -> Duration {
56        Duration::from_nanos(self)
57    }
58}
59
60impl DurationExt for u32 {
61    fn seconds(self) -> Duration {
62        Duration::from_secs(self as u64)
63    }
64
65    fn minutes(self) -> Duration {
66        Duration::from_secs((self as u64).saturating_mul(60))
67    }
68
69    fn hours(self) -> Duration {
70        Duration::from_secs((self as u64).saturating_mul(3600))
71    }
72
73    fn days(self) -> Duration {
74        Duration::from_secs((self as u64).saturating_mul(86400))
75    }
76
77    fn weeks(self) -> Duration {
78        Duration::from_secs((self as u64).saturating_mul(604800))
79    }
80
81    fn milliseconds(self) -> Duration {
82        Duration::from_millis(self as u64)
83    }
84
85    fn microseconds(self) -> Duration {
86        Duration::from_micros(self as u64)
87    }
88
89    fn nanoseconds(self) -> Duration {
90        Duration::from_nanos(self as u64)
91    }
92}
93
94impl DurationExt for i64 {
95    fn seconds(self) -> Duration {
96        Duration::from_secs(self.abs() as u64)
97    }
98
99    fn minutes(self) -> Duration {
100        Duration::from_secs((self.abs() as u64).saturating_mul(60))
101    }
102
103    fn hours(self) -> Duration {
104        Duration::from_secs((self.abs() as u64).saturating_mul(3600))
105    }
106
107    fn days(self) -> Duration {
108        Duration::from_secs((self.abs() as u64).saturating_mul(86400))
109    }
110
111    fn weeks(self) -> Duration {
112        Duration::from_secs((self.abs() as u64).saturating_mul(604800))
113    }
114    
115    fn milliseconds(self) -> Duration {
116        Duration::from_millis(self.abs() as u64)
117    }
118
119    fn microseconds(self) -> Duration {
120        Duration::from_micros(self.abs() as u64)
121    }
122
123    fn nanoseconds(self) -> Duration {
124        Duration::from_nanos(self.abs() as u64)
125    }
126}
127
128impl DurationExt for i32 {
129    fn seconds(self) -> Duration {
130        Duration::from_secs(self.abs() as u64)
131    }
132
133    fn minutes(self) -> Duration {
134        Duration::from_secs((self.abs() as u64).saturating_mul(60))
135    }
136
137    fn hours(self) -> Duration {
138        Duration::from_secs((self.abs() as u64).saturating_mul(3600))
139    }
140
141    fn days(self) -> Duration {
142        Duration::from_secs((self.abs() as u64).saturating_mul(86400))
143    }
144
145    fn weeks(self) -> Duration {
146        Duration::from_secs((self.abs() as u64).saturating_mul(604800))
147    }
148
149    fn milliseconds(self) -> Duration {
150        Duration::from_millis(self.abs() as u64)
151    }
152
153    fn microseconds(self) -> Duration {
154        Duration::from_micros(self.abs() as u64)
155    }
156
157    fn nanoseconds(self) -> Duration {
158        Duration::from_nanos(self.abs() as u64)
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165    use std::time::Duration;
166
167    // --- U64 Tests ---
168    #[test]
169    fn test_u64_large_units() {
170        let five: u64 = 5;
171        assert_eq!(five.seconds(), Duration::from_secs(5));
172        assert_eq!(five.minutes(), Duration::from_secs(5 * 60));
173        assert_eq!(five.hours(), Duration::from_secs(5 * 3600));
174        assert_eq!(five.days(), Duration::from_secs(5 * 86400));
175        assert_eq!(five.weeks(), Duration::from_secs(5 * 604800));
176    }
177
178    #[test]
179    fn test_u64_small_units() {
180        let one: u64 = 1;
181        assert_eq!(one.milliseconds(), Duration::from_millis(1));
182        assert_eq!(one.microseconds(), Duration::from_micros(1));
183        assert_eq!(one.nanoseconds(), Duration::from_nanos(1));
184
185        let large_num: u64 = 1_234_567;
186        assert_eq!(large_num.milliseconds(), Duration::from_millis(1_234_567));
187    }
188
189    // --- U32 Tests ---
190    #[test]
191    fn test_u32_large_units() {
192        let three: u32 = 3;
193        assert_eq!(three.seconds(), Duration::from_secs(3));
194        assert_eq!(three.minutes(), Duration::from_secs(3 * 60));
195        assert_eq!(three.hours(), Duration::from_secs(3 * 3600));
196    }
197
198    #[test]
199    fn test_u32_small_units() {
200        let num: u32 = 999;
201        assert_eq!(num.milliseconds(), Duration::from_millis(999));
202        assert_eq!(num.microseconds(), Duration::from_micros(999));
203        assert_eq!(num.nanoseconds(), Duration::from_nanos(999));
204    }
205
206    // --- I64 Tests ---
207    #[test]
208    fn test_i64_positive_and_negative() {
209        let pos_ten: i64 = 10;
210        let neg_ten: i64 = -10;
211
212        // Large units
213        assert_eq!(pos_ten.minutes(), Duration::from_secs(600));
214        assert_eq!(neg_ten.minutes(), Duration::from_secs(600));
215
216        // Small units
217        assert_eq!(pos_ten.milliseconds(), Duration::from_millis(10));
218        assert_eq!(neg_ten.milliseconds(), Duration::from_millis(10));
219    }
220
221    // --- I32 Tests ---
222    #[test]
223    fn test_i32_positive_and_negative() {
224        let pos_two: i32 = 2;
225        let neg_two: i32 = -2;
226
227        // Large units
228        assert_eq!(pos_two.days(), Duration::from_secs(2 * 86400));
229        assert_eq!(neg_two.days(), Duration::from_secs(2 * 86400));
230
231        // Small units
232        assert_eq!(pos_two.microseconds(), Duration::from_micros(2));
233        assert_eq!(neg_two.microseconds(), Duration::from_micros(2));
234    }
235    
236    // --- Saturation Test ---
237    #[test]
238    fn test_saturating_mul_no_panic() {
239        let max_u64 = u64::MAX;
240        // Test large multiplication for saturation
241        let duration = max_u64.minutes();
242        assert!(duration.as_secs() > 0); 
243        
244        // Test small multiplication where the value is simply passed to std::time::Duration 
245        // (i.e., we rely on Duration::from_* to handle the conversion/saturation internally, 
246        // but ensure our methods don't panic)
247        let small_duration = max_u64.milliseconds();
248        assert!(small_duration.as_millis() > 0);
249    }
250}