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