| #[cfg_attr(target_env = "musl", allow(deprecated))] | |
| // https://github.com/rust-lang/libc/issues/1848 | |
| pub use libc::{suseconds_t, time_t}; | |
| use libc::{timespec, timeval}; | |
| use std::convert::From; | |
| use std::time::Duration; | |
| use std::{cmp, fmt, ops}; | |
| const fn zero_init_timespec() -> timespec { | |
| // `std::mem::MaybeUninit::zeroed()` is not yet a const fn | |
| // (https://github.com/rust-lang/rust/issues/91850) so we will instead initialize an array of | |
| // the appropriate size to zero and then transmute it to a timespec value. | |
| unsafe { std::mem::transmute([0u8; std::mem::size_of::<timespec>()]) } | |
| } | |
| #[cfg(any( | |
| all(feature = "time", any(target_os = "android", target_os = "linux")), | |
| all( | |
| any( | |
| target_os = "freebsd", | |
| target_os = "illumos", | |
| target_os = "linux", | |
| target_os = "netbsd" | |
| ), | |
| feature = "time", | |
| feature = "signal" | |
| ) | |
| ))] | |
| pub(crate) mod timer { | |
| use crate::sys::time::{zero_init_timespec, TimeSpec}; | |
| use bitflags::bitflags; | |
| #[derive(Debug, Clone, Copy)] | |
| pub(crate) struct TimerSpec(libc::itimerspec); | |
| impl TimerSpec { | |
| pub const fn none() -> Self { | |
| Self(libc::itimerspec { | |
| it_interval: zero_init_timespec(), | |
| it_value: zero_init_timespec(), | |
| }) | |
| } | |
| } | |
| impl AsMut<libc::itimerspec> for TimerSpec { | |
| fn as_mut(&mut self) -> &mut libc::itimerspec { | |
| &mut self.0 | |
| } | |
| } | |
| impl AsRef<libc::itimerspec> for TimerSpec { | |
| fn as_ref(&self) -> &libc::itimerspec { | |
| &self.0 | |
| } | |
| } | |
| impl From<Expiration> for TimerSpec { | |
| fn from(expiration: Expiration) -> TimerSpec { | |
| match expiration { | |
| Expiration::OneShot(t) => TimerSpec(libc::itimerspec { | |
| it_interval: zero_init_timespec(), | |
| it_value: *t.as_ref(), | |
| }), | |
| Expiration::IntervalDelayed(start, interval) => { | |
| TimerSpec(libc::itimerspec { | |
| it_interval: *interval.as_ref(), | |
| it_value: *start.as_ref(), | |
| }) | |
| } | |
| Expiration::Interval(t) => TimerSpec(libc::itimerspec { | |
| it_interval: *t.as_ref(), | |
| it_value: *t.as_ref(), | |
| }), | |
| } | |
| } | |
| } | |
| /// An enumeration allowing the definition of the expiration time of an alarm, | |
| /// recurring or not. | |
| #[derive(Debug, Clone, Copy, Eq, PartialEq)] | |
| pub enum Expiration { | |
| /// Alarm will trigger once after the time given in `TimeSpec` | |
| OneShot(TimeSpec), | |
| /// Alarm will trigger after a specified delay and then every interval of | |
| /// time. | |
| IntervalDelayed(TimeSpec, TimeSpec), | |
| /// Alarm will trigger every specified interval of time. | |
| Interval(TimeSpec), | |
| } | |
| #[cfg(any(target_os = "android", target_os = "linux"))] | |
| bitflags! { | |
| /// Flags that are used for arming the timer. | |
| #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] | |
| pub struct TimerSetTimeFlags: libc::c_int { | |
| const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME; | |
| const TFD_TIMER_CANCEL_ON_SET = libc::TFD_TIMER_CANCEL_ON_SET; | |
| } | |
| } | |
| #[cfg(any( | |
| target_os = "freebsd", | |
| target_os = "netbsd", | |
| target_os = "dragonfly", | |
| target_os = "illumos" | |
| ))] | |
| bitflags! { | |
| /// Flags that are used for arming the timer. | |
| #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] | |
| pub struct TimerSetTimeFlags: libc::c_int { | |
| const TFD_TIMER_ABSTIME = libc::TIMER_ABSTIME; | |
| } | |
| } | |
| impl From<TimerSpec> for Expiration { | |
| fn from(timerspec: TimerSpec) -> Expiration { | |
| match timerspec { | |
| TimerSpec(libc::itimerspec { | |
| it_interval: | |
| libc::timespec { | |
| tv_sec: 0, | |
| tv_nsec: 0, | |
| .. | |
| }, | |
| it_value: ts, | |
| }) => Expiration::OneShot(ts.into()), | |
| TimerSpec(libc::itimerspec { | |
| it_interval: int_ts, | |
| it_value: val_ts, | |
| }) => { | |
| if (int_ts.tv_sec == val_ts.tv_sec) | |
| && (int_ts.tv_nsec == val_ts.tv_nsec) | |
| { | |
| Expiration::Interval(int_ts.into()) | |
| } else { | |
| Expiration::IntervalDelayed( | |
| val_ts.into(), | |
| int_ts.into(), | |
| ) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| pub trait TimeValLike: Sized { | |
| #[inline] | |
| fn zero() -> Self { | |
| Self::seconds(0) | |
| } | |
| #[inline] | |
| fn hours(hours: i64) -> Self { | |
| let secs = hours | |
| .checked_mul(SECS_PER_HOUR) | |
| .expect("TimeValLike::hours ouf of bounds"); | |
| Self::seconds(secs) | |
| } | |
| #[inline] | |
| fn minutes(minutes: i64) -> Self { | |
| let secs = minutes | |
| .checked_mul(SECS_PER_MINUTE) | |
| .expect("TimeValLike::minutes out of bounds"); | |
| Self::seconds(secs) | |
| } | |
| fn seconds(seconds: i64) -> Self; | |
| fn milliseconds(milliseconds: i64) -> Self; | |
| fn microseconds(microseconds: i64) -> Self; | |
| fn nanoseconds(nanoseconds: i64) -> Self; | |
| #[inline] | |
| fn num_hours(&self) -> i64 { | |
| self.num_seconds() / 3600 | |
| } | |
| #[inline] | |
| fn num_minutes(&self) -> i64 { | |
| self.num_seconds() / 60 | |
| } | |
| fn num_seconds(&self) -> i64; | |
| fn num_milliseconds(&self) -> i64; | |
| fn num_microseconds(&self) -> i64; | |
| fn num_nanoseconds(&self) -> i64; | |
| } | |
| #[repr(C)] | |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |
| pub struct TimeSpec(timespec); | |
| const NANOS_PER_SEC: i64 = 1_000_000_000; | |
| const SECS_PER_MINUTE: i64 = 60; | |
| const SECS_PER_HOUR: i64 = 3600; | |
| #[cfg(target_pointer_width = "64")] | |
| const TS_MAX_SECONDS: i64 = (i64::MAX / NANOS_PER_SEC) - 1; | |
| #[cfg(target_pointer_width = "32")] | |
| const TS_MAX_SECONDS: i64 = isize::MAX as i64; | |
| const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS; | |
| // x32 compatibility | |
| // See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 | |
| #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] | |
| type timespec_tv_nsec_t = i64; | |
| #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] | |
| type timespec_tv_nsec_t = libc::c_long; | |
| impl From<timespec> for TimeSpec { | |
| fn from(ts: timespec) -> Self { | |
| Self(ts) | |
| } | |
| } | |
| impl From<Duration> for TimeSpec { | |
| fn from(duration: Duration) -> Self { | |
| Self::from_duration(duration) | |
| } | |
| } | |
| impl From<TimeSpec> for Duration { | |
| fn from(timespec: TimeSpec) -> Self { | |
| Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32) | |
| } | |
| } | |
| impl AsRef<timespec> for TimeSpec { | |
| fn as_ref(&self) -> ×pec { | |
| &self.0 | |
| } | |
| } | |
| impl AsMut<timespec> for TimeSpec { | |
| fn as_mut(&mut self) -> &mut timespec { | |
| &mut self.0 | |
| } | |
| } | |
| impl Ord for TimeSpec { | |
| // The implementation of cmp is simplified by assuming that the struct is | |
| // normalized. That is, tv_nsec must always be within [0, 1_000_000_000) | |
| fn cmp(&self, other: &TimeSpec) -> cmp::Ordering { | |
| if self.tv_sec() == other.tv_sec() { | |
| self.tv_nsec().cmp(&other.tv_nsec()) | |
| } else { | |
| self.tv_sec().cmp(&other.tv_sec()) | |
| } | |
| } | |
| } | |
| impl PartialOrd for TimeSpec { | |
| fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> { | |
| Some(self.cmp(other)) | |
| } | |
| } | |
| impl TimeValLike for TimeSpec { | |
| #[inline] | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] | |
| // https://github.com/rust-lang/libc/issues/1848 | |
| fn seconds(seconds: i64) -> TimeSpec { | |
| assert!( | |
| (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&seconds), | |
| "TimeSpec out of bounds; seconds={seconds}", | |
| ); | |
| let mut ts = zero_init_timespec(); | |
| ts.tv_sec = seconds as time_t; | |
| TimeSpec(ts) | |
| } | |
| #[inline] | |
| fn milliseconds(milliseconds: i64) -> TimeSpec { | |
| let nanoseconds = milliseconds | |
| .checked_mul(1_000_000) | |
| .expect("TimeSpec::milliseconds out of bounds"); | |
| TimeSpec::nanoseconds(nanoseconds) | |
| } | |
| /// Makes a new `TimeSpec` with given number of microseconds. | |
| #[inline] | |
| fn microseconds(microseconds: i64) -> TimeSpec { | |
| let nanoseconds = microseconds | |
| .checked_mul(1_000) | |
| .expect("TimeSpec::milliseconds out of bounds"); | |
| TimeSpec::nanoseconds(nanoseconds) | |
| } | |
| /// Makes a new `TimeSpec` with given number of nanoseconds. | |
| #[inline] | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] | |
| // https://github.com/rust-lang/libc/issues/1848 | |
| fn nanoseconds(nanoseconds: i64) -> TimeSpec { | |
| let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC); | |
| assert!( | |
| (TS_MIN_SECONDS..=TS_MAX_SECONDS).contains(&secs), | |
| "TimeSpec out of bounds" | |
| ); | |
| let mut ts = zero_init_timespec(); | |
| ts.tv_sec = secs as time_t; | |
| ts.tv_nsec = nanos as timespec_tv_nsec_t; | |
| TimeSpec(ts) | |
| } | |
| // The cast is not unnecessary on all platforms. | |
| #[allow(clippy::unnecessary_cast)] | |
| fn num_seconds(&self) -> i64 { | |
| if self.tv_sec() < 0 && self.tv_nsec() > 0 { | |
| (self.tv_sec() + 1) as i64 | |
| } else { | |
| self.tv_sec() as i64 | |
| } | |
| } | |
| fn num_milliseconds(&self) -> i64 { | |
| self.num_nanoseconds() / 1_000_000 | |
| } | |
| fn num_microseconds(&self) -> i64 { | |
| self.num_nanoseconds() / 1_000 | |
| } | |
| // The cast is not unnecessary on all platforms. | |
| #[allow(clippy::unnecessary_cast)] | |
| fn num_nanoseconds(&self) -> i64 { | |
| let secs = self.num_seconds() * 1_000_000_000; | |
| let nsec = self.nanos_mod_sec(); | |
| secs + nsec as i64 | |
| } | |
| } | |
| impl TimeSpec { | |
| /// Construct a new `TimeSpec` from its components | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 | |
| pub const fn new(seconds: time_t, nanoseconds: timespec_tv_nsec_t) -> Self { | |
| let mut ts = zero_init_timespec(); | |
| ts.tv_sec = seconds; | |
| ts.tv_nsec = nanoseconds; | |
| Self(ts) | |
| } | |
| fn nanos_mod_sec(&self) -> timespec_tv_nsec_t { | |
| if self.tv_sec() < 0 && self.tv_nsec() > 0 { | |
| self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t | |
| } else { | |
| self.tv_nsec() | |
| } | |
| } | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 | |
| pub const fn tv_sec(&self) -> time_t { | |
| self.0.tv_sec | |
| } | |
| pub const fn tv_nsec(&self) -> timespec_tv_nsec_t { | |
| self.0.tv_nsec | |
| } | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] | |
| // https://github.com/rust-lang/libc/issues/1848 | |
| pub const fn from_duration(duration: Duration) -> Self { | |
| let mut ts = zero_init_timespec(); | |
| ts.tv_sec = duration.as_secs() as time_t; | |
| ts.tv_nsec = duration.subsec_nanos() as timespec_tv_nsec_t; | |
| TimeSpec(ts) | |
| } | |
| pub const fn from_timespec(timespec: timespec) -> Self { | |
| Self(timespec) | |
| } | |
| } | |
| impl ops::Neg for TimeSpec { | |
| type Output = TimeSpec; | |
| fn neg(self) -> TimeSpec { | |
| TimeSpec::nanoseconds(-self.num_nanoseconds()) | |
| } | |
| } | |
| impl ops::Add for TimeSpec { | |
| type Output = TimeSpec; | |
| fn add(self, rhs: TimeSpec) -> TimeSpec { | |
| TimeSpec::nanoseconds(self.num_nanoseconds() + rhs.num_nanoseconds()) | |
| } | |
| } | |
| impl ops::Sub for TimeSpec { | |
| type Output = TimeSpec; | |
| fn sub(self, rhs: TimeSpec) -> TimeSpec { | |
| TimeSpec::nanoseconds(self.num_nanoseconds() - rhs.num_nanoseconds()) | |
| } | |
| } | |
| impl ops::Mul<i32> for TimeSpec { | |
| type Output = TimeSpec; | |
| fn mul(self, rhs: i32) -> TimeSpec { | |
| let usec = self | |
| .num_nanoseconds() | |
| .checked_mul(i64::from(rhs)) | |
| .expect("TimeSpec multiply out of bounds"); | |
| TimeSpec::nanoseconds(usec) | |
| } | |
| } | |
| impl ops::Div<i32> for TimeSpec { | |
| type Output = TimeSpec; | |
| fn div(self, rhs: i32) -> TimeSpec { | |
| let usec = self.num_nanoseconds() / i64::from(rhs); | |
| TimeSpec::nanoseconds(usec) | |
| } | |
| } | |
| impl fmt::Display for TimeSpec { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| let (abs, sign) = if self.tv_sec() < 0 { | |
| (-*self, "-") | |
| } else { | |
| (*self, "") | |
| }; | |
| let sec = abs.tv_sec(); | |
| write!(f, "{sign}")?; | |
| if abs.tv_nsec() == 0 { | |
| if sec == 1 { | |
| write!(f, "1 second")?; | |
| } else { | |
| write!(f, "{sec} seconds")?; | |
| } | |
| } else if abs.tv_nsec() % 1_000_000 == 0 { | |
| write!(f, "{sec}.{:03} seconds", abs.tv_nsec() / 1_000_000)?; | |
| } else if abs.tv_nsec() % 1_000 == 0 { | |
| write!(f, "{sec}.{:06} seconds", abs.tv_nsec() / 1_000)?; | |
| } else { | |
| write!(f, "{sec}.{:09} seconds", abs.tv_nsec())?; | |
| } | |
| Ok(()) | |
| } | |
| } | |
| #[repr(transparent)] | |
| #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] | |
| pub struct TimeVal(timeval); | |
| const MICROS_PER_SEC: i64 = 1_000_000; | |
| #[cfg(target_pointer_width = "64")] | |
| const TV_MAX_SECONDS: i64 = (i64::MAX / MICROS_PER_SEC) - 1; | |
| #[cfg(target_pointer_width = "32")] | |
| const TV_MAX_SECONDS: i64 = isize::MAX as i64; | |
| const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS; | |
| impl AsRef<timeval> for TimeVal { | |
| fn as_ref(&self) -> &timeval { | |
| &self.0 | |
| } | |
| } | |
| impl AsMut<timeval> for TimeVal { | |
| fn as_mut(&mut self) -> &mut timeval { | |
| &mut self.0 | |
| } | |
| } | |
| impl Ord for TimeVal { | |
| // The implementation of cmp is simplified by assuming that the struct is | |
| // normalized. That is, tv_usec must always be within [0, 1_000_000) | |
| fn cmp(&self, other: &TimeVal) -> cmp::Ordering { | |
| if self.tv_sec() == other.tv_sec() { | |
| self.tv_usec().cmp(&other.tv_usec()) | |
| } else { | |
| self.tv_sec().cmp(&other.tv_sec()) | |
| } | |
| } | |
| } | |
| impl PartialOrd for TimeVal { | |
| fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> { | |
| Some(self.cmp(other)) | |
| } | |
| } | |
| impl TimeValLike for TimeVal { | |
| #[inline] | |
| fn seconds(seconds: i64) -> TimeVal { | |
| assert!( | |
| (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&seconds), | |
| "TimeVal out of bounds; seconds={seconds}" | |
| ); | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] | |
| // https://github.com/rust-lang/libc/issues/1848 | |
| TimeVal(timeval { | |
| tv_sec: seconds as time_t, | |
| tv_usec: 0, | |
| }) | |
| } | |
| #[inline] | |
| fn milliseconds(milliseconds: i64) -> TimeVal { | |
| let microseconds = milliseconds | |
| .checked_mul(1_000) | |
| .expect("TimeVal::milliseconds out of bounds"); | |
| TimeVal::microseconds(microseconds) | |
| } | |
| /// Makes a new `TimeVal` with given number of microseconds. | |
| #[inline] | |
| fn microseconds(microseconds: i64) -> TimeVal { | |
| let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); | |
| assert!( | |
| (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), | |
| "TimeVal out of bounds" | |
| ); | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] | |
| // https://github.com/rust-lang/libc/issues/1848 | |
| TimeVal(timeval { | |
| tv_sec: secs as time_t, | |
| tv_usec: micros as suseconds_t, | |
| }) | |
| } | |
| /// Makes a new `TimeVal` with given number of nanoseconds. Some precision | |
| /// will be lost | |
| #[inline] | |
| fn nanoseconds(nanoseconds: i64) -> TimeVal { | |
| let microseconds = nanoseconds / 1000; | |
| let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); | |
| assert!( | |
| (TV_MIN_SECONDS..=TV_MAX_SECONDS).contains(&secs), | |
| "TimeVal out of bounds" | |
| ); | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] | |
| // https://github.com/rust-lang/libc/issues/1848 | |
| TimeVal(timeval { | |
| tv_sec: secs as time_t, | |
| tv_usec: micros as suseconds_t, | |
| }) | |
| } | |
| // The cast is not unnecessary on all platforms. | |
| #[allow(clippy::unnecessary_cast)] | |
| fn num_seconds(&self) -> i64 { | |
| if self.tv_sec() < 0 && self.tv_usec() > 0 { | |
| (self.tv_sec() + 1) as i64 | |
| } else { | |
| self.tv_sec() as i64 | |
| } | |
| } | |
| fn num_milliseconds(&self) -> i64 { | |
| self.num_microseconds() / 1_000 | |
| } | |
| // The cast is not unnecessary on all platforms. | |
| #[allow(clippy::unnecessary_cast)] | |
| fn num_microseconds(&self) -> i64 { | |
| let secs = self.num_seconds() * 1_000_000; | |
| let usec = self.micros_mod_sec(); | |
| secs + usec as i64 | |
| } | |
| fn num_nanoseconds(&self) -> i64 { | |
| self.num_microseconds() * 1_000 | |
| } | |
| } | |
| impl TimeVal { | |
| /// Construct a new `TimeVal` from its components | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 | |
| pub const fn new(seconds: time_t, microseconds: suseconds_t) -> Self { | |
| Self(timeval { | |
| tv_sec: seconds, | |
| tv_usec: microseconds, | |
| }) | |
| } | |
| fn micros_mod_sec(&self) -> suseconds_t { | |
| if self.tv_sec() < 0 && self.tv_usec() > 0 { | |
| self.tv_usec() - MICROS_PER_SEC as suseconds_t | |
| } else { | |
| self.tv_usec() | |
| } | |
| } | |
| #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848 | |
| pub const fn tv_sec(&self) -> time_t { | |
| self.0.tv_sec | |
| } | |
| pub const fn tv_usec(&self) -> suseconds_t { | |
| self.0.tv_usec | |
| } | |
| } | |
| impl ops::Neg for TimeVal { | |
| type Output = TimeVal; | |
| fn neg(self) -> TimeVal { | |
| TimeVal::microseconds(-self.num_microseconds()) | |
| } | |
| } | |
| impl ops::Add for TimeVal { | |
| type Output = TimeVal; | |
| fn add(self, rhs: TimeVal) -> TimeVal { | |
| TimeVal::microseconds(self.num_microseconds() + rhs.num_microseconds()) | |
| } | |
| } | |
| impl ops::Sub for TimeVal { | |
| type Output = TimeVal; | |
| fn sub(self, rhs: TimeVal) -> TimeVal { | |
| TimeVal::microseconds(self.num_microseconds() - rhs.num_microseconds()) | |
| } | |
| } | |
| impl ops::Mul<i32> for TimeVal { | |
| type Output = TimeVal; | |
| fn mul(self, rhs: i32) -> TimeVal { | |
| let usec = self | |
| .num_microseconds() | |
| .checked_mul(i64::from(rhs)) | |
| .expect("TimeVal multiply out of bounds"); | |
| TimeVal::microseconds(usec) | |
| } | |
| } | |
| impl ops::Div<i32> for TimeVal { | |
| type Output = TimeVal; | |
| fn div(self, rhs: i32) -> TimeVal { | |
| let usec = self.num_microseconds() / i64::from(rhs); | |
| TimeVal::microseconds(usec) | |
| } | |
| } | |
| impl fmt::Display for TimeVal { | |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
| let (abs, sign) = if self.tv_sec() < 0 { | |
| (-*self, "-") | |
| } else { | |
| (*self, "") | |
| }; | |
| let sec = abs.tv_sec(); | |
| write!(f, "{sign}")?; | |
| if abs.tv_usec() == 0 { | |
| if sec == 1 { | |
| write!(f, "1 second")?; | |
| } else { | |
| write!(f, "{sec} seconds")?; | |
| } | |
| } else if abs.tv_usec() % 1000 == 0 { | |
| write!(f, "{sec}.{:03} seconds", abs.tv_usec() / 1000)?; | |
| } else { | |
| write!(f, "{sec}.{:06} seconds", abs.tv_usec())?; | |
| } | |
| Ok(()) | |
| } | |
| } | |
| impl From<timeval> for TimeVal { | |
| fn from(tv: timeval) -> Self { | |
| TimeVal(tv) | |
| } | |
| } | |
| #[inline] | |
| fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { | |
| (div_floor_64(this, other), mod_floor_64(this, other)) | |
| } | |
| #[inline] | |
| fn div_floor_64(this: i64, other: i64) -> i64 { | |
| match div_rem_64(this, other) { | |
| (d, r) if (r > 0 && other < 0) || (r < 0 && other > 0) => d - 1, | |
| (d, _) => d, | |
| } | |
| } | |
| #[inline] | |
| fn mod_floor_64(this: i64, other: i64) -> i64 { | |
| match this % other { | |
| r if (r > 0 && other < 0) || (r < 0 && other > 0) => r + other, | |
| r => r, | |
| } | |
| } | |
| #[inline] | |
| fn div_rem_64(this: i64, other: i64) -> (i64, i64) { | |
| (this / other, this % other) | |
| } | |
| #[cfg(test)] | |
| mod test { | |
| use super::{TimeSpec, TimeVal, TimeValLike}; | |
| use std::time::Duration; | |
| #[test] | |
| pub fn test_timespec() { | |
| assert_ne!(TimeSpec::seconds(1), TimeSpec::zero()); | |
| assert_eq!( | |
| TimeSpec::seconds(1) + TimeSpec::seconds(2), | |
| TimeSpec::seconds(3) | |
| ); | |
| assert_eq!( | |
| TimeSpec::minutes(3) + TimeSpec::seconds(2), | |
| TimeSpec::seconds(182) | |
| ); | |
| } | |
| #[test] | |
| pub fn test_timespec_from() { | |
| let duration = Duration::new(123, 123_456_789); | |
| let timespec = TimeSpec::nanoseconds(123_123_456_789); | |
| assert_eq!(TimeSpec::from(duration), timespec); | |
| assert_eq!(Duration::from(timespec), duration); | |
| } | |
| #[test] | |
| pub fn test_timespec_neg() { | |
| let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123); | |
| let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123); | |
| assert_eq!(a, -b); | |
| } | |
| #[test] | |
| pub fn test_timespec_ord() { | |
| assert_eq!(TimeSpec::seconds(1), TimeSpec::nanoseconds(1_000_000_000)); | |
| assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001)); | |
| assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999)); | |
| assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999)); | |
| assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001)); | |
| } | |
| #[test] | |
| pub fn test_timespec_fmt() { | |
| assert_eq!(TimeSpec::zero().to_string(), "0 seconds"); | |
| assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds"); | |
| assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds"); | |
| assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds"); | |
| assert_eq!( | |
| TimeSpec::nanoseconds(42).to_string(), | |
| "0.000000042 seconds" | |
| ); | |
| assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds"); | |
| } | |
| #[test] | |
| pub fn test_timeval() { | |
| assert_ne!(TimeVal::seconds(1), TimeVal::zero()); | |
| assert_eq!( | |
| TimeVal::seconds(1) + TimeVal::seconds(2), | |
| TimeVal::seconds(3) | |
| ); | |
| assert_eq!( | |
| TimeVal::minutes(3) + TimeVal::seconds(2), | |
| TimeVal::seconds(182) | |
| ); | |
| } | |
| #[test] | |
| pub fn test_timeval_ord() { | |
| assert_eq!(TimeVal::seconds(1), TimeVal::microseconds(1_000_000)); | |
| assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001)); | |
| assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999)); | |
| assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999)); | |
| assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001)); | |
| } | |
| #[test] | |
| pub fn test_timeval_neg() { | |
| let a = TimeVal::seconds(1) + TimeVal::microseconds(123); | |
| let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123); | |
| assert_eq!(a, -b); | |
| } | |
| #[test] | |
| pub fn test_timeval_fmt() { | |
| assert_eq!(TimeVal::zero().to_string(), "0 seconds"); | |
| assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds"); | |
| assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds"); | |
| assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds"); | |
| assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds"); | |
| assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds"); | |
| } | |
| } |