Coverage Report

Created: 2026-02-14 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nix-0.30.1/src/sys/time.rs
Line
Count
Source
1
#[cfg_attr(
2
    any(target_env = "musl", target_env = "ohos"),
3
    allow(deprecated)
4
)]
5
// https://github.com/rust-lang/libc/issues/1848
6
pub use libc::{suseconds_t, time_t};
7
use libc::{timespec, timeval};
8
use std::time::Duration;
9
use std::{cmp, fmt, ops};
10
11
0
const 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
0
    unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) }
16
0
}
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
))]
31
pub(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
143
pub trait TimeValLike: Sized {
144
    #[inline]
145
0
    fn zero() -> Self {
146
0
        Self::seconds(0)
147
0
    }
148
149
    #[inline]
150
0
    fn hours(hours: i64) -> Self {
151
0
        let secs = hours
152
0
            .checked_mul(SECS_PER_HOUR)
153
0
            .expect("TimeValLike::hours ouf of bounds");
154
0
        Self::seconds(secs)
155
0
    }
156
157
    #[inline]
158
0
    fn minutes(minutes: i64) -> Self {
159
0
        let secs = minutes
160
0
            .checked_mul(SECS_PER_MINUTE)
161
0
            .expect("TimeValLike::minutes out of bounds");
162
0
        Self::seconds(secs)
163
0
    }
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
0
    fn num_hours(&self) -> i64 {
172
0
        self.num_seconds() / 3600
173
0
    }
174
175
    #[inline]
176
0
    fn num_minutes(&self) -> i64 {
177
0
        self.num_seconds() / 60
178
0
    }
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)]
188
pub struct TimeSpec(timespec);
189
190
const NANOS_PER_SEC: i64 = 1_000_000_000;
191
const SECS_PER_MINUTE: i64 = 60;
192
const SECS_PER_HOUR: i64 = 3600;
193
194
#[cfg(target_pointer_width = "64")]
195
const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1;
196
197
#[cfg(target_pointer_width = "32")]
198
const TS_MAX_SECONDS: i64 = isize::MAX as i64;
199
200
const 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"))]
205
type timespec_tv_nsec_t = i64;
206
#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
207
type timespec_tv_nsec_t = libc::c_long;
208
209
impl From<timespec> for TimeSpec {
210
0
    fn from(ts: timespec) -> Self {
211
0
        Self(ts)
212
0
    }
213
}
214
215
impl From<Duration> for TimeSpec {
216
0
    fn from(duration: Duration) -> Self {
217
0
        Self::from_duration(duration)
218
0
    }
219
}
220
221
impl From<TimeSpec> for Duration {
222
0
    fn from(timespec: TimeSpec) -> Self {
223
0
        Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32)
224
0
    }
225
}
226
227
impl AsRef<timespec> for TimeSpec {
228
0
    fn as_ref(&self) -> &timespec {
229
0
        &self.0
230
0
    }
231
}
232
233
impl AsMut<timespec> for TimeSpec {
234
0
    fn as_mut(&mut self) -> &mut timespec {
235
0
        &mut self.0
236
0
    }
237
}
238
239
impl 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
0
    fn cmp(&self, other: &TimeSpec) -> cmp::Ordering {
243
0
        if self.tv_sec() == other.tv_sec() {
244
0
            self.tv_nsec().cmp(&other.tv_nsec())
245
        } else {
246
0
            self.tv_sec().cmp(&other.tv_sec())
247
        }
248
0
    }
249
}
250
251
impl PartialOrd for TimeSpec {
252
0
    fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
253
0
        Some(self.cmp(other))
254
0
    }
255
}
256
257
impl 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
0
    fn seconds(seconds: i64) -> TimeSpec {
265
0
        assert!(
266
0
            (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
267
0
            "TimeSpec out of bounds; seconds={seconds}",
268
        );
269
0
        let mut ts = zero_init_timespec();
270
0
        ts.tv_sec = seconds as time_t;
271
0
        TimeSpec(ts)
272
0
    }
273
274
    #[inline]
275
0
    fn milliseconds(milliseconds: i64) -> TimeSpec {
276
0
        let nanoseconds = milliseconds
277
0
            .checked_mul(1_000_000)
278
0
            .expect("TimeSpec::milliseconds out of bounds");
279
280
0
        TimeSpec::nanoseconds(nanoseconds)
281
0
    }
282
283
    /// Makes a new `TimeSpec` with given number of microseconds.
284
    #[inline]
285
0
    fn microseconds(microseconds: i64) -> TimeSpec {
286
0
        let nanoseconds = microseconds
287
0
            .checked_mul(1_000)
288
0
            .expect("TimeSpec::milliseconds out of bounds");
289
290
0
        TimeSpec::nanoseconds(nanoseconds)
291
0
    }
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
0
    fn nanoseconds(nanoseconds: i64) -> TimeSpec {
301
0
        let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
302
0
        assert!(
303
0
            (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs),
304
0
            "TimeSpec out of bounds"
305
        );
306
0
        let mut ts = zero_init_timespec();
307
0
        ts.tv_sec = secs as time_t;
308
0
        ts.tv_nsec = nanos as timespec_tv_nsec_t;
309
0
        TimeSpec(ts)
310
0
    }
311
312
    // The cast is not unnecessary on all platforms.
313
    #[allow(clippy::unnecessary_cast)]
314
0
    fn num_seconds(&self) -> i64 {
315
0
        if self.tv_sec() < 0 && self.tv_nsec() > 0 {
316
0
            (self.tv_sec() + 1) as i64
317
        } else {
318
0
            self.tv_sec() as i64
319
        }
320
0
    }
321
322
0
    fn num_milliseconds(&self) -> i64 {
323
0
        self.num_nanoseconds() / 1_000_000
324
0
    }
325
326
0
    fn num_microseconds(&self) -> i64 {
327
0
        self.num_nanoseconds() / 1_000
328
0
    }
329
330
    // The cast is not unnecessary on all platforms.
331
    #[allow(clippy::unnecessary_cast)]
332
0
    fn num_nanoseconds(&self) -> i64 {
333
0
        let secs = self.num_seconds() * 1_000_000_000;
334
0
        let nsec = self.nanos_mod_sec();
335
0
        secs + nsec as i64
336
0
    }
337
}
338
339
impl 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
0
    pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
357
0
        let mut ts = zero_init_timespec();
358
0
        ts.tv_sec = seconds;
359
0
        ts.tv_nsec = nanoseconds;
360
0
        Self(ts)
361
0
    }
362
363
0
    fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
364
0
        if self.tv_sec() < 0 && self.tv_nsec() > 0 {
365
0
            self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
366
        } else {
367
0
            self.tv_nsec()
368
        }
369
0
    }
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
0
    pub const fn tv_sec(&self) -> time_t {
376
0
        self.0.tv_sec
377
0
    }
378
379
0
    pub const fn tv_nsec(&self) -> timespec_tv_nsec_t {
380
0
        self.0.tv_nsec
381
0
    }
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
0
    pub const fn from_duration(duration: Duration) -> Self {
389
0
        let mut ts = zero_init_timespec();
390
0
        ts.tv_sec = duration.as_secs() as time_t;
391
0
        ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t;
392
0
        TimeSpec(ts)
393
0
    }
394
395
0
    pub const fn from_timespec(timespec: timespec) -> Self {
396
0
        Self(timespec)
397
0
    }
398
}
399
400
impl ops::Neg for TimeSpec {
401
    type Output = TimeSpec;
402
403
0
    fn neg(self) -> TimeSpec {
404
0
        TimeSpec::nanoseconds(-self.num_nanoseconds())
405
0
    }
406
}
407
408
impl ops::Add for TimeSpec {
409
    type Output = TimeSpec;
410
411
0
    fn add(self, rhs: TimeSpec) -> TimeSpec {
412
0
        TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds())
413
0
    }
414
}
415
416
impl ops::Sub for TimeSpec {
417
    type Output = TimeSpec;
418
419
0
    fn sub(self, rhs: TimeSpec) -> TimeSpec {
420
0
        TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds())
421
0
    }
422
}
423
424
impl ops::Mul<i32> for TimeSpec {
425
    type Output = TimeSpec;
426
427
0
    fn mul(self, rhs: i32) -> TimeSpec {
428
0
        let usec = self
429
0
            .num_nanoseconds()
430
0
            .checked_mul(i64::from(rhs))
431
0
            .expect("TimeSpec multiply out of bounds");
432
433
0
        TimeSpec::nanoseconds(usec)
434
0
    }
435
}
436
437
impl ops::Div<i32> for TimeSpec {
438
    type Output = TimeSpec;
439
440
0
    fn div(self, rhs: i32) -> TimeSpec {
441
0
        let usec = self.num_nanoseconds() / i64::from(rhs);
442
0
        TimeSpec::nanoseconds(usec)
443
0
    }
444
}
445
446
impl fmt::Display for TimeSpec {
447
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
448
0
        let (abs, sign) = if self.tv_sec() < 0 {
449
0
            (-*self, "-")
450
        } else {
451
0
            (*self, "")
452
        };
453
454
0
        let sec = abs.tv_sec();
455
456
0
        write!(f, "{sign}")?;
457
458
0
        if abs.tv_nsec() == 0 {
459
0
            if sec == 1 {
460
0
                write!(f, "1 second")?;
461
            } else {
462
0
                write!(f, "{sec} seconds")?;
463
            }
464
0
        } else if abs.tv_nsec() % 1_000_000 == 0 {
465
0
            write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?;
466
0
        } else if abs.tv_nsec() % 1_000 == 0 {
467
0
            write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?;
468
        } else {
469
0
            write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?;
470
        }
471
472
0
        Ok(())
473
0
    }
474
}
475
476
#[repr(transparent)]
477
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
478
pub struct TimeVal(timeval);
479
480
const MICROS_PER_SEC: i64 = 1_000_000;
481
482
#[cfg(target_pointer_width = "64")]
483
const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1;
484
485
#[cfg(target_pointer_width = "32")]
486
const TV_MAX_SECONDS: i64 = isize::MAX as i64;
487
488
const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
489
490
impl AsRef<timeval> for TimeVal {
491
0
    fn as_ref(&self) -> &timeval {
492
0
        &self.0
493
0
    }
494
}
495
496
impl AsMut<timeval> for TimeVal {
497
0
    fn as_mut(&mut self) -> &mut timeval {
498
0
        &mut self.0
499
0
    }
500
}
501
502
impl 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
0
    fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
506
0
        if self.tv_sec() == other.tv_sec() {
507
0
            self.tv_usec().cmp(&other.tv_usec())
508
        } else {
509
0
            self.tv_sec().cmp(&other.tv_sec())
510
        }
511
0
    }
512
}
513
514
impl PartialOrd for TimeVal {
515
0
    fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
516
0
        Some(self.cmp(other))
517
0
    }
518
}
519
520
impl TimeValLike for TimeVal {
521
    #[inline]
522
0
    fn seconds(seconds: i64) -> TimeVal {
523
0
        assert!(
524
0
            (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds),
525
0
            "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
0
        TimeVal(timeval {
533
0
            tv_sec: seconds as time_t,
534
0
            tv_usec: 0,
535
0
        })
536
0
    }
537
538
    #[inline]
539
0
    fn milliseconds(milliseconds: i64) -> TimeVal {
540
0
        let microseconds = milliseconds
541
0
            .checked_mul(1_000)
542
0
            .expect("TimeVal::milliseconds out of bounds");
543
544
0
        TimeVal::microseconds(microseconds)
545
0
    }
546
547
    /// Makes a new `TimeVal` with given number of microseconds.
548
    #[inline]
549
0
    fn microseconds(microseconds: i64) -> TimeVal {
550
0
        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
551
0
        assert!(
552
0
            (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
553
0
            "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
0
        TimeVal(timeval {
561
0
            tv_sec: secs as time_t,
562
0
            tv_usec: micros as suseconds_t,
563
0
        })
564
0
    }
565
566
    /// Makes a new `TimeVal` with given number of nanoseconds.  Some precision
567
    /// will be lost
568
    #[inline]
569
0
    fn nanoseconds(nanoseconds: i64) -> TimeVal {
570
0
        let microseconds = nanoseconds / 1000;
571
0
        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
572
0
        assert!(
573
0
            (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
574
0
            "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
0
        TimeVal(timeval {
582
0
            tv_sec: secs as time_t,
583
0
            tv_usec: micros as suseconds_t,
584
0
        })
585
0
    }
586
587
    // The cast is not unnecessary on all platforms.
588
    #[allow(clippy::unnecessary_cast)]
589
0
    fn num_seconds(&self) -> i64 {
590
0
        if self.tv_sec() < 0 && self.tv_usec() > 0 {
591
0
            (self.tv_sec() + 1) as i64
592
        } else {
593
0
            self.tv_sec() as i64
594
        }
595
0
    }
596
597
0
    fn num_milliseconds(&self) -> i64 {
598
0
        self.num_microseconds() / 1_000
599
0
    }
600
601
    // The cast is not unnecessary on all platforms.
602
    #[allow(clippy::unnecessary_cast)]
603
0
    fn num_microseconds(&self) -> i64 {
604
0
        let secs = self.num_seconds() * 1_000_000;
605
0
        let usec = self.micros_mod_sec();
606
0
        secs + usec as i64
607
0
    }
608
609
0
    fn num_nanoseconds(&self) -> i64 {
610
0
        self.num_microseconds() * 1_000
611
0
    }
612
}
613
614
impl 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
0
    pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self {
621
0
        Self(timeval {
622
0
            tv_sec: seconds,
623
0
            tv_usec: microseconds,
624
0
        })
625
0
    }
626
627
0
    fn micros_mod_sec(&self) -> suseconds_t {
628
0
        if self.tv_sec() < 0 && self.tv_usec() > 0 {
629
0
            self.tv_usec() - MICROS_PER_SEC as suseconds_t
630
        } else {
631
0
            self.tv_usec()
632
        }
633
0
    }
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
0
    pub const fn tv_sec(&self) -> time_t {
640
0
        self.0.tv_sec
641
0
    }
642
643
0
    pub const fn tv_usec(&self) -> suseconds_t {
644
0
        self.0.tv_usec
645
0
    }
646
}
647
648
impl ops::Neg for TimeVal {
649
    type Output = TimeVal;
650
651
0
    fn neg(self) -> TimeVal {
652
0
        TimeVal::microseconds(-self.num_microseconds())
653
0
    }
654
}
655
656
impl ops::Add for TimeVal {
657
    type Output = TimeVal;
658
659
0
    fn add(self, rhs: TimeVal) -> TimeVal {
660
0
        TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds())
661
0
    }
662
}
663
664
impl ops::Sub for TimeVal {
665
    type Output = TimeVal;
666
667
0
    fn sub(self, rhs: TimeVal) -> TimeVal {
668
0
        TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds())
669
0
    }
670
}
671
672
impl ops::Mul<i32> for TimeVal {
673
    type Output = TimeVal;
674
675
0
    fn mul(self, rhs: i32) -> TimeVal {
676
0
        let usec = self
677
0
            .num_microseconds()
678
0
            .checked_mul(i64::from(rhs))
679
0
            .expect("TimeVal multiply out of bounds");
680
681
0
        TimeVal::microseconds(usec)
682
0
    }
683
}
684
685
impl ops::Div<i32> for TimeVal {
686
    type Output = TimeVal;
687
688
0
    fn div(self, rhs: i32) -> TimeVal {
689
0
        let usec = self.num_microseconds() / i64::from(rhs);
690
0
        TimeVal::microseconds(usec)
691
0
    }
692
}
693
694
impl fmt::Display for TimeVal {
695
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
696
0
        let (abs, sign) = if self.tv_sec() < 0 {
697
0
            (-*self, "-")
698
        } else {
699
0
            (*self, "")
700
        };
701
702
0
        let sec = abs.tv_sec();
703
704
0
        write!(f, "{sign}")?;
705
706
0
        if abs.tv_usec() == 0 {
707
0
            if sec == 1 {
708
0
                write!(f, "1 second")?;
709
            } else {
710
0
                write!(f, "{sec} seconds")?;
711
            }
712
0
        } else if abs.tv_usec() % 1000 == 0 {
713
0
            write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?;
714
        } else {
715
0
            write!(f, "{sec}.{:06} seconds", abs.tv_usec())?;
716
        }
717
718
0
        Ok(())
719
0
    }
720
}
721
722
impl From<timeval> for TimeVal {
723
0
    fn from(tv: timeval) -> Self {
724
0
        TimeVal(tv)
725
0
    }
726
}
727
728
#[inline]
729
0
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
730
0
    (div_floor_64(this, other), mod_floor_64(this, other))
731
0
}
732
733
#[inline]
734
0
fn div_floor_64(this: i64, other: i64) -> i64 {
735
0
    match div_rem_64(this, other) {
736
0
        (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1,
737
0
        (d, _) => d,
738
    }
739
0
}
740
741
#[inline]
742
0
fn mod_floor_64(this: i64, other: i64) -> i64 {
743
0
    match this % other {
744
0
        r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other,
745
0
        r => r,
746
    }
747
0
}
748
749
#[inline]
750
0
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
751
0
    (this / other, this % other)
752
0
}