1#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Hash)]
6pub struct Duration {
7 pub(crate) inner: cyclonedds_sys::dds_duration_t,
8}
9
10impl Duration {
11 pub const INFINITE: Self = Duration {
15 inner: cyclonedds_sys::DURATION_INFINITE,
16 };
17
18 #[must_use]
31 pub const fn from_nanos(nanos: i64) -> Self {
32 Self { inner: nanos }
33 }
34
35 #[must_use]
45 pub const fn from_millis(millis: i64) -> Self {
46 Self {
47 inner: millis * 1_000_000,
48 }
49 }
50
51 #[must_use]
61 pub const fn from_secs(secs: i64) -> Self {
62 Self {
63 inner: secs * 1_000_000_000,
64 }
65 }
66
67 #[must_use]
77 pub const fn as_nanos(&self) -> i64 {
78 self.inner
79 }
80
81 #[must_use]
91 pub const fn as_millis(&self) -> i64 {
92 self.inner / 1_000_000
93 }
94
95 #[must_use]
105 pub const fn as_secs(&self) -> i64 {
106 self.inner / 1_000_000_000
107 }
108
109 #[must_use]
120 pub const fn is_infinite(&self) -> bool {
121 self.inner == Self::INFINITE.inner
122 }
123
124 #[must_use]
135 pub fn checked_add(self, rhs: Self) -> Option<Self> {
136 self.inner
137 .checked_add(rhs.inner)
138 .map(|inner| Self { inner })
139 }
140
141 #[must_use]
152 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
153 self.inner
154 .checked_sub(rhs.inner)
155 .map(|inner| Self { inner })
156 }
157
158 #[must_use]
169 pub fn checked_mul(self, rhs: i64) -> Option<Self> {
170 self.inner.checked_mul(rhs).map(|inner| Self { inner })
171 }
172}
173
174impl std::ops::Add for Duration {
175 type Output = Self;
176
177 fn add(self, rhs: Self) -> Self::Output {
184 self.checked_add(rhs)
185 .expect("overflow when adding durations")
186 }
187}
188
189impl std::ops::Sub for Duration {
190 type Output = Self;
191
192 fn sub(self, rhs: Self) -> Self::Output {
199 self.checked_sub(rhs)
200 .expect("underflow when subtracting durations")
201 }
202}
203
204impl std::ops::Mul<i64> for Duration {
205 type Output = Self;
206
207 fn mul(self, rhs: i64) -> Self::Output {
214 self.checked_mul(rhs)
215 .expect("overflow when multiplying duration")
216 }
217}
218
219impl TryFrom<std::time::Duration> for Duration {
220 type Error = crate::Error;
221
222 fn try_from(value: std::time::Duration) -> Result<Self, Self::Error> {
223 let inner = cyclonedds_sys::dds_duration_t::try_from(value.as_nanos())
224 .map_err(|_err| crate::Error::BadParameter)?;
225
226 if inner == Self::INFINITE.inner {
227 Err(crate::Error::BadParameter)
228 } else {
229 Ok(Self { inner })
230 }
231 }
232}
233
234impl From<Duration> for std::time::Duration {
235 fn from(duration: Duration) -> Self {
236 std::time::Duration::from_nanos(duration.inner.cast_unsigned())
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn test_duration_from_nanos() {
246 let nanos = 1_000_000_000;
247 let duration = Duration::from_nanos(nanos);
248 assert_eq!(duration.inner, nanos);
249 }
250 #[test]
251 fn test_duration_from_millis() {
252 let duration = Duration::from_millis(100);
253 assert_eq!(duration.inner, 100_000_000);
254 }
255
256 #[test]
257 fn test_duration_from_secs() {
258 let duration = Duration::from_secs(5);
259 assert_eq!(duration.inner, 5_000_000_000);
260 }
261
262 #[test]
263 fn test_duration_as_nanos() {
264 let duration = Duration::from_nanos(1_000_000_000);
265 assert_eq!(duration.as_nanos(), 1_000_000_000);
266 }
267
268 #[test]
269 fn test_duration_as_millis() {
270 let duration = Duration::from_secs(1);
271 assert_eq!(duration.as_millis(), 1_000);
272 }
273
274 #[test]
275 fn test_duration_from_std_duration() {
276 let nanos = 1_000_000_000;
277 let standard = std::time::Duration::from_nanos(nanos as u64);
278 let duration = Duration::try_from(standard).unwrap();
279 assert_eq!(duration.inner, nanos);
280 }
281
282 #[test]
283 fn test_duration_from_infinite_std_duration() {
284 let nanos = Duration::INFINITE.inner;
285 let standard = std::time::Duration::from_nanos(nanos as u64);
286 let result = Duration::try_from(standard).unwrap_err();
287 assert_eq!(result, crate::Error::BadParameter);
288 }
289
290 #[test]
291 fn test_duration_from_out_of_range_std_duration() {
292 let nanos = u64::MAX;
293 let standard = std::time::Duration::from_nanos(nanos);
294 let result = Duration::try_from(standard).unwrap_err();
295 assert_eq!(result, crate::Error::BadParameter);
296 }
297
298 #[test]
299 fn test_duration_as_millis_truncates() {
300 let duration = Duration::from_millis(1) + Duration::from_nanos(999_999);
301 assert_eq!(duration.as_millis(), 1);
302 }
303
304 #[test]
305 fn test_duration_as_secs() {
306 let duration = Duration::from_millis(1_500);
307 assert_eq!(duration.as_secs(), 1);
308 }
309
310 #[test]
311 fn test_duration_as_secs_truncates() {
312 let duration = Duration::from_millis(999);
313 assert_eq!(duration.as_secs(), 0);
314 }
315
316 #[test]
317 fn test_duration_is_infinite() {
318 assert!(Duration::INFINITE.is_infinite());
319 }
320
321 #[test]
322 fn test_duration_is_not_infinite() {
323 assert!(!Duration::from_secs(5).is_infinite());
324 }
325
326 #[test]
327 fn test_duration_checked_add() {
328 let result = Duration::from_secs(1).checked_add(Duration::from_secs(2));
329 assert_eq!(result, Some(Duration::from_secs(3)));
330 }
331
332 #[test]
333 fn test_duration_checked_add_overflow() {
334 let result = Duration::from_nanos(i64::MAX).checked_add(Duration::from_nanos(1));
335 assert_eq!(result, None);
336 }
337
338 #[test]
339 fn test_duration_add() {
340 let result = Duration::from_secs(1) + Duration::from_secs(2);
341 assert_eq!(result, Duration::from_secs(3));
342 }
343
344 #[test]
345 #[should_panic(expected = "overflow when adding durations")]
346 fn test_duration_add_overflow() {
347 let _ = Duration::from_nanos(i64::MAX) + Duration::from_nanos(1);
348 }
349 #[test]
350 fn test_duration_checked_sub() {
351 let result = Duration::from_secs(3).checked_sub(Duration::from_secs(1));
352 assert_eq!(result, Some(Duration::from_secs(2)));
353 }
354
355 #[test]
356 fn test_duration_checked_sub_underflow() {
357 let result = Duration::from_nanos(i64::MIN).checked_sub(Duration::from_nanos(1));
358 assert_eq!(result, None);
359 }
360
361 #[test]
362 fn test_duration_sub() {
363 let result = Duration::from_secs(3) - Duration::from_secs(1);
364 assert_eq!(result, Duration::from_secs(2));
365 }
366
367 #[test]
368 #[should_panic(expected = "underflow when subtracting durations")]
369 fn test_duration_sub_underflow() {
370 let _ = Duration::from_nanos(i64::MIN) - Duration::from_nanos(1);
371 }
372
373 #[test]
374 fn test_duration_checked_mul() {
375 let result = Duration::from_secs(2).checked_mul(3);
376 assert_eq!(result, Some(Duration::from_secs(6)));
377 }
378
379 #[test]
380 fn test_duration_checked_mul_overflow() {
381 let result = Duration::from_nanos(i64::MAX).checked_mul(2);
382 assert_eq!(result, None);
383 }
384
385 #[test]
386 fn test_duration_mul() {
387 let result = Duration::from_secs(2) * 3;
388 assert_eq!(result, Duration::from_secs(6));
389 }
390
391 #[test]
392 fn test_to_std_duration() {
393 let nanos = 11_222_33;
394 let duration = Duration::from_nanos(nanos);
395 let expected = std::time::Duration::from_nanos(nanos as u64);
396 let actual = std::time::Duration::from(duration);
397 assert_eq!(actual, expected);
398 }
399
400 #[test]
401 #[should_panic(expected = "overflow when multiplying duration")]
402 fn test_duration_mul_overflow() {
403 let _ = Duration::from_nanos(i64::MAX) * 2;
404 }
405}