]> git.proxmox.com Git - rustc.git/blob - src/vendor/nix/src/sys/time.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / vendor / nix / src / sys / time.rs
1 use std::{cmp, fmt, ops};
2 use libc::{c_long, time_t, suseconds_t, timespec, timeval};
3
4 pub trait TimeValLike: Sized {
5 #[inline]
6 fn zero() -> Self {
7 Self::seconds(0)
8 }
9
10 #[inline]
11 fn hours(hours: i64) -> Self {
12 let secs = hours.checked_mul(SECS_PER_HOUR)
13 .expect("TimeValLike::hours ouf of bounds");
14 Self::seconds(secs)
15 }
16
17 #[inline]
18 fn minutes(minutes: i64) -> Self {
19 let secs = minutes.checked_mul(SECS_PER_MINUTE)
20 .expect("TimeValLike::minutes out of bounds");
21 Self::seconds(secs)
22 }
23
24 fn seconds(seconds: i64) -> Self;
25 fn milliseconds(milliseconds: i64) -> Self;
26 fn microseconds(microseconds: i64) -> Self;
27 fn nanoseconds(nanoseconds: i64) -> Self;
28
29 #[inline]
30 fn num_hours(&self) -> i64 {
31 self.num_seconds() / 3600
32 }
33
34 #[inline]
35 fn num_minutes(&self) -> i64 {
36 self.num_seconds() / 60
37 }
38
39 fn num_seconds(&self) -> i64;
40 fn num_milliseconds(&self) -> i64;
41 fn num_microseconds(&self) -> i64;
42 fn num_nanoseconds(&self) -> i64;
43 }
44
45 #[repr(C)]
46 #[derive(Clone, Copy)]
47 pub struct TimeSpec(timespec);
48
49 const NANOS_PER_SEC: i64 = 1_000_000_000;
50 const SECS_PER_MINUTE: i64 = 60;
51 const SECS_PER_HOUR: i64 = 3600;
52
53 #[cfg(target_pointer_width = "64")]
54 const TS_MAX_SECONDS: i64 = (::std::i64::MAX / NANOS_PER_SEC) - 1;
55
56 #[cfg(target_pointer_width = "32")]
57 const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
58
59 const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
60
61
62 impl AsRef<timespec> for TimeSpec {
63 fn as_ref(&self) -> &timespec {
64 &self.0
65 }
66 }
67
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())
73 .finish()
74 }
75 }
76
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()
82 }
83 }
84
85 impl cmp::Eq for TimeSpec {}
86
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())
93 } else {
94 self.tv_sec().cmp(&other.tv_sec())
95 }
96 }
97 }
98
99 impl cmp::PartialOrd for TimeSpec {
100 fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
101 Some(self.cmp(other))
102 }
103 }
104
105 impl TimeValLike for TimeSpec {
106 #[inline]
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 })
111 }
112
113 #[inline]
114 fn milliseconds(milliseconds: i64) -> TimeSpec {
115 let nanoseconds = milliseconds.checked_mul(1_000_000)
116 .expect("TimeSpec::milliseconds out of bounds");
117
118 TimeSpec::nanoseconds(nanoseconds)
119 }
120
121 /// Makes a new `TimeSpec` with given number of microseconds.
122 #[inline]
123 fn microseconds(microseconds: i64) -> TimeSpec {
124 let nanoseconds = microseconds.checked_mul(1_000)
125 .expect("TimeSpec::milliseconds out of bounds");
126
127 TimeSpec::nanoseconds(nanoseconds)
128 }
129
130 /// Makes a new `TimeSpec` with given number of nanoseconds.
131 #[inline]
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 })
138 }
139
140 fn num_seconds(&self) -> i64 {
141 if self.tv_sec() < 0 && self.tv_nsec() > 0 {
142 (self.tv_sec() + 1) as i64
143 } else {
144 self.tv_sec() as i64
145 }
146 }
147
148 fn num_milliseconds(&self) -> i64 {
149 self.num_nanoseconds() / 1_000_000
150 }
151
152 fn num_microseconds(&self) -> i64 {
153 self.num_nanoseconds() / 1_000_000_000
154 }
155
156 fn num_nanoseconds(&self) -> i64 {
157 let secs = self.num_seconds() * 1_000_000_000;
158 let nsec = self.nanos_mod_sec();
159 secs + nsec as i64
160 }
161 }
162
163 impl TimeSpec {
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
167 } else {
168 self.tv_nsec()
169 }
170 }
171
172 pub fn tv_sec(&self) -> time_t {
173 self.0.tv_sec
174 }
175
176 pub fn tv_nsec(&self) -> c_long {
177 self.0.tv_nsec
178 }
179 }
180
181 impl ops::Neg for TimeSpec {
182 type Output = TimeSpec;
183
184 fn neg(self) -> TimeSpec {
185 TimeSpec::nanoseconds(-self.num_nanoseconds())
186 }
187 }
188
189 impl ops::Add for TimeSpec {
190 type Output = TimeSpec;
191
192 fn add(self, rhs: TimeSpec) -> TimeSpec {
193 TimeSpec::nanoseconds(
194 self.num_nanoseconds() + rhs.num_nanoseconds())
195 }
196 }
197
198 impl ops::Sub for TimeSpec {
199 type Output = TimeSpec;
200
201 fn sub(self, rhs: TimeSpec) -> TimeSpec {
202 TimeSpec::nanoseconds(
203 self.num_nanoseconds() - rhs.num_nanoseconds())
204 }
205 }
206
207 impl ops::Mul<i32> for TimeSpec {
208 type Output = TimeSpec;
209
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");
213
214 TimeSpec::nanoseconds(usec)
215 }
216 }
217
218 impl ops::Div<i32> for TimeSpec {
219 type Output = TimeSpec;
220
221 fn div(self, rhs: i32) -> TimeSpec {
222 let usec = self.num_nanoseconds() / rhs as i64;
223 TimeSpec::nanoseconds(usec)
224 }
225 }
226
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 {
230 (-*self, "-")
231 } else {
232 (*self, "")
233 };
234
235 let sec = abs.tv_sec();
236
237 try!(write!(f, "{}", sign));
238
239 if abs.tv_nsec() == 0 {
240 if abs.tv_sec() == 1 {
241 try!(write!(f, "{} second", sec));
242 } else {
243 try!(write!(f, "{} seconds", sec));
244 }
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));
249 } else {
250 try!(write!(f, "{}.{:09} seconds", sec, abs.tv_nsec()));
251 }
252
253 Ok(())
254 }
255 }
256
257
258
259 #[repr(C)]
260 #[derive(Clone, Copy)]
261 pub struct TimeVal(timeval);
262
263 const MICROS_PER_SEC: i64 = 1_000_000;
264
265 #[cfg(target_pointer_width = "64")]
266 const TV_MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;
267
268 #[cfg(target_pointer_width = "32")]
269 const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
270
271 const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
272
273 impl AsRef<timeval> for TimeVal {
274 fn as_ref(&self) -> &timeval {
275 &self.0
276 }
277 }
278
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())
284 .finish()
285 }
286 }
287
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()
293 }
294 }
295
296 impl cmp::Eq for TimeVal {}
297
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())
304 } else {
305 self.tv_sec().cmp(&other.tv_sec())
306 }
307 }
308 }
309
310 impl cmp::PartialOrd for TimeVal {
311 fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
312 Some(self.cmp(other))
313 }
314 }
315
316 impl TimeValLike for TimeVal {
317 #[inline]
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 })
322 }
323
324 #[inline]
325 fn milliseconds(milliseconds: i64) -> TimeVal {
326 let microseconds = milliseconds.checked_mul(1_000)
327 .expect("TimeVal::milliseconds out of bounds");
328
329 TimeVal::microseconds(microseconds)
330 }
331
332 /// Makes a new `TimeVal` with given number of microseconds.
333 #[inline]
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 })
340 }
341
342 /// Makes a new `TimeVal` with given number of nanoseconds. Some precision
343 /// will be lost
344 #[inline]
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 })
352 }
353
354 fn num_seconds(&self) -> i64 {
355 if self.tv_sec() < 0 && self.tv_usec() > 0 {
356 (self.tv_sec() + 1) as i64
357 } else {
358 self.tv_sec() as i64
359 }
360 }
361
362 fn num_milliseconds(&self) -> i64 {
363 self.num_microseconds() / 1_000
364 }
365
366 fn num_microseconds(&self) -> i64 {
367 let secs = self.num_seconds() * 1_000_000;
368 let usec = self.micros_mod_sec();
369 secs + usec as i64
370 }
371
372 fn num_nanoseconds(&self) -> i64 {
373 self.num_microseconds() * 1_000
374 }
375 }
376
377 impl TimeVal {
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
381 } else {
382 self.tv_usec()
383 }
384 }
385
386 pub fn tv_sec(&self) -> time_t {
387 self.0.tv_sec
388 }
389
390 pub fn tv_usec(&self) -> suseconds_t {
391 self.0.tv_usec
392 }
393 }
394
395 impl ops::Neg for TimeVal {
396 type Output = TimeVal;
397
398 fn neg(self) -> TimeVal {
399 TimeVal::microseconds(-self.num_microseconds())
400 }
401 }
402
403 impl ops::Add for TimeVal {
404 type Output = TimeVal;
405
406 fn add(self, rhs: TimeVal) -> TimeVal {
407 TimeVal::microseconds(
408 self.num_microseconds() + rhs.num_microseconds())
409 }
410 }
411
412 impl ops::Sub for TimeVal {
413 type Output = TimeVal;
414
415 fn sub(self, rhs: TimeVal) -> TimeVal {
416 TimeVal::microseconds(
417 self.num_microseconds() - rhs.num_microseconds())
418 }
419 }
420
421 impl ops::Mul<i32> for TimeVal {
422 type Output = TimeVal;
423
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");
427
428 TimeVal::microseconds(usec)
429 }
430 }
431
432 impl ops::Div<i32> for TimeVal {
433 type Output = TimeVal;
434
435 fn div(self, rhs: i32) -> TimeVal {
436 let usec = self.num_microseconds() / rhs as i64;
437 TimeVal::microseconds(usec)
438 }
439 }
440
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 {
444 (-*self, "-")
445 } else {
446 (*self, "")
447 };
448
449 let sec = abs.tv_sec();
450
451 try!(write!(f, "{}", sign));
452
453 if abs.tv_usec() == 0 {
454 if abs.tv_sec() == 1 {
455 try!(write!(f, "{} second", sec));
456 } else {
457 try!(write!(f, "{} seconds", sec));
458 }
459 } else if abs.tv_usec() % 1000 == 0 {
460 try!(write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000));
461 } else {
462 try!(write!(f, "{}.{:06} seconds", sec, abs.tv_usec()));
463 }
464
465 Ok(())
466 }
467 }
468
469 #[inline]
470 fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
471 (div_floor_64(this, other), mod_floor_64(this, other))
472 }
473
474 #[inline]
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,
479 (d, _) => d,
480 }
481 }
482
483 #[inline]
484 fn mod_floor_64(this: i64, other: i64) -> i64 {
485 match this % other {
486 r if (r > 0 && other < 0)
487 || (r < 0 && other > 0) => r + other,
488 r => r,
489 }
490 }
491
492 #[inline]
493 fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
494 (this / other, this % other)
495 }
496
497 #[cfg(test)]
498 mod test {
499 use super::{TimeSpec, TimeVal, TimeValLike};
500
501 #[test]
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));
508 }
509
510 #[test]
511 pub fn test_timespec_neg() {
512 let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
513 let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
514
515 assert_eq!(a, -b);
516 }
517
518 #[test]
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));
525 }
526
527 #[test]
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");
535 }
536
537 #[test]
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));
544 }
545
546 #[test]
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));
553 }
554
555 #[test]
556 pub fn test_timeval_neg() {
557 let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
558 let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
559
560 assert_eq!(a, -b);
561 }
562
563 #[test]
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");
571 }
572 }