diff options
Diffstat (limited to 'vendor/time/src/duration.rs')
-rw-r--r-- | vendor/time/src/duration.rs | 442 |
1 files changed, 356 insertions, 86 deletions
diff --git a/vendor/time/src/duration.rs b/vendor/time/src/duration.rs index 47c3f1516..453d2254d 100644 --- a/vendor/time/src/duration.rs +++ b/vendor/time/src/duration.rs @@ -6,6 +6,7 @@ use core::iter::Sum; use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; use core::time::Duration as StdDuration; +use crate::convert::*; use crate::error; #[cfg(feature = "std")] use crate::Instant; @@ -50,6 +51,124 @@ impl fmt::Debug for Duration { } } +/// This is adapted from the `std` implementation, which uses mostly bit +/// operations to ensure the highest precision: +/// https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340 +/// Changes from `std` are marked and explained below. +#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly. +macro_rules! try_from_secs { + ( + secs = $secs: expr, + mantissa_bits = $mant_bits: literal, + exponent_bits = $exp_bits: literal, + offset = $offset: literal, + bits_ty = $bits_ty:ty, + bits_ty_signed = $bits_ty_signed:ty, + double_ty = $double_ty:ty, + float_ty = $float_ty:ty, + is_nan = $is_nan:expr, + is_overflow = $is_overflow:expr, + ) => {{ + 'value: { + const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2; + const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1; + const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1; + + // Change from std: No error check for negative values necessary. + + let bits = $secs.to_bits(); + let mant = (bits & MANT_MASK) | (MANT_MASK + 1); + let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP; + + let (secs, nanos) = if exp < -31 { + // the input represents less than 1ns and can not be rounded to it + (0u64, 0u32) + } else if exp < 0 { + // the input is less than 1 second + let t = <$double_ty>::from(mant) << ($offset + exp); + let nanos_offset = $mant_bits + $offset; + let nanos_tmp = u128::from(Nanosecond.per(Second)) * u128::from(t); + let nanos = (nanos_tmp >> nanos_offset) as u32; + + let rem_mask = (1 << nanos_offset) - 1; + let rem_msb_mask = 1 << (nanos_offset - 1); + let rem = nanos_tmp & rem_mask; + let is_tie = rem == rem_msb_mask; + let is_even = (nanos & 1) == 0; + let rem_msb = nanos_tmp & rem_msb_mask == 0; + let add_ns = !(rem_msb || (is_even && is_tie)); + + // f32 does not have enough precision to trigger the second branch + // since it can not represent numbers between 0.999_999_940_395 and 1.0. + let nanos = nanos + add_ns as u32; + if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) { + (0, nanos) + } else { + (1, 0) + } + } else if exp < $mant_bits { + let secs = u64::from(mant >> ($mant_bits - exp)); + let t = <$double_ty>::from((mant << exp) & MANT_MASK); + let nanos_offset = $mant_bits; + let nanos_tmp = <$double_ty>::from(Nanosecond.per(Second)) * t; + let nanos = (nanos_tmp >> nanos_offset) as u32; + + let rem_mask = (1 << nanos_offset) - 1; + let rem_msb_mask = 1 << (nanos_offset - 1); + let rem = nanos_tmp & rem_mask; + let is_tie = rem == rem_msb_mask; + let is_even = (nanos & 1) == 0; + let rem_msb = nanos_tmp & rem_msb_mask == 0; + let add_ns = !(rem_msb || (is_even && is_tie)); + + // f32 does not have enough precision to trigger the second branch. + // For example, it can not represent numbers between 1.999_999_880... + // and 2.0. Bigger values result in even smaller precision of the + // fractional part. + let nanos = nanos + add_ns as u32; + if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) { + (secs, nanos) + } else { + (secs + 1, 0) + } + } else if exp < 63 { + // Change from std: The exponent here is 63 instead of 64, + // because i64::MAX + 1 is 2^63. + + // the input has no fractional part + let secs = u64::from(mant) << (exp - $mant_bits); + (secs, 0) + } else if bits == (i64::MIN as $float_ty).to_bits() { + // Change from std: Signed integers are asymmetrical in that + // iN::MIN is -iN::MAX - 1. So for example i8 covers the + // following numbers -128..=127. The check above (exp < 63) + // doesn't cover i64::MIN as that is -2^63, so we have this + // additional case to handle the asymmetry of iN::MIN. + break 'value Self::new_unchecked(i64::MIN, 0); + } else if $secs.is_nan() { + // Change from std: std doesn't differentiate between the error + // cases. + $is_nan + } else { + $is_overflow + }; + + // Change from std: All the code is mostly unmodified in that it + // simply calculates an unsigned integer. Here we extract the sign + // bit and assign it to the number. We basically manually do two's + // complement here, we could also use an if and just negate the + // numbers based on the sign, but it turns out to be quite a bit + // slower. + let mask = (bits as $bits_ty_signed) >> ($mant_bits + $exp_bits); + #[allow(trivial_numeric_casts)] + let secs_signed = ((secs as i64) ^ (mask as i64)) - (mask as i64); + #[allow(trivial_numeric_casts)] + let nanos_signed = ((nanos as i32) ^ (mask as i32)) - (mask as i32); + Self::new_unchecked(secs_signed, nanos_signed) + } + }}; +} + impl Duration { // region: constants /// Equivalent to `0.seconds()`. @@ -125,10 +244,10 @@ impl Duration { pub const WEEK: Self = Self::weeks(1); /// The minimum possible duration. Adding any negative duration to this will cause an overflow. - pub const MIN: Self = Self::new_unchecked(i64::MIN, -999_999_999); + pub const MIN: Self = Self::new_unchecked(i64::MIN, -((Nanosecond.per(Second) - 1) as i32)); /// The maximum possible duration. Adding any positive duration to this will cause an overflow. - pub const MAX: Self = Self::new_unchecked(i64::MAX, 999_999_999); + pub const MAX: Self = Self::new_unchecked(i64::MAX, (Nanosecond.per(Second) - 1) as _); // endregion constants // region: is_{sign} @@ -202,12 +321,12 @@ impl Duration { pub(crate) const fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self { if seconds < 0 { debug_assert!(nanoseconds <= 0); - debug_assert!(nanoseconds > -1_000_000_000); + debug_assert!(nanoseconds > -(Nanosecond.per(Second) as i32)); } else if seconds > 0 { debug_assert!(nanoseconds >= 0); - debug_assert!(nanoseconds < 1_000_000_000); + debug_assert!(nanoseconds < Nanosecond.per(Second) as _); } else { - debug_assert!(nanoseconds.unsigned_abs() < 1_000_000_000); + debug_assert!(nanoseconds.unsigned_abs() < Nanosecond.per(Second)); } Self { @@ -228,19 +347,19 @@ impl Duration { /// ``` pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self { seconds = expect_opt!( - seconds.checked_add(nanoseconds as i64 / 1_000_000_000), + seconds.checked_add(nanoseconds as i64 / Nanosecond.per(Second) as i64), "overflow constructing `time::Duration`" ); - nanoseconds %= 1_000_000_000; + nanoseconds %= Nanosecond.per(Second) as i32; if seconds > 0 && nanoseconds < 0 { // `seconds` cannot overflow here because it is positive. seconds -= 1; - nanoseconds += 1_000_000_000; + nanoseconds += Nanosecond.per(Second) as i32; } else if seconds < 0 && nanoseconds > 0 { // `seconds` cannot overflow here because it is negative. seconds += 1; - nanoseconds -= 1_000_000_000; + nanoseconds -= Nanosecond.per(Second) as i32; } Self::new_unchecked(seconds, nanoseconds) @@ -255,7 +374,7 @@ impl Duration { /// ``` pub const fn weeks(weeks: i64) -> Self { Self::seconds(expect_opt!( - weeks.checked_mul(604_800), + weeks.checked_mul(Second.per(Week) as _), "overflow constructing `time::Duration`" )) } @@ -269,7 +388,7 @@ impl Duration { /// ``` pub const fn days(days: i64) -> Self { Self::seconds(expect_opt!( - days.checked_mul(86_400), + days.checked_mul(Second.per(Day) as _), "overflow constructing `time::Duration`" )) } @@ -283,7 +402,7 @@ impl Duration { /// ``` pub const fn hours(hours: i64) -> Self { Self::seconds(expect_opt!( - hours.checked_mul(3_600), + hours.checked_mul(Second.per(Hour) as _), "overflow constructing `time::Duration`" )) } @@ -297,7 +416,7 @@ impl Duration { /// ``` pub const fn minutes(minutes: i64) -> Self { Self::seconds(expect_opt!( - minutes.checked_mul(60), + minutes.checked_mul(Second.per(Minute) as _), "overflow constructing `time::Duration`" )) } @@ -320,16 +439,18 @@ impl Duration { /// assert_eq!(Duration::seconds_f64(-0.5), -0.5.seconds()); /// ``` pub fn seconds_f64(seconds: f64) -> Self { - if seconds > i64::MAX as f64 || seconds < i64::MIN as f64 { - crate::expect_failed("overflow constructing `time::Duration`"); - } - if seconds.is_nan() { - crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"); - } - let seconds_truncated = seconds as i64; - // This only works because we handle the overflow condition above. - let nanoseconds = ((seconds - seconds_truncated as f64) * 1_000_000_000.) as i32; - Self::new_unchecked(seconds_truncated, nanoseconds) + try_from_secs!( + secs = seconds, + mantissa_bits = 52, + exponent_bits = 11, + offset = 44, + bits_ty = u64, + bits_ty_signed = i64, + double_ty = u128, + float_ty = f64, + is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"), + is_overflow = crate::expect_failed("overflow constructing `time::Duration`"), + ) } /// Creates a new `Duration` from the specified number of seconds represented as `f32`. @@ -340,16 +461,146 @@ impl Duration { /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds()); /// ``` pub fn seconds_f32(seconds: f32) -> Self { - if seconds > i64::MAX as f32 || seconds < i64::MIN as f32 { - crate::expect_failed("overflow constructing `time::Duration`"); - } - if seconds.is_nan() { - crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"); - } - let seconds_truncated = seconds as i64; - // This only works because we handle the overflow condition above. - let nanoseconds = ((seconds - seconds_truncated as f32) * 1_000_000_000.) as i32; - Self::new_unchecked(seconds_truncated, nanoseconds) + try_from_secs!( + secs = seconds, + mantissa_bits = 23, + exponent_bits = 8, + offset = 41, + bits_ty = u32, + bits_ty_signed = i32, + double_ty = u64, + float_ty = f32, + is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"), + is_overflow = crate::expect_failed("overflow constructing `time::Duration`"), + ) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f64`. Any values that are out of bounds are saturated at + /// the minimum or maximum respectively. `NaN` gets turned into a `Duration` + /// of 0 seconds. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::saturating_seconds_f64(0.5), 0.5.seconds()); + /// assert_eq!(Duration::saturating_seconds_f64(-0.5), -0.5.seconds()); + /// assert_eq!( + /// Duration::saturating_seconds_f64(f64::NAN), + /// Duration::new(0, 0), + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f64(f64::NEG_INFINITY), + /// Duration::MIN, + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f64(f64::INFINITY), + /// Duration::MAX, + /// ); + /// ``` + pub fn saturating_seconds_f64(seconds: f64) -> Self { + try_from_secs!( + secs = seconds, + mantissa_bits = 52, + exponent_bits = 11, + offset = 44, + bits_ty = u64, + bits_ty_signed = i64, + double_ty = u128, + float_ty = f64, + is_nan = return Self::ZERO, + is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX }, + ) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f32`. Any values that are out of bounds are saturated at + /// the minimum or maximum respectively. `NaN` gets turned into a `Duration` + /// of 0 seconds. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::saturating_seconds_f32(0.5), 0.5.seconds()); + /// assert_eq!(Duration::saturating_seconds_f32(-0.5), (-0.5).seconds()); + /// assert_eq!( + /// Duration::saturating_seconds_f32(f32::NAN), + /// Duration::new(0, 0), + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f32(f32::NEG_INFINITY), + /// Duration::MIN, + /// ); + /// assert_eq!( + /// Duration::saturating_seconds_f32(f32::INFINITY), + /// Duration::MAX, + /// ); + /// ``` + pub fn saturating_seconds_f32(seconds: f32) -> Self { + try_from_secs!( + secs = seconds, + mantissa_bits = 23, + exponent_bits = 8, + offset = 41, + bits_ty = u32, + bits_ty_signed = i32, + double_ty = u64, + float_ty = f32, + is_nan = return Self::ZERO, + is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX }, + ) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f64`. Returns `None` if the `Duration` can't be + /// represented. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::checked_seconds_f64(0.5), Some(0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f64(-0.5), Some(-0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f64(f64::NAN), None); + /// assert_eq!(Duration::checked_seconds_f64(f64::NEG_INFINITY), None); + /// assert_eq!(Duration::checked_seconds_f64(f64::INFINITY), None); + /// ``` + pub fn checked_seconds_f64(seconds: f64) -> Option<Self> { + Some(try_from_secs!( + secs = seconds, + mantissa_bits = 52, + exponent_bits = 11, + offset = 44, + bits_ty = u64, + bits_ty_signed = i64, + double_ty = u128, + float_ty = f64, + is_nan = return None, + is_overflow = return None, + )) + } + + /// Creates a new `Duration` from the specified number of seconds + /// represented as `f32`. Returns `None` if the `Duration` can't be + /// represented. + /// + /// ```rust + /// # use time::{Duration, ext::NumericalDuration}; + /// assert_eq!(Duration::checked_seconds_f32(0.5), Some(0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f32(-0.5), Some(-0.5.seconds())); + /// assert_eq!(Duration::checked_seconds_f32(f32::NAN), None); + /// assert_eq!(Duration::checked_seconds_f32(f32::NEG_INFINITY), None); + /// assert_eq!(Duration::checked_seconds_f32(f32::INFINITY), None); + /// ``` + pub fn checked_seconds_f32(seconds: f32) -> Option<Self> { + Some(try_from_secs!( + secs = seconds, + mantissa_bits = 23, + exponent_bits = 8, + offset = 41, + bits_ty = u32, + bits_ty_signed = i32, + double_ty = u64, + float_ty = f32, + is_nan = return None, + is_overflow = return None, + )) } /// Create a new `Duration` with the given number of milliseconds. @@ -361,8 +612,9 @@ impl Duration { /// ``` pub const fn milliseconds(milliseconds: i64) -> Self { Self::new_unchecked( - milliseconds / 1_000, - ((milliseconds % 1_000) * 1_000_000) as _, + milliseconds / Millisecond.per(Second) as i64, + (milliseconds % Millisecond.per(Second) as i64 * Nanosecond.per(Millisecond) as i64) + as _, ) } @@ -375,8 +627,9 @@ impl Duration { /// ``` pub const fn microseconds(microseconds: i64) -> Self { Self::new_unchecked( - microseconds / 1_000_000, - ((microseconds % 1_000_000) * 1_000) as _, + microseconds / Microsecond.per(Second) as i64, + (microseconds % Microsecond.per(Second) as i64 * Nanosecond.per(Microsecond) as i64) + as _, ) } @@ -389,8 +642,8 @@ impl Duration { /// ``` pub const fn nanoseconds(nanoseconds: i64) -> Self { Self::new_unchecked( - nanoseconds / 1_000_000_000, - (nanoseconds % 1_000_000_000) as _, + nanoseconds / Nanosecond.per(Second) as i64, + (nanoseconds % Nanosecond.per(Second) as i64) as _, ) } @@ -399,8 +652,8 @@ impl Duration { /// As the input range cannot be fully mapped to the output, this should only be used where it's /// known to result in a valid value. pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self { - let seconds = nanoseconds / 1_000_000_000; - let nanoseconds = nanoseconds % 1_000_000_000; + let seconds = nanoseconds / Nanosecond.per(Second) as i128; + let nanoseconds = nanoseconds % Nanosecond.per(Second) as i128; if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 { crate::expect_failed("overflow constructing `time::Duration`"); @@ -421,7 +674,7 @@ impl Duration { /// assert_eq!((-6).days().whole_weeks(), 0); /// ``` pub const fn whole_weeks(self) -> i64 { - self.whole_seconds() / 604_800 + self.whole_seconds() / Second.per(Week) as i64 } /// Get the number of whole days in the duration. @@ -434,7 +687,7 @@ impl Duration { /// assert_eq!((-23).hours().whole_days(), 0); /// ``` pub const fn whole_days(self) -> i64 { - self.whole_seconds() / 86_400 + self.whole_seconds() / Second.per(Day) as i64 } /// Get the number of whole hours in the duration. @@ -447,7 +700,7 @@ impl Duration { /// assert_eq!((-59).minutes().whole_hours(), 0); /// ``` pub const fn whole_hours(self) -> i64 { - self.whole_seconds() / 3_600 + self.whole_seconds() / Second.per(Hour) as i64 } /// Get the number of whole minutes in the duration. @@ -460,7 +713,7 @@ impl Duration { /// assert_eq!((-59).seconds().whole_minutes(), 0); /// ``` pub const fn whole_minutes(self) -> i64 { - self.whole_seconds() / 60 + self.whole_seconds() / Second.per(Minute) as i64 } /// Get the number of whole seconds in the duration. @@ -484,7 +737,7 @@ impl Duration { /// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5); /// ``` pub fn as_seconds_f64(self) -> f64 { - self.seconds as f64 + self.nanoseconds as f64 / 1_000_000_000. + self.seconds as f64 + self.nanoseconds as f64 / Nanosecond.per(Second) as f64 } /// Get the number of fractional seconds in the duration. @@ -495,7 +748,7 @@ impl Duration { /// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5); /// ``` pub fn as_seconds_f32(self) -> f32 { - self.seconds as f32 + self.nanoseconds as f32 / 1_000_000_000. + self.seconds as f32 + self.nanoseconds as f32 / Nanosecond.per(Second) as f32 } /// Get the number of whole milliseconds in the duration. @@ -508,7 +761,8 @@ impl Duration { /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1); /// ``` pub const fn whole_milliseconds(self) -> i128 { - self.seconds as i128 * 1_000 + self.nanoseconds as i128 / 1_000_000 + self.seconds as i128 * Millisecond.per(Second) as i128 + + self.nanoseconds as i128 / Nanosecond.per(Millisecond) as i128 } /// Get the number of milliseconds past the number of whole seconds. @@ -522,7 +776,7 @@ impl Duration { /// ``` // Allow the lint, as the value is guaranteed to be less than 1000. pub const fn subsec_milliseconds(self) -> i16 { - (self.nanoseconds / 1_000_000) as _ + (self.nanoseconds / Nanosecond.per(Millisecond) as i32) as _ } /// Get the number of whole microseconds in the duration. @@ -535,7 +789,8 @@ impl Duration { /// assert_eq!((-1).microseconds().whole_microseconds(), -1); /// ``` pub const fn whole_microseconds(self) -> i128 { - self.seconds as i128 * 1_000_000 + self.nanoseconds as i128 / 1_000 + self.seconds as i128 * Microsecond.per(Second) as i128 + + self.nanoseconds as i128 / Nanosecond.per(Microsecond) as i128 } /// Get the number of microseconds past the number of whole seconds. @@ -548,7 +803,7 @@ impl Duration { /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400); /// ``` pub const fn subsec_microseconds(self) -> i32 { - self.nanoseconds / 1_000 + self.nanoseconds / Nanosecond.per(Microsecond) as i32 } /// Get the number of nanoseconds in the duration. @@ -561,7 +816,7 @@ impl Duration { /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1); /// ``` pub const fn whole_nanoseconds(self) -> i128 { - self.seconds as i128 * 1_000_000_000 + self.nanoseconds as i128 + self.seconds as i128 * Nanosecond.per(Second) as i128 + self.nanoseconds as i128 } /// Get the number of nanoseconds past the number of whole seconds. @@ -591,11 +846,12 @@ impl Duration { let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds)); let mut nanoseconds = self.nanoseconds + rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 { + nanoseconds -= Nanosecond.per(Second) as i32; seconds = const_try_opt!(seconds.checked_add(1)); - } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = const_try_opt!(seconds.checked_sub(1)); } @@ -614,11 +870,12 @@ impl Duration { let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds)); let mut nanoseconds = self.nanoseconds - rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 { + nanoseconds -= Nanosecond.per(Second) as i32; seconds = const_try_opt!(seconds.checked_add(1)); - } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = const_try_opt!(seconds.checked_sub(1)); } @@ -638,8 +895,8 @@ impl Duration { pub const fn checked_mul(self, rhs: i32) -> Option<Self> { // Multiply nanoseconds as i64, because it cannot overflow that way. let total_nanos = self.nanoseconds as i64 * rhs as i64; - let extra_secs = total_nanos / 1_000_000_000; - let nanoseconds = (total_nanos % 1_000_000_000) as _; + let extra_secs = total_nanos / Nanosecond.per(Second) as i64; + let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _; let seconds = const_try_opt!( const_try_opt!(self.seconds.checked_mul(rhs as _)).checked_add(extra_secs) ); @@ -658,7 +915,8 @@ impl Duration { pub const fn checked_div(self, rhs: i32) -> Option<Self> { let seconds = const_try_opt!(self.seconds.checked_div(rhs as i64)); let carry = self.seconds - seconds * (rhs as i64); - let extra_nanos = const_try_opt!((carry * 1_000_000_000).checked_div(rhs as i64)); + let extra_nanos = + const_try_opt!((carry * Nanosecond.per(Second) as i64).checked_div(rhs as i64)); let nanoseconds = const_try_opt!(self.nanoseconds.checked_div(rhs)) + (extra_nanos as i32); Some(Self::new_unchecked(seconds, nanoseconds)) @@ -688,14 +946,15 @@ impl Duration { } let mut nanoseconds = self.nanoseconds + rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 { + nanoseconds -= Nanosecond.per(Second) as i32; seconds = match seconds.checked_add(1) { Some(seconds) => seconds, None => return Self::MAX, }; - } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = match seconds.checked_sub(1) { Some(seconds) => seconds, None => return Self::MIN, @@ -727,14 +986,15 @@ impl Duration { } let mut nanoseconds = self.nanoseconds - rhs.nanoseconds; - if nanoseconds >= 1_000_000_000 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= 1_000_000_000; + if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 { + nanoseconds -= Nanosecond.per(Second) as i32; seconds = match seconds.checked_add(1) { Some(seconds) => seconds, None => return Self::MAX, }; - } else if nanoseconds <= -1_000_000_000 || seconds > 0 && nanoseconds < 0 { - nanoseconds += 1_000_000_000; + } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0 + { + nanoseconds += Nanosecond.per(Second) as i32; seconds = match seconds.checked_sub(1) { Some(seconds) => seconds, None => return Self::MIN, @@ -759,8 +1019,8 @@ impl Duration { pub const fn saturating_mul(self, rhs: i32) -> Self { // Multiply nanoseconds as i64, because it cannot overflow that way. let total_nanos = self.nanoseconds as i64 * rhs as i64; - let extra_secs = total_nanos / 1_000_000_000; - let nanoseconds = (total_nanos % 1_000_000_000) as _; + let extra_secs = total_nanos / Nanosecond.per(Second) as i64; + let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _; let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as _); if overflow1 { if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 { @@ -834,13 +1094,13 @@ impl fmt::Display for Duration { // Even if this produces a de-normal float, because we're rounding we don't really care. let seconds = self.unsigned_abs().as_secs_f64(); - item!("d", seconds / 86_400.); - item!("h", seconds / 3_600.); - item!("m", seconds / 60.); + item!("d", seconds / Second.per(Day) as f64); + item!("h", seconds / Second.per(Hour) as f64); + item!("m", seconds / Second.per(Minute) as f64); item!("s", seconds); - item!("ms", seconds * 1_000.); - item!("µs", seconds * 1_000_000.); - item!("ns", seconds * 1_000_000_000.); + item!("ms", seconds * Millisecond.per(Second) as f64); + item!("µs", seconds * Microsecond.per(Second) as f64); + item!("ns", seconds * Nanosecond.per(Second) as f64); } else { // Precise, but verbose representation. @@ -861,13 +1121,23 @@ impl fmt::Display for Duration { let seconds = self.seconds.unsigned_abs(); let nanoseconds = self.nanoseconds.unsigned_abs(); - item!("d", seconds / 86_400)?; - item!("h", seconds / 3_600 % 24)?; - item!("m", seconds / 60 % 60)?; - item!("s", seconds % 60)?; - item!("ms", nanoseconds / 1_000_000)?; - item!("µs", nanoseconds / 1_000 % 1_000)?; - item!("ns", nanoseconds % 1_000)?; + item!("d", seconds / Second.per(Day) as u64)?; + item!( + "h", + seconds / Second.per(Hour) as u64 % Hour.per(Day) as u64 + )?; + item!( + "m", + seconds / Second.per(Minute) as u64 % Minute.per(Hour) as u64 + )?; + item!("s", seconds % Second.per(Minute) as u64)?; + item!("ms", nanoseconds / Nanosecond.per(Millisecond))?; + item!( + "µs", + nanoseconds / Nanosecond.per(Microsecond) as u32 + % Microsecond.per(Millisecond) as u32 + )?; + item!("ns", nanoseconds % Nanosecond.per(Microsecond) as u32)?; } Ok(()) |