/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) -> ×pec { |
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 | | } |