1 use std
::{cmp, fmt, ops}
;
2 use libc
::{c_long, time_t, suseconds_t, timespec, timeval}
;
4 pub trait TimeValLike
: Sized
{
11 fn hours(hours
: i64) -> Self {
12 let secs
= hours
.checked_mul(SECS_PER_HOUR
)
13 .expect("TimeValLike::hours ouf of bounds");
18 fn minutes(minutes
: i64) -> Self {
19 let secs
= minutes
.checked_mul(SECS_PER_MINUTE
)
20 .expect("TimeValLike::minutes out of bounds");
24 fn seconds(seconds
: i64) -> Self;
25 fn milliseconds(milliseconds
: i64) -> Self;
26 fn microseconds(microseconds
: i64) -> Self;
27 fn nanoseconds(nanoseconds
: i64) -> Self;
30 fn num_hours(&self) -> i64 {
31 self.num_seconds() / 3600
35 fn num_minutes(&self) -> i64 {
36 self.num_seconds() / 60
39 fn num_seconds(&self) -> i64;
40 fn num_milliseconds(&self) -> i64;
41 fn num_microseconds(&self) -> i64;
42 fn num_nanoseconds(&self) -> i64;
46 #[derive(Clone, Copy)]
47 pub struct TimeSpec(timespec
);
49 const NANOS_PER_SEC
: i64 = 1_000_000_000;
50 const SECS_PER_MINUTE
: i64 = 60;
51 const SECS_PER_HOUR
: i64 = 3600;
53 #[cfg(target_pointer_width = "64")]
54 const TS_MAX_SECONDS
: i64 = (::std
::i64::MAX
/ NANOS_PER_SEC
) - 1;
56 #[cfg(target_pointer_width = "32")]
57 const TS_MAX_SECONDS
: i64 = ::std
::isize::MAX
as i64;
59 const TS_MIN_SECONDS
: i64 = -TS_MAX_SECONDS
;
62 impl AsRef
<timespec
> for TimeSpec
{
63 fn as_ref(&self) -> ×pec
{
68 impl fmt
::Debug
for TimeSpec
{
69 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
70 fmt
.debug_struct("TimeSpec")
71 .field("tv_sec", &self.tv_sec())
72 .field("tv_nsec", &self.tv_nsec())
77 impl cmp
::PartialEq
for TimeSpec
{
78 // The implementation of cmp is simplified by assuming that the struct is
79 // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
80 fn eq(&self, other
: &TimeSpec
) -> bool
{
81 self.tv_sec() == other
.tv_sec() && self.tv_nsec() == other
.tv_nsec()
85 impl cmp
::Eq
for TimeSpec {}
87 impl cmp
::Ord
for TimeSpec
{
88 // The implementation of cmp is simplified by assuming that the struct is
89 // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
90 fn cmp(&self, other
: &TimeSpec
) -> cmp
::Ordering
{
91 if self.tv_sec() == other
.tv_sec() {
92 self.tv_nsec().cmp(&other
.tv_nsec())
94 self.tv_sec().cmp(&other
.tv_sec())
99 impl cmp
::PartialOrd
for TimeSpec
{
100 fn partial_cmp(&self, other
: &TimeSpec
) -> Option
<cmp
::Ordering
> {
101 Some(self.cmp(other
))
105 impl TimeValLike
for TimeSpec
{
107 fn seconds(seconds
: i64) -> TimeSpec
{
108 assert
!(seconds
>= TS_MIN_SECONDS
&& seconds
<= TS_MAX_SECONDS
,
109 "TimeSpec out of bounds; seconds={}", seconds
);
110 TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 }
)
114 fn milliseconds(milliseconds
: i64) -> TimeSpec
{
115 let nanoseconds
= milliseconds
.checked_mul(1_000_000)
116 .expect("TimeSpec::milliseconds out of bounds");
118 TimeSpec
::nanoseconds(nanoseconds
)
121 /// Makes a new `TimeSpec` with given number of microseconds.
123 fn microseconds(microseconds
: i64) -> TimeSpec
{
124 let nanoseconds
= microseconds
.checked_mul(1_000)
125 .expect("TimeSpec::milliseconds out of bounds");
127 TimeSpec
::nanoseconds(nanoseconds
)
130 /// Makes a new `TimeSpec` with given number of nanoseconds.
132 fn nanoseconds(nanoseconds
: i64) -> TimeSpec
{
133 let (secs
, nanos
) = div_mod_floor_64(nanoseconds
, NANOS_PER_SEC
);
134 assert
!(secs
>= TS_MIN_SECONDS
&& secs
<= TS_MAX_SECONDS
,
135 "TimeSpec out of bounds");
136 TimeSpec(timespec
{tv_sec
: secs
as time_t
,
137 tv_nsec
: nanos
as c_long
})
140 fn num_seconds(&self) -> i64 {
141 if self.tv_sec() < 0 && self.tv_nsec() > 0 {
142 (self.tv_sec() + 1) as i64
148 fn num_milliseconds(&self) -> i64 {
149 self.num_nanoseconds() / 1_000_000
152 fn num_microseconds(&self) -> i64 {
153 self.num_nanoseconds() / 1_000_000_000
156 fn num_nanoseconds(&self) -> i64 {
157 let secs
= self.num_seconds() * 1_000_000_000;
158 let nsec
= self.nanos_mod_sec();
164 fn nanos_mod_sec(&self) -> c_long
{
165 if self.tv_sec() < 0 && self.tv_nsec() > 0 {
166 self.tv_nsec() - NANOS_PER_SEC
as c_long
172 pub fn tv_sec(&self) -> time_t
{
176 pub fn tv_nsec(&self) -> c_long
{
181 impl ops
::Neg
for TimeSpec
{
182 type Output
= TimeSpec
;
184 fn neg(self) -> TimeSpec
{
185 TimeSpec
::nanoseconds(-self.num_nanoseconds())
189 impl ops
::Add
for TimeSpec
{
190 type Output
= TimeSpec
;
192 fn add(self, rhs
: TimeSpec
) -> TimeSpec
{
193 TimeSpec
::nanoseconds(
194 self.num_nanoseconds() + rhs
.num_nanoseconds())
198 impl ops
::Sub
for TimeSpec
{
199 type Output
= TimeSpec
;
201 fn sub(self, rhs
: TimeSpec
) -> TimeSpec
{
202 TimeSpec
::nanoseconds(
203 self.num_nanoseconds() - rhs
.num_nanoseconds())
207 impl ops
::Mul
<i32> for TimeSpec
{
208 type Output
= TimeSpec
;
210 fn mul(self, rhs
: i32) -> TimeSpec
{
211 let usec
= self.num_nanoseconds().checked_mul(rhs
as i64)
212 .expect("TimeSpec multiply out of bounds");
214 TimeSpec
::nanoseconds(usec
)
218 impl ops
::Div
<i32> for TimeSpec
{
219 type Output
= TimeSpec
;
221 fn div(self, rhs
: i32) -> TimeSpec
{
222 let usec
= self.num_nanoseconds() / rhs
as i64;
223 TimeSpec
::nanoseconds(usec
)
227 impl fmt
::Display
for TimeSpec
{
228 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
229 let (abs
, sign
) = if self.tv_sec() < 0 {
235 let sec
= abs
.tv_sec();
237 try
!(write
!(f
, "{}", sign
));
239 if abs
.tv_nsec() == 0 {
240 if abs
.tv_sec() == 1 {
241 try
!(write
!(f
, "{} second", sec
));
243 try
!(write
!(f
, "{} seconds", sec
));
245 } else if abs
.tv_nsec() % 1_000_000 == 0 {
246 try
!(write
!(f
, "{}.{:03} seconds", sec
, abs
.tv_nsec() / 1_000_000));
247 } else if abs
.tv_nsec() % 1_000 == 0 {
248 try
!(write
!(f
, "{}.{:06} seconds", sec
, abs
.tv_nsec() / 1_000));
250 try
!(write
!(f
, "{}.{:09} seconds", sec
, abs
.tv_nsec()));
260 #[derive(Clone, Copy)]
261 pub struct TimeVal(timeval
);
263 const MICROS_PER_SEC
: i64 = 1_000_000;
265 #[cfg(target_pointer_width = "64")]
266 const TV_MAX_SECONDS
: i64 = (::std
::i64::MAX
/ MICROS_PER_SEC
) - 1;
268 #[cfg(target_pointer_width = "32")]
269 const TV_MAX_SECONDS
: i64 = ::std
::isize::MAX
as i64;
271 const TV_MIN_SECONDS
: i64 = -TV_MAX_SECONDS
;
273 impl AsRef
<timeval
> for TimeVal
{
274 fn as_ref(&self) -> &timeval
{
279 impl fmt
::Debug
for TimeVal
{
280 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
281 fmt
.debug_struct("TimeVal")
282 .field("tv_sec", &self.tv_sec())
283 .field("tv_usec", &self.tv_usec())
288 impl cmp
::PartialEq
for TimeVal
{
289 // The implementation of cmp is simplified by assuming that the struct is
290 // normalized. That is, tv_usec must always be within [0, 1_000_000)
291 fn eq(&self, other
: &TimeVal
) -> bool
{
292 self.tv_sec() == other
.tv_sec() && self.tv_usec() == other
.tv_usec()
296 impl cmp
::Eq
for TimeVal {}
298 impl cmp
::Ord
for TimeVal
{
299 // The implementation of cmp is simplified by assuming that the struct is
300 // normalized. That is, tv_usec must always be within [0, 1_000_000)
301 fn cmp(&self, other
: &TimeVal
) -> cmp
::Ordering
{
302 if self.tv_sec() == other
.tv_sec() {
303 self.tv_usec().cmp(&other
.tv_usec())
305 self.tv_sec().cmp(&other
.tv_sec())
310 impl cmp
::PartialOrd
for TimeVal
{
311 fn partial_cmp(&self, other
: &TimeVal
) -> Option
<cmp
::Ordering
> {
312 Some(self.cmp(other
))
316 impl TimeValLike
for TimeVal
{
318 fn seconds(seconds
: i64) -> TimeVal
{
319 assert
!(seconds
>= TV_MIN_SECONDS
&& seconds
<= TV_MAX_SECONDS
,
320 "TimeVal out of bounds; seconds={}", seconds
);
321 TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 }
)
325 fn milliseconds(milliseconds
: i64) -> TimeVal
{
326 let microseconds
= milliseconds
.checked_mul(1_000)
327 .expect("TimeVal::milliseconds out of bounds");
329 TimeVal
::microseconds(microseconds
)
332 /// Makes a new `TimeVal` with given number of microseconds.
334 fn microseconds(microseconds
: i64) -> TimeVal
{
335 let (secs
, micros
) = div_mod_floor_64(microseconds
, MICROS_PER_SEC
);
336 assert
!(secs
>= TV_MIN_SECONDS
&& secs
<= TV_MAX_SECONDS
,
337 "TimeVal out of bounds");
338 TimeVal(timeval
{tv_sec
: secs
as time_t
,
339 tv_usec
: micros
as suseconds_t
})
342 /// Makes a new `TimeVal` with given number of nanoseconds. Some precision
345 fn nanoseconds(nanoseconds
: i64) -> TimeVal
{
346 let microseconds
= nanoseconds
/ 1000;
347 let (secs
, micros
) = div_mod_floor_64(microseconds
, MICROS_PER_SEC
);
348 assert
!(secs
>= TV_MIN_SECONDS
&& secs
<= TV_MAX_SECONDS
,
349 "TimeVal out of bounds");
350 TimeVal(timeval
{tv_sec
: secs
as time_t
,
351 tv_usec
: micros
as suseconds_t
})
354 fn num_seconds(&self) -> i64 {
355 if self.tv_sec() < 0 && self.tv_usec() > 0 {
356 (self.tv_sec() + 1) as i64
362 fn num_milliseconds(&self) -> i64 {
363 self.num_microseconds() / 1_000
366 fn num_microseconds(&self) -> i64 {
367 let secs
= self.num_seconds() * 1_000_000;
368 let usec
= self.micros_mod_sec();
372 fn num_nanoseconds(&self) -> i64 {
373 self.num_microseconds() * 1_000
378 fn micros_mod_sec(&self) -> suseconds_t
{
379 if self.tv_sec() < 0 && self.tv_usec() > 0 {
380 self.tv_usec() - MICROS_PER_SEC
as suseconds_t
386 pub fn tv_sec(&self) -> time_t
{
390 pub fn tv_usec(&self) -> suseconds_t
{
395 impl ops
::Neg
for TimeVal
{
396 type Output
= TimeVal
;
398 fn neg(self) -> TimeVal
{
399 TimeVal
::microseconds(-self.num_microseconds())
403 impl ops
::Add
for TimeVal
{
404 type Output
= TimeVal
;
406 fn add(self, rhs
: TimeVal
) -> TimeVal
{
407 TimeVal
::microseconds(
408 self.num_microseconds() + rhs
.num_microseconds())
412 impl ops
::Sub
for TimeVal
{
413 type Output
= TimeVal
;
415 fn sub(self, rhs
: TimeVal
) -> TimeVal
{
416 TimeVal
::microseconds(
417 self.num_microseconds() - rhs
.num_microseconds())
421 impl ops
::Mul
<i32> for TimeVal
{
422 type Output
= TimeVal
;
424 fn mul(self, rhs
: i32) -> TimeVal
{
425 let usec
= self.num_microseconds().checked_mul(rhs
as i64)
426 .expect("TimeVal multiply out of bounds");
428 TimeVal
::microseconds(usec
)
432 impl ops
::Div
<i32> for TimeVal
{
433 type Output
= TimeVal
;
435 fn div(self, rhs
: i32) -> TimeVal
{
436 let usec
= self.num_microseconds() / rhs
as i64;
437 TimeVal
::microseconds(usec
)
441 impl fmt
::Display
for TimeVal
{
442 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
443 let (abs
, sign
) = if self.tv_sec() < 0 {
449 let sec
= abs
.tv_sec();
451 try
!(write
!(f
, "{}", sign
));
453 if abs
.tv_usec() == 0 {
454 if abs
.tv_sec() == 1 {
455 try
!(write
!(f
, "{} second", sec
));
457 try
!(write
!(f
, "{} seconds", sec
));
459 } else if abs
.tv_usec() % 1000 == 0 {
460 try
!(write
!(f
, "{}.{:03} seconds", sec
, abs
.tv_usec() / 1000));
462 try
!(write
!(f
, "{}.{:06} seconds", sec
, abs
.tv_usec()));
470 fn div_mod_floor_64(this
: i64, other
: i64) -> (i64, i64) {
471 (div_floor_64(this
, other
), mod_floor_64(this
, other
))
475 fn div_floor_64(this
: i64, other
: i64) -> i64 {
476 match div_rem_64(this
, other
) {
477 (d
, r
) if (r
> 0 && other
< 0)
478 || (r
< 0 && other
> 0) => d
- 1,
484 fn mod_floor_64(this
: i64, other
: i64) -> i64 {
486 r
if (r
> 0 && other
< 0)
487 || (r
< 0 && other
> 0) => r
+ other
,
493 fn div_rem_64(this
: i64, other
: i64) -> (i64, i64) {
494 (this
/ other
, this
% other
)
499 use super::{TimeSpec, TimeVal, TimeValLike}
;
502 pub fn test_timespec() {
503 assert
!(TimeSpec
::seconds(1) != TimeSpec
::zero());
504 assert_eq
!(TimeSpec
::seconds(1) + TimeSpec
::seconds(2),
505 TimeSpec
::seconds(3));
506 assert_eq
!(TimeSpec
::minutes(3) + TimeSpec
::seconds(2),
507 TimeSpec
::seconds(182));
511 pub fn test_timespec_neg() {
512 let a
= TimeSpec
::seconds(1) + TimeSpec
::nanoseconds(123);
513 let b
= TimeSpec
::seconds(-1) + TimeSpec
::nanoseconds(-123);
519 pub fn test_timespec_ord() {
520 assert
!(TimeSpec
::seconds(1) == TimeSpec
::nanoseconds(1_000_000_000));
521 assert
!(TimeSpec
::seconds(1) < TimeSpec
::nanoseconds(1_000_000_001));
522 assert
!(TimeSpec
::seconds(1) > TimeSpec
::nanoseconds(999_999_999));
523 assert
!(TimeSpec
::seconds(-1) < TimeSpec
::nanoseconds(-999_999_999));
524 assert
!(TimeSpec
::seconds(-1) > TimeSpec
::nanoseconds(-1_000_000_001));
528 pub fn test_timespec_fmt() {
529 assert_eq
!(TimeSpec
::zero().to_string(), "0 seconds");
530 assert_eq
!(TimeSpec
::seconds(42).to_string(), "42 seconds");
531 assert_eq
!(TimeSpec
::milliseconds(42).to_string(), "0.042 seconds");
532 assert_eq
!(TimeSpec
::microseconds(42).to_string(), "0.000042 seconds");
533 assert_eq
!(TimeSpec
::nanoseconds(42).to_string(), "0.000000042 seconds");
534 assert_eq
!(TimeSpec
::seconds(-86401).to_string(), "-86401 seconds");
538 pub fn test_timeval() {
539 assert
!(TimeVal
::seconds(1) != TimeVal
::zero());
540 assert_eq
!(TimeVal
::seconds(1) + TimeVal
::seconds(2),
541 TimeVal
::seconds(3));
542 assert_eq
!(TimeVal
::minutes(3) + TimeVal
::seconds(2),
543 TimeVal
::seconds(182));
547 pub fn test_timeval_ord() {
548 assert
!(TimeVal
::seconds(1) == TimeVal
::microseconds(1_000_000));
549 assert
!(TimeVal
::seconds(1) < TimeVal
::microseconds(1_000_001));
550 assert
!(TimeVal
::seconds(1) > TimeVal
::microseconds(999_999));
551 assert
!(TimeVal
::seconds(-1) < TimeVal
::microseconds(-999_999));
552 assert
!(TimeVal
::seconds(-1) > TimeVal
::microseconds(-1_000_001));
556 pub fn test_timeval_neg() {
557 let a
= TimeVal
::seconds(1) + TimeVal
::microseconds(123);
558 let b
= TimeVal
::seconds(-1) + TimeVal
::microseconds(-123);
564 pub fn test_timeval_fmt() {
565 assert_eq
!(TimeVal
::zero().to_string(), "0 seconds");
566 assert_eq
!(TimeVal
::seconds(42).to_string(), "42 seconds");
567 assert_eq
!(TimeVal
::milliseconds(42).to_string(), "0.042 seconds");
568 assert_eq
!(TimeVal
::microseconds(42).to_string(), "0.000042 seconds");
569 assert_eq
!(TimeVal
::nanoseconds(1402).to_string(), "0.000001 seconds");
570 assert_eq
!(TimeVal
::seconds(-86401).to_string(), "-86401 seconds");