Coverage Report

Created: 2025-02-25 06:39

/rust/registry/src/index.crates.io-6f17d22bba15001f/nix-0.26.4/src/sys/time.rs
Line
Count
Source (jump to first uncovered line)
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
0
    // `std::mem::MaybeUninit::zeroed()` is not yet a const fn
11
0
    // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of
12
0
    // 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
        pub struct TimerSetTimeFlags: libc::c_int {
95
            const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
96
        }
97
    }
98
    #[cfg(any(
99
        target_os = "freebsd",
100
        target_os = "netbsd",
101
        target_os = "dragonfly",
102
        target_os = "illumos"
103
    ))]
104
    bitflags! {
105
        /// Flags that are used for arming the timer.
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(target_env = "musl", allow(deprecated))]
260
    // https://github.com/rust-lang/libc/issues/1848
261
0
    fn seconds(seconds: i64) -> TimeSpec {
262
0
        assert!(
263
0
            (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds),
264
0
            "TimeSpec out of bounds; seconds={}",
265
            seconds
266
        );
267
0
        let mut ts = zero_init_timespec();
268
0
        ts.tv_sec = seconds as time_t;
269
0
        TimeSpec(ts)
270
0
    }
271
272
    #[inline]
273
0
    fn milliseconds(milliseconds: i64) -> TimeSpec {
274
0
        let nanoseconds = milliseconds
275
0
            .checked_mul(1_000_000)
276
0
            .expect("TimeSpec::milliseconds out of bounds");
277
0
278
0
        TimeSpec::nanoseconds(nanoseconds)
279
0
    }
280
281
    /// Makes a new `TimeSpec` with given number of microseconds.
282
    #[inline]
283
0
    fn microseconds(microseconds: i64) -> TimeSpec {
284
0
        let nanoseconds = microseconds
285
0
            .checked_mul(1_000)
286
0
            .expect("TimeSpec::milliseconds out of bounds");
287
0
288
0
        TimeSpec::nanoseconds(nanoseconds)
289
0
    }
290
291
    /// Makes a new `TimeSpec` with given number of nanoseconds.
292
    #[inline]
293
    #[cfg_attr(target_env = "musl", allow(deprecated))]
294
    // https://github.com/rust-lang/libc/issues/1848
295
0
    fn nanoseconds(nanoseconds: i64) -> TimeSpec {
296
0
        let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
297
0
        assert!(
298
0
            (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs),
299
0
            "TimeSpec out of bounds"
300
0
        );
301
0
        let mut ts = zero_init_timespec();
302
0
        ts.tv_sec = secs as time_t;
303
0
        ts.tv_nsec = nanos as timespec_tv_nsec_t;
304
0
        TimeSpec(ts)
305
0
    }
306
307
    // The cast is not unnecessary on all platforms.
308
    #[allow(clippy::unnecessary_cast)]
309
0
    fn num_seconds(&self) -> i64 {
310
0
        if self.tv_sec() < 0 && self.tv_nsec() > 0 {
311
0
            (self.tv_sec() + 1) as i64
312
        } else {
313
0
            self.tv_sec() as i64
314
        }
315
0
    }
316
317
0
    fn num_milliseconds(&self) -> i64 {
318
0
        self.num_nanoseconds() / 1_000_000
319
0
    }
320
321
0
    fn num_microseconds(&self) -> i64 {
322
0
        self.num_nanoseconds() / 1_000
323
0
    }
324
325
    // The cast is not unnecessary on all platforms.
326
    #[allow(clippy::unnecessary_cast)]
327
0
    fn num_nanoseconds(&self) -> i64 {
328
0
        let secs = self.num_seconds() * 1_000_000_000;
329
0
        let nsec = self.nanos_mod_sec();
330
0
        secs + nsec as i64
331
0
    }
332
}
333
334
impl TimeSpec {
335
    /// Construct a new `TimeSpec` from its components
336
    #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
337
0
    pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self {
338
0
        let mut ts = zero_init_timespec();
339
0
        ts.tv_sec = seconds;
340
0
        ts.tv_nsec = nanoseconds;
341
0
        Self(ts)
342
0
    }
343
344
0
    fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
345
0
        if self.tv_sec() < 0 && self.tv_nsec() > 0 {
346
0
            self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
347
        } else {
348
0
            self.tv_nsec()
349
        }
350
0
    }
351
352
    #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
353
0
    pub const fn tv_sec(&self) -> time_t {
354
0
        self.0.tv_sec
355
0
    }
356
357
0
    pub const fn tv_nsec(&self) -> timespec_tv_nsec_t {
358
0
        self.0.tv_nsec
359
0
    }
360
361
    #[cfg_attr(target_env = "musl", allow(deprecated))]
362
    // https://github.com/rust-lang/libc/issues/1848
363
0
    pub const fn from_duration(duration: Duration) -> Self {
364
0
        let mut ts = zero_init_timespec();
365
0
        ts.tv_sec = duration.as_secs() as time_t;
366
0
        ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t;
367
0
        TimeSpec(ts)
368
0
    }
369
370
0
    pub const fn from_timespec(timespec: timespec) -> Self {
371
0
        Self(timespec)
372
0
    }
373
}
374
375
impl ops::Neg for TimeSpec {
376
    type Output = TimeSpec;
377
378
0
    fn neg(self) -> TimeSpec {
379
0
        TimeSpec::nanoseconds(-self.num_nanoseconds())
380
0
    }
381
}
382
383
impl ops::Add for TimeSpec {
384
    type Output = TimeSpec;
385
386
0
    fn add(self, rhs: TimeSpec) -> TimeSpec {
387
0
        TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds())
388
0
    }
389
}
390
391
impl ops::Sub for TimeSpec {
392
    type Output = TimeSpec;
393
394
0
    fn sub(self, rhs: TimeSpec) -> TimeSpec {
395
0
        TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds())
396
0
    }
397
}
398
399
impl ops::Mul<i32> for TimeSpec {
400
    type Output = TimeSpec;
401
402
0
    fn mul(self, rhs: i32) -> TimeSpec {
403
0
        let usec = self
404
0
            .num_nanoseconds()
405
0
            .checked_mul(i64::from(rhs))
406
0
            .expect("TimeSpec multiply out of bounds");
407
0
408
0
        TimeSpec::nanoseconds(usec)
409
0
    }
410
}
411
412
impl ops::Div<i32> for TimeSpec {
413
    type Output = TimeSpec;
414
415
0
    fn div(self, rhs: i32) -> TimeSpec {
416
0
        let usec = self.num_nanoseconds() / i64::from(rhs);
417
0
        TimeSpec::nanoseconds(usec)
418
0
    }
419
}
420
421
impl fmt::Display for TimeSpec {
422
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
423
0
        let (abs, sign) = if self.tv_sec() < 0 {
424
0
            (-*self, "-")
425
        } else {
426
0
            (*self, "")
427
        };
428
429
0
        let sec = abs.tv_sec();
430
0
431
0
        write!(f, "{}", sign)?;
432
433
0
        if abs.tv_nsec() == 0 {
434
0
            if abs.tv_sec() == 1 {
435
0
                write!(f, "{} second", sec)?;
436
            } else {
437
0
                write!(f, "{} seconds", sec)?;
438
            }
439
0
        } else if abs.tv_nsec() % 1_000_000 == 0 {
440
0
            write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?;
441
0
        } else if abs.tv_nsec() % 1_000 == 0 {
442
0
            write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?;
443
        } else {
444
0
            write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?;
445
        }
446
447
0
        Ok(())
448
0
    }
449
}
450
451
#[repr(transparent)]
452
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
453
pub struct TimeVal(timeval);
454
455
const MICROS_PER_SEC: i64 = 1_000_000;
456
457
#[cfg(target_pointer_width = "64")]
458
const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1;
459
460
#[cfg(target_pointer_width = "32")]
461
const TV_MAX_SECONDS: i64 = isize::MAX as i64;
462
463
const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
464
465
impl AsRef<timeval> for TimeVal {
466
0
    fn as_ref(&self) -> &timeval {
467
0
        &self.0
468
0
    }
469
}
470
471
impl AsMut<timeval> for TimeVal {
472
0
    fn as_mut(&mut self) -> &mut timeval {
473
0
        &mut self.0
474
0
    }
475
}
476
477
impl Ord for TimeVal {
478
    // The implementation of cmp is simplified by assuming that the struct is
479
    // normalized.  That is, tv_usec must always be within [0, 1_000_000)
480
0
    fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
481
0
        if self.tv_sec() == other.tv_sec() {
482
0
            self.tv_usec().cmp(&other.tv_usec())
483
        } else {
484
0
            self.tv_sec().cmp(&other.tv_sec())
485
        }
486
0
    }
487
}
488
489
impl PartialOrd for TimeVal {
490
0
    fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
491
0
        Some(self.cmp(other))
492
0
    }
493
}
494
495
impl TimeValLike for TimeVal {
496
    #[inline]
497
0
    fn seconds(seconds: i64) -> TimeVal {
498
0
        assert!(
499
0
            (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds),
500
0
            "TimeVal out of bounds; seconds={}",
501
            seconds
502
        );
503
        #[cfg_attr(target_env = "musl", allow(deprecated))]
504
        // https://github.com/rust-lang/libc/issues/1848
505
0
        TimeVal(timeval {
506
0
            tv_sec: seconds as time_t,
507
0
            tv_usec: 0,
508
0
        })
509
0
    }
510
511
    #[inline]
512
0
    fn milliseconds(milliseconds: i64) -> TimeVal {
513
0
        let microseconds = milliseconds
514
0
            .checked_mul(1_000)
515
0
            .expect("TimeVal::milliseconds out of bounds");
516
0
517
0
        TimeVal::microseconds(microseconds)
518
0
    }
519
520
    /// Makes a new `TimeVal` with given number of microseconds.
521
    #[inline]
522
0
    fn microseconds(microseconds: i64) -> TimeVal {
523
0
        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
524
0
        assert!(
525
0
            (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
526
0
            "TimeVal out of bounds"
527
0
        );
528
        #[cfg_attr(target_env = "musl", allow(deprecated))]
529
        // https://github.com/rust-lang/libc/issues/1848
530
0
        TimeVal(timeval {
531
0
            tv_sec: secs as time_t,
532
0
            tv_usec: micros as suseconds_t,
533
0
        })
534
0
    }
535
536
    /// Makes a new `TimeVal` with given number of nanoseconds.  Some precision
537
    /// will be lost
538
    #[inline]
539
0
    fn nanoseconds(nanoseconds: i64) -> TimeVal {
540
0
        let microseconds = nanoseconds / 1000;
541
0
        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
542
0
        assert!(
543
0
            (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs),
544
0
            "TimeVal out of bounds"
545
0
        );
546
        #[cfg_attr(target_env = "musl", allow(deprecated))]
547
        // https://github.com/rust-lang/libc/issues/1848
548
0
        TimeVal(timeval {
549
0
            tv_sec: secs as time_t,
550
0
            tv_usec: micros as suseconds_t,
551
0
        })
552
0
    }
553
554
    // The cast is not unnecessary on all platforms.
555
    #[allow(clippy::unnecessary_cast)]
556
0
    fn num_seconds(&self) -> i64 {
557
0
        if self.tv_sec() < 0 && self.tv_usec() > 0 {
558
0
            (self.tv_sec() + 1) as i64
559
        } else {
560
0
            self.tv_sec() as i64
561
        }
562
0
    }
563
564
0
    fn num_milliseconds(&self) -> i64 {
565
0
        self.num_microseconds() / 1_000
566
0
    }
567
568
    // The cast is not unnecessary on all platforms.
569
    #[allow(clippy::unnecessary_cast)]
570
0
    fn num_microseconds(&self) -> i64 {
571
0
        let secs = self.num_seconds() * 1_000_000;
572
0
        let usec = self.micros_mod_sec();
573
0
        secs + usec as i64
574
0
    }
575
576
0
    fn num_nanoseconds(&self) -> i64 {
577
0
        self.num_microseconds() * 1_000
578
0
    }
579
}
580
581
impl TimeVal {
582
    /// Construct a new `TimeVal` from its components
583
    #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
584
0
    pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self {
585
0
        Self(timeval {
586
0
            tv_sec: seconds,
587
0
            tv_usec: microseconds,
588
0
        })
589
0
    }
590
591
0
    fn micros_mod_sec(&self) -> suseconds_t {
592
0
        if self.tv_sec() < 0 && self.tv_usec() > 0 {
593
0
            self.tv_usec() - MICROS_PER_SEC as suseconds_t
594
        } else {
595
0
            self.tv_usec()
596
        }
597
0
    }
598
599
    #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
600
0
    pub const fn tv_sec(&self) -> time_t {
601
0
        self.0.tv_sec
602
0
    }
603
604
0
    pub const fn tv_usec(&self) -> suseconds_t {
605
0
        self.0.tv_usec
606
0
    }
607
}
608
609
impl ops::Neg for TimeVal {
610
    type Output = TimeVal;
611
612
0
    fn neg(self) -> TimeVal {
613
0
        TimeVal::microseconds(-self.num_microseconds())
614
0
    }
615
}
616
617
impl ops::Add for TimeVal {
618
    type Output = TimeVal;
619
620
0
    fn add(self, rhs: TimeVal) -> TimeVal {
621
0
        TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds())
622
0
    }
623
}
624
625
impl ops::Sub for TimeVal {
626
    type Output = TimeVal;
627
628
0
    fn sub(self, rhs: TimeVal) -> TimeVal {
629
0
        TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds())
630
0
    }
631
}
632
633
impl ops::Mul<i32> for TimeVal {
634
    type Output = TimeVal;
635
636
0
    fn mul(self, rhs: i32) -> TimeVal {
637
0
        let usec = self
638
0
            .num_microseconds()
639
0
            .checked_mul(i64::from(rhs))
640
0
            .expect("TimeVal multiply out of bounds");
641
0
642
0
        TimeVal::microseconds(usec)
643
0
    }
644
}
645
646
impl ops::Div<i32> for TimeVal {
647
    type Output = TimeVal;
648
649
0
    fn div(self, rhs: i32) -> TimeVal {
650
0
        let usec = self.num_microseconds() / i64::from(rhs);
651
0
        TimeVal::microseconds(usec)
652
0
    }
653
}
654
655
impl fmt::Display for TimeVal {
656
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657
0
        let (abs, sign) = if self.tv_sec() < 0 {
658
0
            (-*self, "-")
659
        } else {
660
0
            (*self, "")
661
        };
662
663
0
        let sec = abs.tv_sec();
664
0
665
0
        write!(f, "{}", sign)?;
666
667
0
        if abs.tv_usec() == 0 {
668
0
            if abs.tv_sec() == 1 {
669
0
                write!(f, "{} second", sec)?;
670
            } else {
671
0
                write!(f, "{} seconds", sec)?;
672
            }
673
0
        } else if abs.tv_usec() % 1000 == 0 {
674
0
            write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?;
675
        } else {
676
0
            write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?;
677
        }
678
679
0
        Ok(())
680
0
    }
681
}
682
683
impl From<timeval> for TimeVal {
684
0
    fn from(tv: timeval) -> Self {
685
0
        TimeVal(tv)
686
0
    }
687
}
688
689
#[inline]
690
0
fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
691
0
    (div_floor_64(this, other), mod_floor_64(this, other))
692
0
}
693
694
#[inline]
695
0
fn div_floor_64(this: i64, other: i64) -> i64 {
696
0
    match div_rem_64(this, other) {
697
0
        (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1,
698
0
        (d, _) => d,
699
    }
700
0
}
701
702
#[inline]
703
0
fn mod_floor_64(this: i64, other: i64) -> i64 {
704
0
    match this % other {
705
0
        r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other,
706
0
        r => r,
707
    }
708
0
}
709
710
#[inline]
711
0
fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
712
0
    (this / other, this % other)
713
0
}
714
715
#[cfg(test)]
716
mod test {
717
    use super::{TimeSpec, TimeVal, TimeValLike};
718
    use std::time::Duration;
719
720
    #[test]
721
    pub fn test_timespec() {
722
        assert_ne!(TimeSpec::seconds(1), TimeSpec::zero());
723
        assert_eq!(
724
            TimeSpec::seconds(1) + TimeSpec::seconds(2),
725
            TimeSpec::seconds(3)
726
        );
727
        assert_eq!(
728
            TimeSpec::minutes(3) + TimeSpec::seconds(2),
729
            TimeSpec::seconds(182)
730
        );
731
    }
732
733
    #[test]
734
    pub fn test_timespec_from() {
735
        let duration = Duration::new(123, 123_456_789);
736
        let timespec = TimeSpec::nanoseconds(123_123_456_789);
737
738
        assert_eq!(TimeSpec::from(duration), timespec);
739
        assert_eq!(Duration::from(timespec), duration);
740
    }
741
742
    #[test]
743
    pub fn test_timespec_neg() {
744
        let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
745
        let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
746
747
        assert_eq!(a, -b);
748
    }
749
750
    #[test]
751
    pub fn test_timespec_ord() {
752
        assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000));
753
        assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
754
        assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
755
        assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
756
        assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
757
    }
758
759
    #[test]
760
    pub fn test_timespec_fmt() {
761
        assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
762
        assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
763
        assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
764
        assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
765
        assert_eq!(
766
            TimeSpec::nanoseconds(42).to_string(),
767
            "0.000000042 seconds"
768
        );
769
        assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
770
    }
771
772
    #[test]
773
    pub fn test_timeval() {
774
        assert_ne!(TimeVal::seconds(1), TimeVal::zero());
775
        assert_eq!(
776
            TimeVal::seconds(1) + TimeVal::seconds(2),
777
            TimeVal::seconds(3)
778
        );
779
        assert_eq!(
780
            TimeVal::minutes(3) + TimeVal::seconds(2),
781
            TimeVal::seconds(182)
782
        );
783
    }
784
785
    #[test]
786
    pub fn test_timeval_ord() {
787
        assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000));
788
        assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
789
        assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
790
        assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
791
        assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
792
    }
793
794
    #[test]
795
    pub fn test_timeval_neg() {
796
        let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
797
        let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
798
799
        assert_eq!(a, -b);
800
    }
801
802
    #[test]
803
    pub fn test_timeval_fmt() {
804
        assert_eq!(TimeVal::zero().to_string(), "0 seconds");
805
        assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
806
        assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
807
        assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
808
        assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
809
        assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
810
    }
811
}