nix/sys/
time.rs

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