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