/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nix-0.30.1/src/sys/time.rs
Line | Count | Source |
1 | | #[cfg_attr( |
2 | | any(target_env = "musl", target_env = "ohos"), |
3 | | allow(deprecated) |
4 | | )] |
5 | | // https://github.com/rust-lang/libc/issues/1848 |
6 | | pub use libc::{suseconds_t, time_t}; |
7 | | use libc::{timespec, timeval}; |
8 | | use std::time::Duration; |
9 | | use std::{cmp, fmt, ops}; |
10 | | |
11 | 0 | const fn zero_init_timespec() -> timespec { |
12 | | // `std::mem::MaybeUninit::zeroed()` is not yet a const fn |
13 | | // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of |
14 | | // the appropriate size to zero and then transmute it to a timespec value. |
15 | 0 | unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) } |
16 | 0 | } |
17 | | |
18 | | #[cfg(any( |
19 | | all(feature = "time", any(target_os = "android", target_os = "linux")), |
20 | | all( |
21 | | any( |
22 | | target_os = "freebsd", |
23 | | solarish, |
24 | | target_os = "linux", |
25 | | target_os = "netbsd" |
26 | | ), |
27 | | feature = "time", |
28 | | feature = "signal" |
29 | | ) |
30 | | ))] |
31 | | pub(crate) mod timer { |
32 | | use crate::sys::time::{zero_init_timespec, TimeSpec}; |
33 | | use bitflags::bitflags; |
34 | | |
35 | | #[derive(Debug, Clone, Copy)] |
36 | | pub(crate) struct TimerSpec(libc::itimerspec); |
37 | | |
38 | | impl TimerSpec { |
39 | | pub const fn none() -> Self { |
40 | | Self(libc::itimerspec { |
41 | | it_interval: zero_init_timespec(), |
42 | | it_value: zero_init_timespec(), |
43 | | }) |
44 | | } |
45 | | } |
46 | | |
47 | | impl AsMut<libc::itimerspec> for TimerSpec { |
48 | | fn as_mut(&mut self) -> &mut libc::itimerspec { |
49 | | &mut self.0 |
50 | | } |
51 | | } |
52 | | |
53 | | impl AsRef<libc::itimerspec> for TimerSpec { |
54 | | fn as_ref(&self) -> &libc::itimerspec { |
55 | | &self.0 |
56 | | } |
57 | | } |
58 | | |
59 | | impl From<Expiration> for TimerSpec { |
60 | | fn from(expiration: Expiration) -> TimerSpec { |
61 | | match expiration { |
62 | | Expiration::OneShot(t) => TimerSpec(libc::itimerspec { |
63 | | it_interval: zero_init_timespec(), |
64 | | it_value: *t.as_ref(), |
65 | | }), |
66 | | Expiration::IntervalDelayed(start, interval) => { |
67 | | TimerSpec(libc::itimerspec { |
68 | | it_interval: *interval.as_ref(), |
69 | | it_value: *start.as_ref(), |
70 | | }) |
71 | | } |
72 | | Expiration::Interval(t) => TimerSpec(libc::itimerspec { |
73 | | it_interval: *t.as_ref(), |
74 | | it_value: *t.as_ref(), |
75 | | }), |
76 | | } |
77 | | } |
78 | | } |
79 | | |
80 | | /// An enumeration allowing the definition of the expiration time of an alarm, |
81 | | /// recurring or not. |
82 | | #[derive(Debug, Clone, Copy, Eq, PartialEq)] |
83 | | pub enum Expiration { |
84 | | /// Alarm will trigger once after the time given in `TimeSpec` |
85 | | OneShot(TimeSpec), |
86 | | /// Alarm will trigger after a specified delay and then every interval of |
87 | | /// time. |
88 | | IntervalDelayed(TimeSpec, TimeSpec), |
89 | | /// Alarm will trigger every specified interval of time. |
90 | | Interval(TimeSpec), |
91 | | } |
92 | | |
93 | | #[cfg(linux_android)] |
94 | | bitflags! { |
95 | | /// Flags that are used for arming the timer. |
96 | | #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] |
97 | | pub struct TimerSetTimeFlags: libc::c_int { |
98 | | const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; |
99 | | const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET; |
100 | | } |
101 | | } |
102 | | #[cfg(any(freebsdlike, target_os = "netbsd", solarish))] |
103 | | bitflags! { |
104 | | /// Flags that are used for arming the timer. |
105 | | #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] |
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( |
260 | | any(target_env = "musl", target_env = "ohos"), |
261 | | allow(deprecated) |
262 | | )] |
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( |
296 | | any(target_env = "musl", target_env = "ohos"), |
297 | | allow(deprecated) |
298 | | )] |
299 | | // https://github.com/rust-lang/libc/issues/1848 |
300 | 0 | fn nanoseconds(nanoseconds: i64) -> TimeSpec { |
301 | 0 | let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); |
302 | 0 | assert!( |
303 | 0 | (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), |
304 | 0 | "TimeSpec out of bounds" |
305 | | ); |
306 | 0 | let mut ts = zero_init_timespec(); |
307 | 0 | ts.tv_sec = secs as time_t; |
308 | 0 | ts.tv_nsec = nanos as timespec_tv_nsec_t; |
309 | 0 | TimeSpec(ts) |
310 | 0 | } |
311 | | |
312 | | // The cast is not unnecessary on all platforms. |
313 | | #[allow(clippy::unnecessary_cast)] |
314 | 0 | fn num_seconds(&self) -> i64 { |
315 | 0 | if self.tv_sec() < 0 && self.tv_nsec() > 0 { |
316 | 0 | (self.tv_sec() + 1) as i64 |
317 | | } else { |
318 | 0 | self.tv_sec() as i64 |
319 | | } |
320 | 0 | } |
321 | | |
322 | 0 | fn num_milliseconds(&self) -> i64 { |
323 | 0 | self.num_nanoseconds() / 1_000_000 |
324 | 0 | } |
325 | | |
326 | 0 | fn num_microseconds(&self) -> i64 { |
327 | 0 | self.num_nanoseconds() / 1_000 |
328 | 0 | } |
329 | | |
330 | | // The cast is not unnecessary on all platforms. |
331 | | #[allow(clippy::unnecessary_cast)] |
332 | 0 | fn num_nanoseconds(&self) -> i64 { |
333 | 0 | let secs = self.num_seconds() * 1_000_000_000; |
334 | 0 | let nsec = self.nanos_mod_sec(); |
335 | 0 | secs + nsec as i64 |
336 | 0 | } |
337 | | } |
338 | | |
339 | | impl TimeSpec { |
340 | | /// Leave the timestamp unchanged. |
341 | | #[cfg(not(target_os = "redox"))] |
342 | | // At the time of writing this PR, redox does not support this feature |
343 | | pub const UTIME_OMIT: TimeSpec = |
344 | | TimeSpec::new(0, libc::UTIME_OMIT as timespec_tv_nsec_t); |
345 | | /// Update the timestamp to `Now` |
346 | | // At the time of writing this PR, redox does not support this feature |
347 | | #[cfg(not(target_os = "redox"))] |
348 | | pub const UTIME_NOW: TimeSpec = |
349 | | TimeSpec::new(0, libc::UTIME_NOW as timespec_tv_nsec_t); |
350 | | |
351 | | /// Construct a new `TimeSpec` from its components |
352 | | #[cfg_attr( |
353 | | any(target_env = "musl", target_env = "ohos"), |
354 | | allow(deprecated) |
355 | | )] // https://github.com/rust-lang/libc/issues/1848 |
356 | 0 | pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { |
357 | 0 | let mut ts = zero_init_timespec(); |
358 | 0 | ts.tv_sec = seconds; |
359 | 0 | ts.tv_nsec = nanoseconds; |
360 | 0 | Self(ts) |
361 | 0 | } |
362 | | |
363 | 0 | fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { |
364 | 0 | if self.tv_sec() < 0 && self.tv_nsec() > 0 { |
365 | 0 | self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t |
366 | | } else { |
367 | 0 | self.tv_nsec() |
368 | | } |
369 | 0 | } |
370 | | |
371 | | #[cfg_attr( |
372 | | any(target_env = "musl", target_env = "ohos"), |
373 | | allow(deprecated) |
374 | | )] // https://github.com/rust-lang/libc/issues/1848 |
375 | 0 | pub const fn tv_sec(&self) -> time_t { |
376 | 0 | self.0.tv_sec |
377 | 0 | } |
378 | | |
379 | 0 | pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { |
380 | 0 | self.0.tv_nsec |
381 | 0 | } |
382 | | |
383 | | #[cfg_attr( |
384 | | any(target_env = "musl", target_env = "ohos"), |
385 | | allow(deprecated) |
386 | | )] |
387 | | // https://github.com/rust-lang/libc/issues/1848 |
388 | 0 | pub const fn from_duration(duration: Duration) -> Self { |
389 | 0 | let mut ts = zero_init_timespec(); |
390 | 0 | ts.tv_sec = duration.as_secs() as time_t; |
391 | 0 | ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; |
392 | 0 | TimeSpec(ts) |
393 | 0 | } |
394 | | |
395 | 0 | pub const fn from_timespec(timespec: timespec) -> Self { |
396 | 0 | Self(timespec) |
397 | 0 | } |
398 | | } |
399 | | |
400 | | impl ops::Neg for TimeSpec { |
401 | | type Output = TimeSpec; |
402 | | |
403 | 0 | fn neg(self) -> TimeSpec { |
404 | 0 | TimeSpec::nanoseconds(-self.num_nanoseconds()) |
405 | 0 | } |
406 | | } |
407 | | |
408 | | impl ops::Add for TimeSpec { |
409 | | type Output = TimeSpec; |
410 | | |
411 | 0 | fn add(self, rhs: TimeSpec) -> TimeSpec { |
412 | 0 | TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds()) |
413 | 0 | } |
414 | | } |
415 | | |
416 | | impl ops::Sub for TimeSpec { |
417 | | type Output = TimeSpec; |
418 | | |
419 | 0 | fn sub(self, rhs: TimeSpec) -> TimeSpec { |
420 | 0 | TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds()) |
421 | 0 | } |
422 | | } |
423 | | |
424 | | impl ops::Mul<i32> for TimeSpec { |
425 | | type Output = TimeSpec; |
426 | | |
427 | 0 | fn mul(self, rhs: i32) -> TimeSpec { |
428 | 0 | let usec = self |
429 | 0 | .num_nanoseconds() |
430 | 0 | .checked_mul(i64::from(rhs)) |
431 | 0 | .expect("TimeSpec multiply out of bounds"); |
432 | | |
433 | 0 | TimeSpec::nanoseconds(usec) |
434 | 0 | } |
435 | | } |
436 | | |
437 | | impl ops::Div<i32> for TimeSpec { |
438 | | type Output = TimeSpec; |
439 | | |
440 | 0 | fn div(self, rhs: i32) -> TimeSpec { |
441 | 0 | let usec = self.num_nanoseconds() / i64::from(rhs); |
442 | 0 | TimeSpec::nanoseconds(usec) |
443 | 0 | } |
444 | | } |
445 | | |
446 | | impl fmt::Display for TimeSpec { |
447 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
448 | 0 | let (abs, sign) = if self.tv_sec() < 0 { |
449 | 0 | (-*self, "-") |
450 | | } else { |
451 | 0 | (*self, "") |
452 | | }; |
453 | | |
454 | 0 | let sec = abs.tv_sec(); |
455 | | |
456 | 0 | write!(f, "{sign}")?; |
457 | | |
458 | 0 | if abs.tv_nsec() == 0 { |
459 | 0 | if sec == 1 { |
460 | 0 | write!(f, "1 second")?; |
461 | | } else { |
462 | 0 | write!(f, "{sec} seconds")?; |
463 | | } |
464 | 0 | } else if abs.tv_nsec() % 1_000_000 == 0 { |
465 | 0 | write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?; |
466 | 0 | } else if abs.tv_nsec() % 1_000 == 0 { |
467 | 0 | write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?; |
468 | | } else { |
469 | 0 | write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?; |
470 | | } |
471 | | |
472 | 0 | Ok(()) |
473 | 0 | } |
474 | | } |
475 | | |
476 | | #[repr(transparent)] |
477 | | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
478 | | pub struct TimeVal(timeval); |
479 | | |
480 | | const MICROS_PER_SEC: i64 = 1_000_000; |
481 | | |
482 | | #[cfg(target_pointer_width = "64")] |
483 | | const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; |
484 | | |
485 | | #[cfg(target_pointer_width = "32")] |
486 | | const TV_MAX_SECONDS: i64 = isize::MAX as i64; |
487 | | |
488 | | const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; |
489 | | |
490 | | impl AsRef<timeval> for TimeVal { |
491 | 0 | fn as_ref(&self) -> &timeval { |
492 | 0 | &self.0 |
493 | 0 | } |
494 | | } |
495 | | |
496 | | impl AsMut<timeval> for TimeVal { |
497 | 0 | fn as_mut(&mut self) -> &mut timeval { |
498 | 0 | &mut self.0 |
499 | 0 | } |
500 | | } |
501 | | |
502 | | impl Ord for TimeVal { |
503 | | // The implementation of cmp is simplified by assuming that the struct is |
504 | | // normalized. That is, tv_usec must always be within [0, 1_000_000) |
505 | 0 | fn cmp(&self, other: &TimeVal) -> cmp::Ordering { |
506 | 0 | if self.tv_sec() == other.tv_sec() { |
507 | 0 | self.tv_usec().cmp(&other.tv_usec()) |
508 | | } else { |
509 | 0 | self.tv_sec().cmp(&other.tv_sec()) |
510 | | } |
511 | 0 | } |
512 | | } |
513 | | |
514 | | impl PartialOrd for TimeVal { |
515 | 0 | fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> { |
516 | 0 | Some(self.cmp(other)) |
517 | 0 | } |
518 | | } |
519 | | |
520 | | impl TimeValLike for TimeVal { |
521 | | #[inline] |
522 | 0 | fn seconds(seconds: i64) -> TimeVal { |
523 | 0 | assert!( |
524 | 0 | (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), |
525 | 0 | "TimeVal out of bounds; seconds={seconds}" |
526 | | ); |
527 | | #[cfg_attr( |
528 | | any(target_env = "musl", target_env = "ohos"), |
529 | | allow(deprecated) |
530 | | )] |
531 | | // https://github.com/rust-lang/libc/issues/1848 |
532 | 0 | TimeVal(timeval { |
533 | 0 | tv_sec: seconds as time_t, |
534 | 0 | tv_usec: 0, |
535 | 0 | }) |
536 | 0 | } |
537 | | |
538 | | #[inline] |
539 | 0 | fn milliseconds(milliseconds: i64) -> TimeVal { |
540 | 0 | let microseconds = milliseconds |
541 | 0 | .checked_mul(1_000) |
542 | 0 | .expect("TimeVal::milliseconds out of bounds"); |
543 | | |
544 | 0 | TimeVal::microseconds(microseconds) |
545 | 0 | } |
546 | | |
547 | | /// Makes a new `TimeVal` with given number of microseconds. |
548 | | #[inline] |
549 | 0 | fn microseconds(microseconds: i64) -> TimeVal { |
550 | 0 | let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); |
551 | 0 | assert!( |
552 | 0 | (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), |
553 | 0 | "TimeVal out of bounds" |
554 | | ); |
555 | | #[cfg_attr( |
556 | | any(target_env = "musl", target_env = "ohos"), |
557 | | allow(deprecated) |
558 | | )] |
559 | | // https://github.com/rust-lang/libc/issues/1848 |
560 | 0 | TimeVal(timeval { |
561 | 0 | tv_sec: secs as time_t, |
562 | 0 | tv_usec: micros as suseconds_t, |
563 | 0 | }) |
564 | 0 | } |
565 | | |
566 | | /// Makes a new `TimeVal` with given number of nanoseconds. Some precision |
567 | | /// will be lost |
568 | | #[inline] |
569 | 0 | fn nanoseconds(nanoseconds: i64) -> TimeVal { |
570 | 0 | let microseconds = nanoseconds / 1000; |
571 | 0 | let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); |
572 | 0 | assert!( |
573 | 0 | (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), |
574 | 0 | "TimeVal out of bounds" |
575 | | ); |
576 | | #[cfg_attr( |
577 | | any(target_env = "musl", target_env = "ohos"), |
578 | | allow(deprecated) |
579 | | )] |
580 | | // https://github.com/rust-lang/libc/issues/1848 |
581 | 0 | TimeVal(timeval { |
582 | 0 | tv_sec: secs as time_t, |
583 | 0 | tv_usec: micros as suseconds_t, |
584 | 0 | }) |
585 | 0 | } |
586 | | |
587 | | // The cast is not unnecessary on all platforms. |
588 | | #[allow(clippy::unnecessary_cast)] |
589 | 0 | fn num_seconds(&self) -> i64 { |
590 | 0 | if self.tv_sec() < 0 && self.tv_usec() > 0 { |
591 | 0 | (self.tv_sec() + 1) as i64 |
592 | | } else { |
593 | 0 | self.tv_sec() as i64 |
594 | | } |
595 | 0 | } |
596 | | |
597 | 0 | fn num_milliseconds(&self) -> i64 { |
598 | 0 | self.num_microseconds() / 1_000 |
599 | 0 | } |
600 | | |
601 | | // The cast is not unnecessary on all platforms. |
602 | | #[allow(clippy::unnecessary_cast)] |
603 | 0 | fn num_microseconds(&self) -> i64 { |
604 | 0 | let secs = self.num_seconds() * 1_000_000; |
605 | 0 | let usec = self.micros_mod_sec(); |
606 | 0 | secs + usec as i64 |
607 | 0 | } |
608 | | |
609 | 0 | fn num_nanoseconds(&self) -> i64 { |
610 | 0 | self.num_microseconds() * 1_000 |
611 | 0 | } |
612 | | } |
613 | | |
614 | | impl TimeVal { |
615 | | /// Construct a new `TimeVal` from its components |
616 | | #[cfg_attr( |
617 | | any(target_env = "musl", target_env = "ohos"), |
618 | | allow(deprecated) |
619 | | )] // https://github.com/rust-lang/libc/issues/1848 |
620 | 0 | pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self { |
621 | 0 | Self(timeval { |
622 | 0 | tv_sec: seconds, |
623 | 0 | tv_usec: microseconds, |
624 | 0 | }) |
625 | 0 | } |
626 | | |
627 | 0 | fn micros_mod_sec(&self) -> suseconds_t { |
628 | 0 | if self.tv_sec() < 0 && self.tv_usec() > 0 { |
629 | 0 | self.tv_usec() - MICROS_PER_SEC as suseconds_t |
630 | | } else { |
631 | 0 | self.tv_usec() |
632 | | } |
633 | 0 | } |
634 | | |
635 | | #[cfg_attr( |
636 | | any(target_env = "musl", target_env = "ohos"), |
637 | | allow(deprecated) |
638 | | )] // https://github.com/rust-lang/libc/issues/1848 |
639 | 0 | pub const fn tv_sec(&self) -> time_t { |
640 | 0 | self.0.tv_sec |
641 | 0 | } |
642 | | |
643 | 0 | pub const fn tv_usec(&self) -> suseconds_t { |
644 | 0 | self.0.tv_usec |
645 | 0 | } |
646 | | } |
647 | | |
648 | | impl ops::Neg for TimeVal { |
649 | | type Output = TimeVal; |
650 | | |
651 | 0 | fn neg(self) -> TimeVal { |
652 | 0 | TimeVal::microseconds(-self.num_microseconds()) |
653 | 0 | } |
654 | | } |
655 | | |
656 | | impl ops::Add for TimeVal { |
657 | | type Output = TimeVal; |
658 | | |
659 | 0 | fn add(self, rhs: TimeVal) -> TimeVal { |
660 | 0 | TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds()) |
661 | 0 | } |
662 | | } |
663 | | |
664 | | impl ops::Sub for TimeVal { |
665 | | type Output = TimeVal; |
666 | | |
667 | 0 | fn sub(self, rhs: TimeVal) -> TimeVal { |
668 | 0 | TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds()) |
669 | 0 | } |
670 | | } |
671 | | |
672 | | impl ops::Mul<i32> for TimeVal { |
673 | | type Output = TimeVal; |
674 | | |
675 | 0 | fn mul(self, rhs: i32) -> TimeVal { |
676 | 0 | let usec = self |
677 | 0 | .num_microseconds() |
678 | 0 | .checked_mul(i64::from(rhs)) |
679 | 0 | .expect("TimeVal multiply out of bounds"); |
680 | | |
681 | 0 | TimeVal::microseconds(usec) |
682 | 0 | } |
683 | | } |
684 | | |
685 | | impl ops::Div<i32> for TimeVal { |
686 | | type Output = TimeVal; |
687 | | |
688 | 0 | fn div(self, rhs: i32) -> TimeVal { |
689 | 0 | let usec = self.num_microseconds() / i64::from(rhs); |
690 | 0 | TimeVal::microseconds(usec) |
691 | 0 | } |
692 | | } |
693 | | |
694 | | impl fmt::Display for TimeVal { |
695 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
696 | 0 | let (abs, sign) = if self.tv_sec() < 0 { |
697 | 0 | (-*self, "-") |
698 | | } else { |
699 | 0 | (*self, "") |
700 | | }; |
701 | | |
702 | 0 | let sec = abs.tv_sec(); |
703 | | |
704 | 0 | write!(f, "{sign}")?; |
705 | | |
706 | 0 | if abs.tv_usec() == 0 { |
707 | 0 | if sec == 1 { |
708 | 0 | write!(f, "1 second")?; |
709 | | } else { |
710 | 0 | write!(f, "{sec} seconds")?; |
711 | | } |
712 | 0 | } else if abs.tv_usec() % 1000 == 0 { |
713 | 0 | write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?; |
714 | | } else { |
715 | 0 | write!(f, "{sec}.{:06} seconds", abs.tv_usec())?; |
716 | | } |
717 | | |
718 | 0 | Ok(()) |
719 | 0 | } |
720 | | } |
721 | | |
722 | | impl From<timeval> for TimeVal { |
723 | 0 | fn from(tv: timeval) -> Self { |
724 | 0 | TimeVal(tv) |
725 | 0 | } |
726 | | } |
727 | | |
728 | | #[inline] |
729 | 0 | fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { |
730 | 0 | (div_floor_64(this, other), mod_floor_64(this, other)) |
731 | 0 | } |
732 | | |
733 | | #[inline] |
734 | 0 | fn div_floor_64(this: i64, other: i64) -> i64 { |
735 | 0 | match div_rem_64(this, other) { |
736 | 0 | (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, |
737 | 0 | (d, _) => d, |
738 | | } |
739 | 0 | } |
740 | | |
741 | | #[inline] |
742 | 0 | fn mod_floor_64(this: i64, other: i64) -> i64 { |
743 | 0 | match this % other { |
744 | 0 | r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, |
745 | 0 | r => r, |
746 | | } |
747 | 0 | } |
748 | | |
749 | | #[inline] |
750 | 0 | fn div_rem_64(this: i64, other: i64) -> (i64, i64) { |
751 | 0 | (this / other, this % other) |
752 | 0 | } |