Coverage Report

Created: 2026-11-12 06:53

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