1#[cfg_attr(target_env = "musl", allow(deprecated))]
2// https://github.com/rust-lang/libc/issues/1848
3pub use libc::{suseconds_t, time_t};
4use libc::{timespec, timeval};
5use std::convert::From;
6use std::time::Duration;
7use std::{cmp, fmt, ops};
8
9const fn zero_init_timespec() -> timespec {
10 // `std::mem::MaybeUninit::zeroed()` is not yet a const fn
11 // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of
12 // the appropriate size to zero and then transmute it to a timespec value.
13 unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) }
14}
15
16#[cfg(any(
17 all(feature = "time", any(target_os = "android", target_os = "linux")),
18 all(
19 any(
20 target_os = "freebsd",
21 target_os = "illumos",
22 target_os = "linux",
23 target_os = "netbsd"
24 ),
25 feature = "time",
26 feature = "signal"
27 )
28))]
29pub(crate) mod timer {
30 use crate::sys::time::{zero_init_timespec, TimeSpec};
31 use bitflags::bitflags;
32
33 #[derive(Debug, Clone, Copy)]
34 pub(crate) struct TimerSpec(libc::itimerspec);
35
36 impl TimerSpec {
37 pub const fn none() -> Self {
38 Self(libc::itimerspec {
39 it_interval: zero_init_timespec(),
40 it_value: zero_init_timespec(),
41 })
42 }
43 }
44
45 impl AsMut<libc::itimerspec> for TimerSpec {
46 fn as_mut(&mut self) -> &mut libc::itimerspec {
47 &mut self.0
48 }
49 }
50
51 impl AsRef<libc::itimerspec> for TimerSpec {
52 fn as_ref(&self) -> &libc::itimerspec {
53 &self.0
54 }
55 }
56
57 impl From<Expiration> for TimerSpec {
58 fn from(expiration: Expiration) -> TimerSpec {
59 match expiration {
60 Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
61 it_interval: zero_init_timespec(),
62 it_value: *t.as_ref(),
63 }),
64 Expiration::IntervalDelayed(start, interval) => {
65 TimerSpec(libc::itimerspec {
66 it_interval: *interval.as_ref(),
67 it_value: *start.as_ref(),
68 })
69 }
70 Expiration::Interval(t) => TimerSpec(libc::itimerspec {
71 it_interval: *t.as_ref(),
72 it_value: *t.as_ref(),
73 }),
74 }
75 }
76 }
77
78 /// An enumeration allowing the definition of the expiration time of an alarm,
79 /// recurring or not.
80 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
81 pub enum Expiration {
82 /// Alarm will trigger once after the time given in `TimeSpec`
83 OneShot(TimeSpec),
84 /// Alarm will trigger after a specified delay and then every interval of
85 /// time.
86 IntervalDelayed(TimeSpec, TimeSpec),
87 /// Alarm will trigger every specified interval of time.
88 Interval(TimeSpec),
89 }
90
91 #[cfg(any(target_os = "android", target_os = "linux"))]
92 bitflags! {
93 /// Flags that are used for arming the timer.
94 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
95 pub struct TimerSetTimeFlags: libc::c_int {
96 const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
97 const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET;
98 }
99 }
100 #[cfg(any(
101 target_os = "freebsd",
102 target_os = "netbsd",
103 target_os = "dragonfly",
104 target_os = "illumos"
105 ))]
106 bitflags! {
107 /// Flags that are used for arming the timer.
108 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
109 pub struct TimerSetTimeFlags: libc::c_int {
110 const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME;
111 }
112 }
113
114 impl From<TimerSpec> for Expiration {
115 fn from(timerspec: TimerSpec) -> Expiration {
116 match timerspec {
117 TimerSpec(libc::itimerspec {
118 it_interval:
119 libc::timespec {
120 tv_sec: 0,
121 tv_nsec: 0,
122 ..
123 },
124 it_value: ts,
125 }) => Expiration::OneShot(ts.into()),
126 TimerSpec(libc::itimerspec {
127 it_interval: int_ts,
128 it_value: val_ts,
129 }) => {
130 if (int_ts.tv_sec == val_ts.tv_sec)
131 && (int_ts.tv_nsec == val_ts.tv_nsec)
132 {
133 Expiration::Interval(int_ts.into())
134 } else {
135 Expiration::IntervalDelayed(
136 val_ts.into(),
137 int_ts.into(),
138 )
139 }
140 }
141 }
142 }
143 }
144}
145
146pub trait TimeValLike: Sized {
147 #[inline]
148 fn zero() -> Self {
149 Self::seconds(0)
150 }
151
152 #[inline]
153 fn hours(hours: i64) -> Self {
154 let secs = hours
155 .checked_mul(SECS_PER_HOUR)
156 .expect("TimeValLike::hours ouf of bounds");
157 Self::seconds(secs)
158 }
159
160 #[inline]
161 fn minutes(minutes: i64) -> Self {
162 let secs = minutes
163 .checked_mul(SECS_PER_MINUTE)
164 .expect("TimeValLike::minutes out of bounds");
165 Self::seconds(secs)
166 }
167
168 fn seconds(seconds: i64) -> Self;
169 fn milliseconds(milliseconds: i64) -> Self;
170 fn microseconds(microseconds: i64) -> Self;
171 fn nanoseconds(nanoseconds: i64) -> Self;
172
173 #[inline]
174 fn num_hours(&self) -> i64 {
175 self.num_seconds() / 3600
176 }
177
178 #[inline]
179 fn num_minutes(&self) -> i64 {
180 self.num_seconds() / 60
181 }
182
183 fn num_seconds(&self) -> i64;
184 fn num_milliseconds(&self) -> i64;
185 fn num_microseconds(&self) -> i64;
186 fn num_nanoseconds(&self) -> i64;
187}
188
189#[repr(C)]
190#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
191pub struct TimeSpec(timespec);
192
193const NANOS_PER_SEC: i64 = 1_000_000_000;
194const SECS_PER_MINUTE: i64 = 60;
195const SECS_PER_HOUR: i64 = 3600;
196
197#[cfg(target_pointer_width = "64")]
198const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1;
199
200#[cfg(target_pointer_width = "32")]
201const TS_MAX_SECONDS: i64 = isize::MAX as i64;
202
203const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
204
205// x32 compatibility
206// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
207#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
208type timespec_tv_nsec_t = i64;
209#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
210type timespec_tv_nsec_t = libc::c_long;
211
212impl From<timespec> for TimeSpec {
213 fn from(ts: timespec) -> Self {
214 Self(ts)
215 }
216}
217
218impl From<Duration> for TimeSpec {
219 fn from(duration: Duration) -> Self {
220 Self::from_duration(duration)
221 }
222}
223
224impl From<TimeSpec> for Duration {
225 fn from(timespec: TimeSpec) -> Self {
226 Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32)
227 }
228}
229
230impl AsRef<timespec> for TimeSpec {
231 fn as_ref(&self) -> &timespec {
232 &self.0
233 }
234}
235
236impl AsMut<timespec> for TimeSpec {
237 fn as_mut(&mut self) -> &mut timespec {
238 &mut self.0
239 }
240}
241
242impl Ord for TimeSpec {
243 // The implementation of cmp is simplified by assuming that the struct is
244 // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
245 fn cmp(&self, other: &TimeSpec) -> cmp::Ordering {
246 if self.tv_sec() == other.tv_sec() {
247 self.tv_nsec().cmp(&other.tv_nsec())
248 } else {
249 self.tv_sec().cmp(&other.tv_sec())
250 }
251 }
252}
253
254impl PartialOrd for TimeSpec {
255 fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
256 Some(self.cmp(other))
257 }
258}
259
260impl TimeValLike for TimeSpec {
261 #[inline]
262 #[cfg_attr(target_env = "musl", allow(deprecated))]
263 // https://github.com/rust-lang/libc/issues/1848
264 fn seconds(seconds: i64) -> TimeSpec {
265 assert!(
266 (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
267 "TimeSpec out of bounds; seconds={seconds}",
268 );
269 let mut ts = zero_init_timespec();
270 ts.tv_sec = seconds as time_t;
271 TimeSpec(ts)
272 }
273
274 #[inline]
275 fn milliseconds(milliseconds: i64) -> TimeSpec {
276 let nanoseconds = milliseconds
277 .checked_mul(1_000_000)
278 .expect("TimeSpec::milliseconds out of bounds");
279
280 TimeSpec::nanoseconds(nanoseconds)
281 }
282
283 /// Makes a new `TimeSpec` with given number of microseconds.
284 #[inline]
285 fn microseconds(microseconds: i64) -> TimeSpec {
286 let nanoseconds = microseconds
287 .checked_mul(1_000)
288 .expect("TimeSpec::milliseconds out of bounds");
289
290 TimeSpec::nanoseconds(nanoseconds)
291 }
292
293 /// Makes a new `TimeSpec` with given number of nanoseconds.
294 #[inline]
295 #[cfg_attr(target_env = "musl", allow(deprecated))]
296 // https://github.com/rust-lang/libc/issues/1848
297 fn nanoseconds(nanoseconds: i64) -> TimeSpec {
298 let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
299 assert!(
300 (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs),
301 "TimeSpec out of bounds"
302 );
303 let mut ts = zero_init_timespec();
304 ts.tv_sec = secs as time_t;
305 ts.tv_nsec = nanos as timespec_tv_nsec_t;
306 TimeSpec(ts)
307 }
308
309 // The cast is not unnecessary on all platforms.
310 #[allow(clippy::unnecessary_cast)]
311 fn num_seconds(&self) -> i64 {
312 if self.tv_sec() < 0 && self.tv_nsec() > 0 {
313 (self.tv_sec() + 1) as i64
314 } else {
315 self.tv_sec() as i64
316 }
317 }
318
319 fn num_milliseconds(&self) -> i64 {
320 self.num_nanoseconds() / 1_000_000
321 }
322
323 fn num_microseconds(&self) -> i64 {
324 self.num_nanoseconds() / 1_000
325 }
326
327 // The cast is not unnecessary on all platforms.
328 #[allow(clippy::unnecessary_cast)]
329 fn num_nanoseconds(&self) -> i64 {
330 let secs = self.num_seconds() * 1_000_000_000;
331 let nsec = self.nanos_mod_sec();
332 secs + nsec as i64
333 }
334}
335
336impl TimeSpec {
337 /// Construct a new `TimeSpec` from its components
338 #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
339 pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
340 let mut ts = zero_init_timespec();
341 ts.tv_sec = seconds;
342 ts.tv_nsec = nanoseconds;
343 Self(ts)
344 }
345
346 fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
347 if self.tv_sec() < 0 && self.tv_nsec() > 0 {
348 self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
349 } else {
350 self.tv_nsec()
351 }
352 }
353
354 #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
355 pub const fn tv_sec(&self) -> time_t {
356 self.0.tv_sec
357 }
358
359 pub const fn tv_nsec(&self) -> timespec_tv_nsec_t {
360 self.0.tv_nsec
361 }
362
363 #[cfg_attr(target_env = "musl", allow(deprecated))]
364 // https://github.com/rust-lang/libc/issues/1848
365 pub const fn from_duration(duration: Duration) -> Self {
366 let mut ts = zero_init_timespec();
367 ts.tv_sec = duration.as_secs() as time_t;
368 ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t;
369 TimeSpec(ts)
370 }
371
372 pub const fn from_timespec(timespec: timespec) -> Self {
373 Self(timespec)
374 }
375}
376
377impl ops::Neg for TimeSpec {
378 type Output = TimeSpec;
379
380 fn neg(self) -> TimeSpec {
381 TimeSpec::nanoseconds(-self.num_nanoseconds())
382 }
383}
384
385impl ops::Add for TimeSpec {
386 type Output = TimeSpec;
387
388 fn add(self, rhs: TimeSpec) -> TimeSpec {
389 TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds())
390 }
391}
392
393impl ops::Sub for TimeSpec {
394 type Output = TimeSpec;
395
396 fn sub(self, rhs: TimeSpec) -> TimeSpec {
397 TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds())
398 }
399}
400
401impl ops::Mul<i32> for TimeSpec {
402 type Output = TimeSpec;
403
404 fn mul(self, rhs: i32) -> TimeSpec {
405 let usec = self
406 .num_nanoseconds()
407 .checked_mul(i64::from(rhs))
408 .expect("TimeSpec multiply out of bounds");
409
410 TimeSpec::nanoseconds(usec)
411 }
412}
413
414impl ops::Div<i32> for TimeSpec {
415 type Output = TimeSpec;
416
417 fn div(self, rhs: i32) -> TimeSpec {
418 let usec = self.num_nanoseconds() / i64::from(rhs);
419 TimeSpec::nanoseconds(usec)
420 }
421}
422
423impl fmt::Display for TimeSpec {
424 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425 let (abs, sign) = if self.tv_sec() < 0 {
426 (-*self, "-")
427 } else {
428 (*self, "")
429 };
430
431 let sec = abs.tv_sec();
432
433 write!(f, "{sign}")?;
434
435 if abs.tv_nsec() == 0 {
436 if sec == 1 {
437 write!(f, "1 second")?;
438 } else {
439 write!(f, "{sec} seconds")?;
440 }
441 } else if abs.tv_nsec() % 1_000_000 == 0 {
442 write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?;
443 } else if abs.tv_nsec() % 1_000 == 0 {
444 write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?;
445 } else {
446 write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?;
447 }
448
449 Ok(())
450 }
451}
452
453#[repr(transparent)]
454#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
455pub struct TimeVal(timeval);
456
457const MICROS_PER_SEC: i64 = 1_000_000;
458
459#[cfg(target_pointer_width = "64")]
460const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1;
461
462#[cfg(target_pointer_width = "32")]
463const TV_MAX_SECONDS: i64 = isize::MAX as i64;
464
465const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
466
467impl AsRef<timeval> for TimeVal {
468 fn as_ref(&self) -> &timeval {
469 &self.0
470 }
471}
472
473impl AsMut<timeval> for TimeVal {
474 fn as_mut(&mut self) -> &mut timeval {
475 &mut self.0
476 }
477}
478
479impl Ord for TimeVal {
480 // The implementation of cmp is simplified by assuming that the struct is
481 // normalized. That is, tv_usec must always be within [0, 1_000_000)
482 fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
483 if self.tv_sec() == other.tv_sec() {
484 self.tv_usec().cmp(&other.tv_usec())
485 } else {
486 self.tv_sec().cmp(&other.tv_sec())
487 }
488 }
489}
490
491impl PartialOrd for TimeVal {
492 fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
493 Some(self.cmp(other))
494 }
495}
496
497impl TimeValLike for TimeVal {
498 #[inline]
499 fn seconds(seconds: i64) -> TimeVal {
500 assert!(
501 (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds),
502 "TimeVal out of bounds; seconds={seconds}"
503 );
504 #[cfg_attr(target_env = "musl", allow(deprecated))]
505 // https://github.com/rust-lang/libc/issues/1848
506 TimeVal(timeval {
507 tv_sec: seconds as time_t,
508 tv_usec: 0,
509 })
510 }
511
512 #[inline]
513 fn milliseconds(milliseconds: i64) -> TimeVal {
514 let microseconds = milliseconds
515 .checked_mul(1_000)
516 .expect("TimeVal::milliseconds out of bounds");
517
518 TimeVal::microseconds(microseconds)
519 }
520
521 /// Makes a new `TimeVal` with given number of microseconds.
522 #[inline]
523 fn microseconds(microseconds: i64) -> TimeVal {
524 let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
525 assert!(
526 (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
527 "TimeVal out of bounds"
528 );
529 #[cfg_attr(target_env = "musl", allow(deprecated))]
530 // https://github.com/rust-lang/libc/issues/1848
531 TimeVal(timeval {
532 tv_sec: secs as time_t,
533 tv_usec: micros as suseconds_t,
534 })
535 }
536
537 /// Makes a new `TimeVal` with given number of nanoseconds. Some precision
538 /// will be lost
539 #[inline]
540 fn nanoseconds(nanoseconds: i64) -> TimeVal {
541 let microseconds = nanoseconds / 1000;
542 let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
543 assert!(
544 (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
545 "TimeVal out of bounds"
546 );
547 #[cfg_attr(target_env = "musl", allow(deprecated))]
548 // https://github.com/rust-lang/libc/issues/1848
549 TimeVal(timeval {
550 tv_sec: secs as time_t,
551 tv_usec: micros as suseconds_t,
552 })
553 }
554
555 // The cast is not unnecessary on all platforms.
556 #[allow(clippy::unnecessary_cast)]
557 fn num_seconds(&self) -> i64 {
558 if self.tv_sec() < 0 && self.tv_usec() > 0 {
559 (self.tv_sec() + 1) as i64
560 } else {
561 self.tv_sec() as i64
562 }
563 }
564
565 fn num_milliseconds(&self) -> i64 {
566 self.num_microseconds() / 1_000
567 }
568
569 // The cast is not unnecessary on all platforms.
570 #[allow(clippy::unnecessary_cast)]
571 fn num_microseconds(&self) -> i64 {
572 let secs = self.num_seconds() * 1_000_000;
573 let usec = self.micros_mod_sec();
574 secs + usec as i64
575 }
576
577 fn num_nanoseconds(&self) -> i64 {
578 self.num_microseconds() * 1_000
579 }
580}
581
582impl TimeVal {
583 /// Construct a new `TimeVal` from its components
584 #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
585 pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self {
586 Self(timeval {
587 tv_sec: seconds,
588 tv_usec: microseconds,
589 })
590 }
591
592 fn micros_mod_sec(&self) -> suseconds_t {
593 if self.tv_sec() < 0 && self.tv_usec() > 0 {
594 self.tv_usec() - MICROS_PER_SEC as suseconds_t
595 } else {
596 self.tv_usec()
597 }
598 }
599
600 #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
601 pub const fn tv_sec(&self) -> time_t {
602 self.0.tv_sec
603 }
604
605 pub const fn tv_usec(&self) -> suseconds_t {
606 self.0.tv_usec
607 }
608}
609
610impl ops::Neg for TimeVal {
611 type Output = TimeVal;
612
613 fn neg(self) -> TimeVal {
614 TimeVal::microseconds(-self.num_microseconds())
615 }
616}
617
618impl ops::Add for TimeVal {
619 type Output = TimeVal;
620
621 fn add(self, rhs: TimeVal) -> TimeVal {
622 TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds())
623 }
624}
625
626impl ops::Sub for TimeVal {
627 type Output = TimeVal;
628
629 fn sub(self, rhs: TimeVal) -> TimeVal {
630 TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds())
631 }
632}
633
634impl ops::Mul<i32> for TimeVal {
635 type Output = TimeVal;
636
637 fn mul(self, rhs: i32) -> TimeVal {
638 let usec = self
639 .num_microseconds()
640 .checked_mul(i64::from(rhs))
641 .expect("TimeVal multiply out of bounds");
642
643 TimeVal::microseconds(usec)
644 }
645}
646
647impl ops::Div<i32> for TimeVal {
648 type Output = TimeVal;
649
650 fn div(self, rhs: i32) -> TimeVal {
651 let usec = self.num_microseconds() / i64::from(rhs);
652 TimeVal::microseconds(usec)
653 }
654}
655
656impl fmt::Display for TimeVal {
657 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
658 let (abs, sign) = if self.tv_sec() < 0 {
659 (-*self, "-")
660 } else {
661 (*self, "")
662 };
663
664 let sec = abs.tv_sec();
665
666 write!(f, "{sign}")?;
667
668 if abs.tv_usec() == 0 {
669 if sec == 1 {
670 write!(f, "1 second")?;
671 } else {
672 write!(f, "{sec} seconds")?;
673 }
674 } else if abs.tv_usec() % 1000 == 0 {
675 write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?;
676 } else {
677 write!(f, "{sec}.{:06} seconds", abs.tv_usec())?;
678 }
679
680 Ok(())
681 }
682}
683
684impl From<timeval> for TimeVal {
685 fn from(tv: timeval) -> Self {
686 TimeVal(tv)
687 }
688}
689
690#[inline]
691fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
692 (div_floor_64(this, other), mod_floor_64(this, other))
693}
694
695#[inline]
696fn div_floor_64(this: i64, other: i64) -> i64 {
697 match div_rem_64(this, other) {
698 (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1,
699 (d, _) => d,
700 }
701}
702
703#[inline]
704fn mod_floor_64(this: i64, other: i64) -> i64 {
705 match this % other {
706 r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other,
707 r => r,
708 }
709}
710
711#[inline]
712fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
713 (this / other, this % other)
714}
715
716#[cfg(test)]
717mod test {
718 use super::{TimeSpec, TimeVal, TimeValLike};
719 use std::time::Duration;
720
721 #[test]
722 pub fn test_timespec() {
723 assert_ne!(TimeSpec::seconds(1), TimeSpec::zero());
724 assert_eq!(
725 TimeSpec::seconds(1) + TimeSpec::seconds(2),
726 TimeSpec::seconds(3)
727 );
728 assert_eq!(
729 TimeSpec::minutes(3) + TimeSpec::seconds(2),
730 TimeSpec::seconds(182)
731 );
732 }
733
734 #[test]
735 pub fn test_timespec_from() {
736 let duration = Duration::new(123, 123_456_789);
737 let timespec = TimeSpec::nanoseconds(123_123_456_789);
738
739 assert_eq!(TimeSpec::from(duration), timespec);
740 assert_eq!(Duration::from(timespec), duration);
741 }
742
743 #[test]
744 pub fn test_timespec_neg() {
745 let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
746 let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
747
748 assert_eq!(a, -b);
749 }
750
751 #[test]
752 pub fn test_timespec_ord() {
753 assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000));
754 assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
755 assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
756 assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
757 assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
758 }
759
760 #[test]
761 pub fn test_timespec_fmt() {
762 assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
763 assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
764 assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
765 assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
766 assert_eq!(
767 TimeSpec::nanoseconds(42).to_string(),
768 "0.000000042 seconds"
769 );
770 assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
771 }
772
773 #[test]
774 pub fn test_timeval() {
775 assert_ne!(TimeVal::seconds(1), TimeVal::zero());
776 assert_eq!(
777 TimeVal::seconds(1) + TimeVal::seconds(2),
778 TimeVal::seconds(3)
779 );
780 assert_eq!(
781 TimeVal::minutes(3) + TimeVal::seconds(2),
782 TimeVal::seconds(182)
783 );
784 }
785
786 #[test]
787 pub fn test_timeval_ord() {
788 assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000));
789 assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
790 assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
791 assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
792 assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
793 }
794
795 #[test]
796 pub fn test_timeval_neg() {
797 let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
798 let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
799
800 assert_eq!(a, -b);
801 }
802
803 #[test]
804 pub fn test_timeval_fmt() {
805 assert_eq!(TimeVal::zero().to_string(), "0 seconds");
806 assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
807 assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
808 assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
809 assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
810 assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
811 }
812}
813