1 #[cfg_attr(target_env = "musl", allow(deprecated))]
2 // https://github.com/rust-lang/libc/issues/1848
3 pub use libc::{suseconds_t, time_t};
4 use libc::{timespec, timeval};
5 use std::time::Duration;
6 use std::{cmp, fmt, ops};
7 
zero_init_timespec() -> timespec8 const fn zero_init_timespec() -> timespec {
9     // `std::mem::MaybeUninit::zeroed()` is not yet a const fn
10     // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of
11     // the appropriate size to zero and then transmute it to a timespec value.
12     unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) }
13 }
14 
15 #[cfg(any(
16     all(feature = "time", any(target_os = "android", target_os = "linux")),
17     all(
18         any(
19             target_os = "freebsd",
20             solarish,
21             target_os = "linux",
22             target_os = "netbsd"
23         ),
24         feature = "time",
25         feature = "signal"
26     )
27 ))]
28 pub(crate) mod timer {
29     use crate::sys::time::{zero_init_timespec, TimeSpec};
30     use bitflags::bitflags;
31 
32     #[derive(Debug, Clone, Copy)]
33     pub(crate) struct TimerSpec(libc::itimerspec);
34 
35     impl TimerSpec {
none() -> Self36         pub const fn none() -> Self {
37             Self(libc::itimerspec {
38                 it_interval: zero_init_timespec(),
39                 it_value: zero_init_timespec(),
40             })
41         }
42     }
43 
44     impl AsMut<libc::itimerspec> for TimerSpec {
as_mut(&mut self) -> &mut libc::itimerspec45         fn as_mut(&mut self) -> &mut libc::itimerspec {
46             &mut self.0
47         }
48     }
49 
50     impl AsRef<libc::itimerspec> for TimerSpec {
as_ref(&self) -> &libc::itimerspec51         fn as_ref(&self) -> &libc::itimerspec {
52             &self.0
53         }
54     }
55 
56     impl From<Expiration> for TimerSpec {
from(expiration: Expiration) -> TimerSpec57         fn from(expiration: Expiration) -> TimerSpec {
58             match expiration {
59                 Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
60                     it_interval: zero_init_timespec(),
61                     it_value: *t.as_ref(),
62                 }),
63                 Expiration::IntervalDelayed(start, interval) => {
64                     TimerSpec(libc::itimerspec {
65                         it_interval: *interval.as_ref(),
66                         it_value: *start.as_ref(),
67                     })
68                 }
69                 Expiration::Interval(t) => TimerSpec(libc::itimerspec {
70                     it_interval: *t.as_ref(),
71                     it_value: *t.as_ref(),
72                 }),
73             }
74         }
75     }
76 
77     /// An enumeration allowing the definition of the expiration time of an alarm,
78     /// recurring or not.
79     #[derive(Debug, Clone, Copy, Eq, PartialEq)]
80     pub enum Expiration {
81         /// Alarm will trigger once after the time given in `TimeSpec`
82         OneShot(TimeSpec),
83         /// Alarm will trigger after a specified delay and then every interval of
84         /// time.
85         IntervalDelayed(TimeSpec, TimeSpec),
86         /// Alarm will trigger every specified interval of time.
87         Interval(TimeSpec),
88     }
89 
90     #[cfg(linux_android)]
91     bitflags! {
92         /// Flags that are used for arming the timer.
93         #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
94         pub struct TimerSetTimeFlags: libc::c_int {
95             const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
96             const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET;
97         }
98     }
99     #[cfg(any(freebsdlike, target_os = "netbsd", solarish))]
100     bitflags! {
101         /// Flags that are used for arming the timer.
102         #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
103         pub struct TimerSetTimeFlags: libc::c_int {
104             const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME;
105         }
106     }
107 
108     impl From<TimerSpec> for Expiration {
from(timerspec: TimerSpec) -> Expiration109         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 
140 pub trait TimeValLike: Sized {
141     #[inline]
zero() -> Self142     fn zero() -> Self {
143         Self::seconds(0)
144     }
145 
146     #[inline]
hours(hours: i64) -> Self147     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]
minutes(minutes: i64) -> Self155     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 
seconds(seconds: i64) -> Self162     fn seconds(seconds: i64) -> Self;
milliseconds(milliseconds: i64) -> Self163     fn milliseconds(milliseconds: i64) -> Self;
microseconds(microseconds: i64) -> Self164     fn microseconds(microseconds: i64) -> Self;
nanoseconds(nanoseconds: i64) -> Self165     fn nanoseconds(nanoseconds: i64) -> Self;
166 
167     #[inline]
num_hours(&self) -> i64168     fn num_hours(&self) -> i64 {
169         self.num_seconds() / 3600
170     }
171 
172     #[inline]
num_minutes(&self) -> i64173     fn num_minutes(&self) -> i64 {
174         self.num_seconds() / 60
175     }
176 
num_seconds(&self) -> i64177     fn num_seconds(&self) -> i64;
num_milliseconds(&self) -> i64178     fn num_milliseconds(&self) -> i64;
num_microseconds(&self) -> i64179     fn num_microseconds(&self) -> i64;
num_nanoseconds(&self) -> i64180     fn num_nanoseconds(&self) -> i64;
181 }
182 
183 #[repr(C)]
184 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
185 pub struct TimeSpec(timespec);
186 
187 const NANOS_PER_SEC: i64 = 1_000_000_000;
188 const SECS_PER_MINUTE: i64 = 60;
189 const SECS_PER_HOUR: i64 = 3600;
190 
191 #[cfg(target_pointer_width = "64")]
192 const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1;
193 
194 #[cfg(target_pointer_width = "32")]
195 const TS_MAX_SECONDS: i64 = isize::MAX as i64;
196 
197 const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
198 
199 // x32 compatibility
200 // See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
201 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
202 type timespec_tv_nsec_t = i64;
203 #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
204 type timespec_tv_nsec_t = libc::c_long;
205 
206 impl From<timespec> for TimeSpec {
from(ts: timespec) -> Self207     fn from(ts: timespec) -> Self {
208         Self(ts)
209     }
210 }
211 
212 impl From<Duration> for TimeSpec {
from(duration: Duration) -> Self213     fn from(duration: Duration) -> Self {
214         Self::from_duration(duration)
215     }
216 }
217 
218 impl From<TimeSpec> for Duration {
from(timespec: TimeSpec) -> Self219     fn from(timespec: TimeSpec) -> Self {
220         Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32)
221     }
222 }
223 
224 impl AsRef<timespec> for TimeSpec {
as_ref(&self) -> &timespec225     fn as_ref(&self) -> &timespec {
226         &self.0
227     }
228 }
229 
230 impl AsMut<timespec> for TimeSpec {
as_mut(&mut self) -> &mut timespec231     fn as_mut(&mut self) -> &mut timespec {
232         &mut self.0
233     }
234 }
235 
236 impl Ord for TimeSpec {
237     // The implementation of cmp is simplified by assuming that the struct is
238     // normalized.  That is, tv_nsec must always be within [0, 1_000_000_000)
cmp(&self, other: &TimeSpec) -> cmp::Ordering239     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 
248 impl PartialOrd for TimeSpec {
partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering>249     fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
250         Some(self.cmp(other))
251     }
252 }
253 
254 impl TimeValLike for TimeSpec {
255     #[inline]
256     #[cfg_attr(target_env = "musl", allow(deprecated))]
257     // https://github.com/rust-lang/libc/issues/1848
seconds(seconds: i64) -> TimeSpec258     fn seconds(seconds: i64) -> TimeSpec {
259         assert!(
260             (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
261             "TimeSpec out of bounds; seconds={seconds}",
262         );
263         let mut ts = zero_init_timespec();
264         ts.tv_sec = seconds as time_t;
265         TimeSpec(ts)
266     }
267 
268     #[inline]
milliseconds(milliseconds: i64) -> TimeSpec269     fn milliseconds(milliseconds: i64) -> TimeSpec {
270         let nanoseconds = milliseconds
271             .checked_mul(1_000_000)
272             .expect("TimeSpec::milliseconds out of bounds");
273 
274         TimeSpec::nanoseconds(nanoseconds)
275     }
276 
277     /// Makes a new `TimeSpec` with given number of microseconds.
278     #[inline]
microseconds(microseconds: i64) -> TimeSpec279     fn microseconds(microseconds: i64) -> TimeSpec {
280         let nanoseconds = microseconds
281             .checked_mul(1_000)
282             .expect("TimeSpec::milliseconds out of bounds");
283 
284         TimeSpec::nanoseconds(nanoseconds)
285     }
286 
287     /// Makes a new `TimeSpec` with given number of nanoseconds.
288     #[inline]
289     #[cfg_attr(target_env = "musl", allow(deprecated))]
290     // https://github.com/rust-lang/libc/issues/1848
nanoseconds(nanoseconds: i64) -> TimeSpec291     fn nanoseconds(nanoseconds: i64) -> TimeSpec {
292         let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
293         assert!(
294             (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs),
295             "TimeSpec out of bounds"
296         );
297         let mut ts = zero_init_timespec();
298         ts.tv_sec = secs as time_t;
299         ts.tv_nsec = nanos as timespec_tv_nsec_t;
300         TimeSpec(ts)
301     }
302 
303     // The cast is not unnecessary on all platforms.
304     #[allow(clippy::unnecessary_cast)]
num_seconds(&self) -> i64305     fn num_seconds(&self) -> i64 {
306         if self.tv_sec() < 0 && self.tv_nsec() > 0 {
307             (self.tv_sec() + 1) as i64
308         } else {
309             self.tv_sec() as i64
310         }
311     }
312 
num_milliseconds(&self) -> i64313     fn num_milliseconds(&self) -> i64 {
314         self.num_nanoseconds() / 1_000_000
315     }
316 
num_microseconds(&self) -> i64317     fn num_microseconds(&self) -> i64 {
318         self.num_nanoseconds() / 1_000
319     }
320 
321     // The cast is not unnecessary on all platforms.
322     #[allow(clippy::unnecessary_cast)]
num_nanoseconds(&self) -> i64323     fn num_nanoseconds(&self) -> i64 {
324         let secs = self.num_seconds() * 1_000_000_000;
325         let nsec = self.nanos_mod_sec();
326         secs + nsec as i64
327     }
328 }
329 
330 impl TimeSpec {
331     /// Leave the timestamp unchanged.
332     #[cfg(not(target_os = "redox"))]
333     // At the time of writing this PR, redox does not support this feature
334     pub const UTIME_OMIT: TimeSpec =
335         TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t);
336     /// Update the timestamp to `Now`
337     // At the time of writing this PR, redox does not support this feature
338     #[cfg(not(target_os = "redox"))]
339     pub const UTIME_NOW: TimeSpec =
340         TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t);
341 
342     /// Construct a new `TimeSpec` from its components
343     #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self344     pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
345         let mut ts = zero_init_timespec();
346         ts.tv_sec = seconds;
347         ts.tv_nsec = nanoseconds;
348         Self(ts)
349     }
350 
nanos_mod_sec(&self) -> timespec_tv_nsec_t351     fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
352         if self.tv_sec() < 0 && self.tv_nsec() > 0 {
353             self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
354         } else {
355             self.tv_nsec()
356         }
357     }
358 
359     #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
tv_sec(&self) -> time_t360     pub const fn tv_sec(&self) -> time_t {
361         self.0.tv_sec
362     }
363 
tv_nsec(&self) -> timespec_tv_nsec_t364     pub const fn tv_nsec(&self) -> timespec_tv_nsec_t {
365         self.0.tv_nsec
366     }
367 
368     #[cfg_attr(target_env = "musl", allow(deprecated))]
369     // https://github.com/rust-lang/libc/issues/1848
from_duration(duration: Duration) -> Self370     pub const fn from_duration(duration: Duration) -> Self {
371         let mut ts = zero_init_timespec();
372         ts.tv_sec = duration.as_secs() as time_t;
373         ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t;
374         TimeSpec(ts)
375     }
376 
from_timespec(timespec: timespec) -> Self377     pub const fn from_timespec(timespec: timespec) -> Self {
378         Self(timespec)
379     }
380 }
381 
382 impl ops::Neg for TimeSpec {
383     type Output = TimeSpec;
384 
neg(self) -> TimeSpec385     fn neg(self) -> TimeSpec {
386         TimeSpec::nanoseconds(-self.num_nanoseconds())
387     }
388 }
389 
390 impl ops::Add for TimeSpec {
391     type Output = TimeSpec;
392 
add(self, rhs: TimeSpec) -> TimeSpec393     fn add(self, rhs: TimeSpec) -> TimeSpec {
394         TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds())
395     }
396 }
397 
398 impl ops::Sub for TimeSpec {
399     type Output = TimeSpec;
400 
sub(self, rhs: TimeSpec) -> TimeSpec401     fn sub(self, rhs: TimeSpec) -> TimeSpec {
402         TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds())
403     }
404 }
405 
406 impl ops::Mul<i32> for TimeSpec {
407     type Output = TimeSpec;
408 
mul(self, rhs: i32) -> TimeSpec409     fn mul(self, rhs: i32) -> TimeSpec {
410         let usec = self
411             .num_nanoseconds()
412             .checked_mul(i64::from(rhs))
413             .expect("TimeSpec multiply out of bounds");
414 
415         TimeSpec::nanoseconds(usec)
416     }
417 }
418 
419 impl ops::Div<i32> for TimeSpec {
420     type Output = TimeSpec;
421 
div(self, rhs: i32) -> TimeSpec422     fn div(self, rhs: i32) -> TimeSpec {
423         let usec = self.num_nanoseconds() / i64::from(rhs);
424         TimeSpec::nanoseconds(usec)
425     }
426 }
427 
428 impl fmt::Display for TimeSpec {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result429     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
430         let (abs, sign) = if self.tv_sec() < 0 {
431             (-*self, "-")
432         } else {
433             (*self, "")
434         };
435 
436         let sec = abs.tv_sec();
437 
438         write!(f, "{sign}")?;
439 
440         if abs.tv_nsec() == 0 {
441             if sec == 1 {
442                 write!(f, "1 second")?;
443             } else {
444                 write!(f, "{sec} seconds")?;
445             }
446         } else if abs.tv_nsec() % 1_000_000 == 0 {
447             write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?;
448         } else if abs.tv_nsec() % 1_000 == 0 {
449             write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?;
450         } else {
451             write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?;
452         }
453 
454         Ok(())
455     }
456 }
457 
458 #[repr(transparent)]
459 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
460 pub struct TimeVal(timeval);
461 
462 const MICROS_PER_SEC: i64 = 1_000_000;
463 
464 #[cfg(target_pointer_width = "64")]
465 const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1;
466 
467 #[cfg(target_pointer_width = "32")]
468 const TV_MAX_SECONDS: i64 = isize::MAX as i64;
469 
470 const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
471 
472 impl AsRef<timeval> for TimeVal {
as_ref(&self) -> &timeval473     fn as_ref(&self) -> &timeval {
474         &self.0
475     }
476 }
477 
478 impl AsMut<timeval> for TimeVal {
as_mut(&mut self) -> &mut timeval479     fn as_mut(&mut self) -> &mut timeval {
480         &mut self.0
481     }
482 }
483 
484 impl Ord for TimeVal {
485     // The implementation of cmp is simplified by assuming that the struct is
486     // normalized.  That is, tv_usec must always be within [0, 1_000_000)
cmp(&self, other: &TimeVal) -> cmp::Ordering487     fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
488         if self.tv_sec() == other.tv_sec() {
489             self.tv_usec().cmp(&other.tv_usec())
490         } else {
491             self.tv_sec().cmp(&other.tv_sec())
492         }
493     }
494 }
495 
496 impl PartialOrd for TimeVal {
partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering>497     fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
498         Some(self.cmp(other))
499     }
500 }
501 
502 impl TimeValLike for TimeVal {
503     #[inline]
seconds(seconds: i64) -> TimeVal504     fn seconds(seconds: i64) -> TimeVal {
505         assert!(
506             (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds),
507             "TimeVal out of bounds; seconds={seconds}"
508         );
509         #[cfg_attr(target_env = "musl", allow(deprecated))]
510         // https://github.com/rust-lang/libc/issues/1848
511         TimeVal(timeval {
512             tv_sec: seconds as time_t,
513             tv_usec: 0,
514         })
515     }
516 
517     #[inline]
milliseconds(milliseconds: i64) -> TimeVal518     fn milliseconds(milliseconds: i64) -> TimeVal {
519         let microseconds = milliseconds
520             .checked_mul(1_000)
521             .expect("TimeVal::milliseconds out of bounds");
522 
523         TimeVal::microseconds(microseconds)
524     }
525 
526     /// Makes a new `TimeVal` with given number of microseconds.
527     #[inline]
microseconds(microseconds: i64) -> TimeVal528     fn microseconds(microseconds: i64) -> TimeVal {
529         let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
530         assert!(
531             (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
532             "TimeVal out of bounds"
533         );
534         #[cfg_attr(target_env = "musl", allow(deprecated))]
535         // https://github.com/rust-lang/libc/issues/1848
536         TimeVal(timeval {
537             tv_sec: secs as time_t,
538             tv_usec: micros as suseconds_t,
539         })
540     }
541 
542     /// Makes a new `TimeVal` with given number of nanoseconds.  Some precision
543     /// will be lost
544     #[inline]
nanoseconds(nanoseconds: i64) -> TimeVal545     fn nanoseconds(nanoseconds: i64) -> TimeVal {
546         let microseconds = nanoseconds / 1000;
547         let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
548         assert!(
549             (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
550             "TimeVal out of bounds"
551         );
552         #[cfg_attr(target_env = "musl", allow(deprecated))]
553         // https://github.com/rust-lang/libc/issues/1848
554         TimeVal(timeval {
555             tv_sec: secs as time_t,
556             tv_usec: micros as suseconds_t,
557         })
558     }
559 
560     // The cast is not unnecessary on all platforms.
561     #[allow(clippy::unnecessary_cast)]
num_seconds(&self) -> i64562     fn num_seconds(&self) -> i64 {
563         if self.tv_sec() < 0 && self.tv_usec() > 0 {
564             (self.tv_sec() + 1) as i64
565         } else {
566             self.tv_sec() as i64
567         }
568     }
569 
num_milliseconds(&self) -> i64570     fn num_milliseconds(&self) -> i64 {
571         self.num_microseconds() / 1_000
572     }
573 
574     // The cast is not unnecessary on all platforms.
575     #[allow(clippy::unnecessary_cast)]
num_microseconds(&self) -> i64576     fn num_microseconds(&self) -> i64 {
577         let secs = self.num_seconds() * 1_000_000;
578         let usec = self.micros_mod_sec();
579         secs + usec as i64
580     }
581 
num_nanoseconds(&self) -> i64582     fn num_nanoseconds(&self) -> i64 {
583         self.num_microseconds() * 1_000
584     }
585 }
586 
587 impl TimeVal {
588     /// Construct a new `TimeVal` from its components
589     #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
new(seconds: time_t, microseconds: suseconds_t) -> Self590     pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self {
591         Self(timeval {
592             tv_sec: seconds,
593             tv_usec: microseconds,
594         })
595     }
596 
micros_mod_sec(&self) -> suseconds_t597     fn micros_mod_sec(&self) -> suseconds_t {
598         if self.tv_sec() < 0 && self.tv_usec() > 0 {
599             self.tv_usec() - MICROS_PER_SEC as suseconds_t
600         } else {
601             self.tv_usec()
602         }
603     }
604 
605     #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
tv_sec(&self) -> time_t606     pub const fn tv_sec(&self) -> time_t {
607         self.0.tv_sec
608     }
609 
tv_usec(&self) -> suseconds_t610     pub const fn tv_usec(&self) -> suseconds_t {
611         self.0.tv_usec
612     }
613 }
614 
615 impl ops::Neg for TimeVal {
616     type Output = TimeVal;
617 
neg(self) -> TimeVal618     fn neg(self) -> TimeVal {
619         TimeVal::microseconds(-self.num_microseconds())
620     }
621 }
622 
623 impl ops::Add for TimeVal {
624     type Output = TimeVal;
625 
add(self, rhs: TimeVal) -> TimeVal626     fn add(self, rhs: TimeVal) -> TimeVal {
627         TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds())
628     }
629 }
630 
631 impl ops::Sub for TimeVal {
632     type Output = TimeVal;
633 
sub(self, rhs: TimeVal) -> TimeVal634     fn sub(self, rhs: TimeVal) -> TimeVal {
635         TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds())
636     }
637 }
638 
639 impl ops::Mul<i32> for TimeVal {
640     type Output = TimeVal;
641 
mul(self, rhs: i32) -> TimeVal642     fn mul(self, rhs: i32) -> TimeVal {
643         let usec = self
644             .num_microseconds()
645             .checked_mul(i64::from(rhs))
646             .expect("TimeVal multiply out of bounds");
647 
648         TimeVal::microseconds(usec)
649     }
650 }
651 
652 impl ops::Div<i32> for TimeVal {
653     type Output = TimeVal;
654 
div(self, rhs: i32) -> TimeVal655     fn div(self, rhs: i32) -> TimeVal {
656         let usec = self.num_microseconds() / i64::from(rhs);
657         TimeVal::microseconds(usec)
658     }
659 }
660 
661 impl fmt::Display for TimeVal {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result662     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
663         let (abs, sign) = if self.tv_sec() < 0 {
664             (-*self, "-")
665         } else {
666             (*self, "")
667         };
668 
669         let sec = abs.tv_sec();
670 
671         write!(f, "{sign}")?;
672 
673         if abs.tv_usec() == 0 {
674             if sec == 1 {
675                 write!(f, "1 second")?;
676             } else {
677                 write!(f, "{sec} seconds")?;
678             }
679         } else if abs.tv_usec() % 1000 == 0 {
680             write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?;
681         } else {
682             write!(f, "{sec}.{:06} seconds", abs.tv_usec())?;
683         }
684 
685         Ok(())
686     }
687 }
688 
689 impl From<timeval> for TimeVal {
from(tv: timeval) -> Self690     fn from(tv: timeval) -> Self {
691         TimeVal(tv)
692     }
693 }
694 
695 #[inline]
div_mod_floor_64(this: i64, other: i64) -> (i64, i64)696 fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
697     (div_floor_64(this, other), mod_floor_64(this, other))
698 }
699 
700 #[inline]
div_floor_64(this: i64, other: i64) -> i64701 fn div_floor_64(this: i64, other: i64) -> i64 {
702     match div_rem_64(this, other) {
703         (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1,
704         (d, _) => d,
705     }
706 }
707 
708 #[inline]
mod_floor_64(this: i64, other: i64) -> i64709 fn mod_floor_64(this: i64, other: i64) -> i64 {
710     match this % other {
711         r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other,
712         r => r,
713     }
714 }
715 
716 #[inline]
div_rem_64(this: i64, other: i64) -> (i64, i64)717 fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
718     (this / other, this % other)
719 }
720