diff options
Diffstat (limited to 'vendor/time/src/duration.rs')
| -rw-r--r-- | vendor/time/src/duration.rs | 1598 |
1 files changed, 0 insertions, 1598 deletions
diff --git a/vendor/time/src/duration.rs b/vendor/time/src/duration.rs deleted file mode 100644 index b86bfe7c..00000000 --- a/vendor/time/src/duration.rs +++ /dev/null @@ -1,1598 +0,0 @@ -//! The [`Duration`] struct and its associated `impl`s. - -use core::cmp::Ordering; -use core::fmt; -use core::iter::Sum; -use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign}; -use core::time::Duration as StdDuration; -#[cfg(feature = "std")] -use std::time::SystemTime; - -use deranged::RangedI32; -use num_conv::prelude::*; - -use crate::convert::*; -use crate::error; -use crate::internal_macros::{ - const_try_opt, expect_opt, impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign, -}; -#[cfg(feature = "std")] -#[allow(deprecated)] -use crate::Instant; - -/// By explicitly inserting this enum where padding is expected, the compiler is able to better -/// perform niche value optimization. -#[repr(u32)] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub(crate) enum Padding { - #[allow(clippy::missing_docs_in_private_items)] - Optimize, -} - -/// The type of the `nanosecond` field of `Duration`. -type Nanoseconds = - RangedI32<{ -(Nanosecond::per(Second) as i32 - 1) }, { Nanosecond::per(Second) as i32 - 1 }>; - -/// A span of time with nanosecond precision. -/// -/// Each `Duration` is composed of a whole number of seconds and a fractional part represented in -/// nanoseconds. -/// -/// This implementation allows for negative durations, unlike [`core::time::Duration`]. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Duration { - /// Number of whole seconds. - seconds: i64, - /// Number of nanoseconds within the second. The sign always matches the `seconds` field. - // Sign must match that of `seconds` (though this is not a safety requirement). - nanoseconds: Nanoseconds, - padding: Padding, -} - -impl fmt::Debug for Duration { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Duration") - .field("seconds", &self.seconds) - .field("nanoseconds", &self.nanoseconds) - .finish() - } -} - -impl Default for Duration { - fn default() -> Self { - Self { - seconds: 0, - nanoseconds: Nanoseconds::new_static::<0>(), - padding: Padding::Optimize, - } - } -} - -/// This is adapted from the [`std` implementation][std], which uses mostly bit -/// operations to ensure the highest precision: -/// -/// Changes from `std` are marked and explained below. -/// -/// [std]: https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340 -#[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_ranged_unchecked(i64::MIN, Nanoseconds::new_static::<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); - // Safety: `nanos_signed` is in range. - unsafe { Self::new_unchecked(secs_signed, nanos_signed) } - } - }}; -} - -impl Duration { - /// Equivalent to `0.seconds()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::ZERO, 0.seconds()); - /// ``` - pub const ZERO: Self = Self::seconds(0); - - /// Equivalent to `1.nanoseconds()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::NANOSECOND, 1.nanoseconds()); - /// ``` - pub const NANOSECOND: Self = Self::nanoseconds(1); - - /// Equivalent to `1.microseconds()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::MICROSECOND, 1.microseconds()); - /// ``` - pub const MICROSECOND: Self = Self::microseconds(1); - - /// Equivalent to `1.milliseconds()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::MILLISECOND, 1.milliseconds()); - /// ``` - pub const MILLISECOND: Self = Self::milliseconds(1); - - /// Equivalent to `1.seconds()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::SECOND, 1.seconds()); - /// ``` - pub const SECOND: Self = Self::seconds(1); - - /// Equivalent to `1.minutes()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::MINUTE, 1.minutes()); - /// ``` - pub const MINUTE: Self = Self::minutes(1); - - /// Equivalent to `1.hours()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::HOUR, 1.hours()); - /// ``` - pub const HOUR: Self = Self::hours(1); - - /// Equivalent to `1.days()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::DAY, 1.days()); - /// ``` - pub const DAY: Self = Self::days(1); - - /// Equivalent to `1.weeks()`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::WEEK, 1.weeks()); - /// ``` - 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_ranged(i64::MIN, Nanoseconds::MIN); - - /// The maximum possible duration. Adding any positive duration to this will cause an overflow. - pub const MAX: Self = Self::new_ranged(i64::MAX, Nanoseconds::MAX); - - /// Check if a duration is exactly zero. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert!(0.seconds().is_zero()); - /// assert!(!1.nanoseconds().is_zero()); - /// ``` - pub const fn is_zero(self) -> bool { - self.seconds == 0 && self.nanoseconds.get() == 0 - } - - /// Check if a duration is negative. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert!((-1).seconds().is_negative()); - /// assert!(!0.seconds().is_negative()); - /// assert!(!1.seconds().is_negative()); - /// ``` - pub const fn is_negative(self) -> bool { - self.seconds < 0 || self.nanoseconds.get() < 0 - } - - /// Check if a duration is positive. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert!(1.seconds().is_positive()); - /// assert!(!0.seconds().is_positive()); - /// assert!(!(-1).seconds().is_positive()); - /// ``` - pub const fn is_positive(self) -> bool { - self.seconds > 0 || self.nanoseconds.get() > 0 - } - - /// Get the absolute value of the duration. - /// - /// This method saturates the returned value if it would otherwise overflow. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.seconds().abs(), 1.seconds()); - /// assert_eq!(0.seconds().abs(), 0.seconds()); - /// assert_eq!((-1).seconds().abs(), 1.seconds()); - /// ``` - pub const fn abs(self) -> Self { - match self.seconds.checked_abs() { - Some(seconds) => Self::new_ranged_unchecked(seconds, self.nanoseconds.abs()), - None => Self::MAX, - } - } - - /// Convert the existing `Duration` to a `std::time::Duration` and its sign. This returns a - /// [`std::time::Duration`] and does not saturate the returned value (unlike [`Duration::abs`]). - /// - /// ```rust - /// # use time::ext::{NumericalDuration, NumericalStdDuration}; - /// assert_eq!(1.seconds().unsigned_abs(), 1.std_seconds()); - /// assert_eq!(0.seconds().unsigned_abs(), 0.std_seconds()); - /// assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds()); - /// ``` - pub const fn unsigned_abs(self) -> StdDuration { - StdDuration::new( - self.seconds.unsigned_abs(), - self.nanoseconds.get().unsigned_abs(), - ) - } - - /// Create a new `Duration` without checking the validity of the components. - /// - /// # Safety - /// - /// - `nanoseconds` must be in the range `-999_999_999..=999_999_999`. - /// - /// While the sign of `nanoseconds` is required to be the same as the sign of `seconds`, this is - /// not a safety invariant. - pub(crate) const unsafe fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self { - Self::new_ranged_unchecked( - seconds, - // Safety: The caller must uphold the safety invariants. - unsafe { Nanoseconds::new_unchecked(nanoseconds) }, - ) - } - - /// Create a new `Duration` without checking the validity of the components. - pub(crate) const fn new_ranged_unchecked(seconds: i64, nanoseconds: Nanoseconds) -> Self { - if seconds < 0 { - debug_assert!(nanoseconds.get() <= 0); - } else if seconds > 0 { - debug_assert!(nanoseconds.get() >= 0); - } - - Self { - seconds, - nanoseconds, - padding: Padding::Optimize, - } - } - - /// Create a new `Duration` with the provided seconds and nanoseconds. If nanoseconds is at - /// least ±10<sup>9</sup>, it will wrap to the number of seconds. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::new(1, 0), 1.seconds()); - /// assert_eq!(Duration::new(-1, 0), (-1).seconds()); - /// assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds()); - /// ``` - /// - /// # Panics - /// - /// This may panic if an overflow occurs. - pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self { - seconds = expect_opt!( - seconds.checked_add(nanoseconds as i64 / Nanosecond::per(Second) as i64), - "overflow constructing `time::Duration`" - ); - nanoseconds %= Nanosecond::per(Second) as i32; - - if seconds > 0 && nanoseconds < 0 { - // `seconds` cannot overflow here because it is positive. - seconds -= 1; - nanoseconds += Nanosecond::per(Second) as i32; - } else if seconds < 0 && nanoseconds > 0 { - // `seconds` cannot overflow here because it is negative. - seconds += 1; - nanoseconds -= Nanosecond::per(Second) as i32; - } - - // Safety: `nanoseconds` is in range due to the modulus above. - unsafe { Self::new_unchecked(seconds, nanoseconds) } - } - - /// Create a new `Duration` with the provided seconds and nanoseconds. - pub(crate) const fn new_ranged(mut seconds: i64, mut nanoseconds: Nanoseconds) -> Self { - if seconds > 0 && nanoseconds.get() < 0 { - // `seconds` cannot overflow here because it is positive. - seconds -= 1; - // Safety: `nanoseconds` is negative with a maximum of 999,999,999, so adding a billion - // to it is guaranteed to result in an in-range value. - nanoseconds = unsafe { - Nanoseconds::new_unchecked(nanoseconds.get() + Nanosecond::per(Second) as i32) - }; - } else if seconds < 0 && nanoseconds.get() > 0 { - // `seconds` cannot overflow here because it is negative. - seconds += 1; - // Safety: `nanoseconds` is positive with a minimum of -999,999,999, so subtracting a - // billion from it is guaranteed to result in an in-range value. - nanoseconds = unsafe { - Nanoseconds::new_unchecked(nanoseconds.get() - Nanosecond::per(Second) as i32) - }; - } - - Self::new_ranged_unchecked(seconds, nanoseconds) - } - - /// Create a new `Duration` with the given number of weeks. Equivalent to - /// `Duration::seconds(weeks * 604_800)`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::weeks(1), 604_800.seconds()); - /// ``` - /// - /// # Panics - /// - /// This may panic if an overflow occurs. - pub const fn weeks(weeks: i64) -> Self { - Self::seconds(expect_opt!( - weeks.checked_mul(Second::per(Week) as i64), - "overflow constructing `time::Duration`" - )) - } - - /// Create a new `Duration` with the given number of days. Equivalent to - /// `Duration::seconds(days * 86_400)`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::days(1), 86_400.seconds()); - /// ``` - /// - /// # Panics - /// - /// This may panic if an overflow occurs. - pub const fn days(days: i64) -> Self { - Self::seconds(expect_opt!( - days.checked_mul(Second::per(Day) as i64), - "overflow constructing `time::Duration`" - )) - } - - /// Create a new `Duration` with the given number of hours. Equivalent to - /// `Duration::seconds(hours * 3_600)`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::hours(1), 3_600.seconds()); - /// ``` - /// - /// # Panics - /// - /// This may panic if an overflow occurs. - pub const fn hours(hours: i64) -> Self { - Self::seconds(expect_opt!( - hours.checked_mul(Second::per(Hour) as i64), - "overflow constructing `time::Duration`" - )) - } - - /// Create a new `Duration` with the given number of minutes. Equivalent to - /// `Duration::seconds(minutes * 60)`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::minutes(1), 60.seconds()); - /// ``` - /// - /// # Panics - /// - /// This may panic if an overflow occurs. - pub const fn minutes(minutes: i64) -> Self { - Self::seconds(expect_opt!( - minutes.checked_mul(Second::per(Minute) as i64), - "overflow constructing `time::Duration`" - )) - } - - /// Create a new `Duration` with the given number of seconds. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::seconds(1), 1_000.milliseconds()); - /// ``` - pub const fn seconds(seconds: i64) -> Self { - Self::new_ranged_unchecked(seconds, Nanoseconds::new_static::<0>()) - } - - /// Creates a new `Duration` from the specified number of seconds represented as `f64`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::seconds_f64(0.5), 0.5.seconds()); - /// assert_eq!(Duration::seconds_f64(-0.5), (-0.5).seconds()); - /// ``` - pub fn 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 = 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`. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::seconds_f32(0.5), 0.5.seconds()); - /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds()); - /// ``` - pub fn 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 = 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. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::milliseconds(1), 1_000.microseconds()); - /// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds()); - /// ``` - pub const fn milliseconds(milliseconds: i64) -> Self { - // Safety: `nanoseconds` is guaranteed to be in range because of the modulus. - unsafe { - Self::new_unchecked( - milliseconds / Millisecond::per(Second) as i64, - (milliseconds % Millisecond::per(Second) as i64 - * Nanosecond::per(Millisecond) as i64) as i32, - ) - } - } - - /// Create a new `Duration` with the given number of microseconds. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::microseconds(1), 1_000.nanoseconds()); - /// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds()); - /// ``` - pub const fn microseconds(microseconds: i64) -> Self { - // Safety: `nanoseconds` is guaranteed to be in range because of the modulus. - unsafe { - Self::new_unchecked( - microseconds / Microsecond::per(Second) as i64, - (microseconds % Microsecond::per(Second) as i64 - * Nanosecond::per(Microsecond) as i64) as i32, - ) - } - } - - /// Create a new `Duration` with the given number of nanoseconds. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(Duration::nanoseconds(1), 1.microseconds() / 1_000); - /// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000); - /// ``` - pub const fn nanoseconds(nanoseconds: i64) -> Self { - // Safety: `nanoseconds` is guaranteed to be in range because of the modulus. - unsafe { - Self::new_unchecked( - nanoseconds / Nanosecond::per(Second) as i64, - (nanoseconds % Nanosecond::per(Second) as i64) as i32, - ) - } - } - - /// Create a new `Duration` with the given number of nanoseconds. - /// - /// 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 / 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`"); - } - - // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above. - unsafe { Self::new_unchecked(seconds as i64, nanoseconds as i32) } - } - - /// Get the number of whole weeks in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.weeks().whole_weeks(), 1); - /// assert_eq!((-1).weeks().whole_weeks(), -1); - /// assert_eq!(6.days().whole_weeks(), 0); - /// assert_eq!((-6).days().whole_weeks(), 0); - /// ``` - pub const fn whole_weeks(self) -> i64 { - self.whole_seconds() / Second::per(Week) as i64 - } - - /// Get the number of whole days in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.days().whole_days(), 1); - /// assert_eq!((-1).days().whole_days(), -1); - /// assert_eq!(23.hours().whole_days(), 0); - /// assert_eq!((-23).hours().whole_days(), 0); - /// ``` - pub const fn whole_days(self) -> i64 { - self.whole_seconds() / Second::per(Day) as i64 - } - - /// Get the number of whole hours in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.hours().whole_hours(), 1); - /// assert_eq!((-1).hours().whole_hours(), -1); - /// assert_eq!(59.minutes().whole_hours(), 0); - /// assert_eq!((-59).minutes().whole_hours(), 0); - /// ``` - pub const fn whole_hours(self) -> i64 { - self.whole_seconds() / Second::per(Hour) as i64 - } - - /// Get the number of whole minutes in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.minutes().whole_minutes(), 1); - /// assert_eq!((-1).minutes().whole_minutes(), -1); - /// assert_eq!(59.seconds().whole_minutes(), 0); - /// assert_eq!((-59).seconds().whole_minutes(), 0); - /// ``` - pub const fn whole_minutes(self) -> i64 { - self.whole_seconds() / Second::per(Minute) as i64 - } - - /// Get the number of whole seconds in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.seconds().whole_seconds(), 1); - /// assert_eq!((-1).seconds().whole_seconds(), -1); - /// assert_eq!(1.minutes().whole_seconds(), 60); - /// assert_eq!((-1).minutes().whole_seconds(), -60); - /// ``` - pub const fn whole_seconds(self) -> i64 { - self.seconds - } - - /// Get the number of fractional seconds in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.5.seconds().as_seconds_f64(), 1.5); - /// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5); - /// ``` - pub fn as_seconds_f64(self) -> f64 { - self.seconds as f64 + self.nanoseconds.get() as f64 / Nanosecond::per(Second) as f64 - } - - /// Get the number of fractional seconds in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.5.seconds().as_seconds_f32(), 1.5); - /// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5); - /// ``` - pub fn as_seconds_f32(self) -> f32 { - self.seconds as f32 + self.nanoseconds.get() as f32 / Nanosecond::per(Second) as f32 - } - - /// Get the number of whole milliseconds in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.seconds().whole_milliseconds(), 1_000); - /// assert_eq!((-1).seconds().whole_milliseconds(), -1_000); - /// assert_eq!(1.milliseconds().whole_milliseconds(), 1); - /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1); - /// ``` - pub const fn whole_milliseconds(self) -> i128 { - self.seconds as i128 * Millisecond::per(Second) as i128 - + self.nanoseconds.get() as i128 / Nanosecond::per(Millisecond) as i128 - } - - /// Get the number of milliseconds past the number of whole seconds. - /// - /// Always in the range `-999..=999`. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.4.seconds().subsec_milliseconds(), 400); - /// assert_eq!((-1.4).seconds().subsec_milliseconds(), -400); - /// ``` - // Allow the lint, as the value is guaranteed to be less than 1000. - pub const fn subsec_milliseconds(self) -> i16 { - (self.nanoseconds.get() / Nanosecond::per(Millisecond) as i32) as i16 - } - - /// Get the number of whole microseconds in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.milliseconds().whole_microseconds(), 1_000); - /// assert_eq!((-1).milliseconds().whole_microseconds(), -1_000); - /// assert_eq!(1.microseconds().whole_microseconds(), 1); - /// assert_eq!((-1).microseconds().whole_microseconds(), -1); - /// ``` - pub const fn whole_microseconds(self) -> i128 { - self.seconds as i128 * Microsecond::per(Second) as i128 - + self.nanoseconds.get() as i128 / Nanosecond::per(Microsecond) as i128 - } - - /// Get the number of microseconds past the number of whole seconds. - /// - /// Always in the range `-999_999..=999_999`. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.0004.seconds().subsec_microseconds(), 400); - /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400); - /// ``` - pub const fn subsec_microseconds(self) -> i32 { - self.nanoseconds.get() / Nanosecond::per(Microsecond) as i32 - } - - /// Get the number of nanoseconds in the duration. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.microseconds().whole_nanoseconds(), 1_000); - /// assert_eq!((-1).microseconds().whole_nanoseconds(), -1_000); - /// assert_eq!(1.nanoseconds().whole_nanoseconds(), 1); - /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1); - /// ``` - pub const fn whole_nanoseconds(self) -> i128 { - self.seconds as i128 * Nanosecond::per(Second) as i128 + self.nanoseconds.get() as i128 - } - - /// Get the number of nanoseconds past the number of whole seconds. - /// - /// The returned value will always be in the range `-999_999_999..=999_999_999`. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(1.000_000_400.seconds().subsec_nanoseconds(), 400); - /// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400); - /// ``` - pub const fn subsec_nanoseconds(self) -> i32 { - self.nanoseconds.get() - } - - /// Get the number of nanoseconds past the number of whole seconds. - #[cfg(feature = "quickcheck")] - pub(crate) const fn subsec_nanoseconds_ranged(self) -> Nanoseconds { - self.nanoseconds - } - - /// Computes `self + rhs`, returning `None` if an overflow occurred. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(5.seconds().checked_add(5.seconds()), Some(10.seconds())); - /// assert_eq!(Duration::MAX.checked_add(1.nanoseconds()), None); - /// assert_eq!((-5).seconds().checked_add(5.seconds()), Some(0.seconds())); - /// ``` - pub const fn checked_add(self, rhs: Self) -> Option<Self> { - let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds)); - let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get(); - - if nanoseconds >= Nanosecond::per(Second) as i32 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= Nanosecond::per(Second) as i32; - seconds = const_try_opt!(seconds.checked_add(1)); - } 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)); - } - - // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling. - unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) } - } - - /// Computes `self - rhs`, returning `None` if an overflow occurred. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(5.seconds().checked_sub(5.seconds()), Some(Duration::ZERO)); - /// assert_eq!(Duration::MIN.checked_sub(1.nanoseconds()), None); - /// assert_eq!(5.seconds().checked_sub(10.seconds()), Some((-5).seconds())); - /// ``` - pub const fn checked_sub(self, rhs: Self) -> Option<Self> { - let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds)); - let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get(); - - if nanoseconds >= Nanosecond::per(Second) as i32 || seconds < 0 && nanoseconds > 0 { - nanoseconds -= Nanosecond::per(Second) as i32; - seconds = const_try_opt!(seconds.checked_add(1)); - } 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)); - } - - // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling. - unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) } - } - - /// Computes `self * rhs`, returning `None` if an overflow occurred. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(5.seconds().checked_mul(2), Some(10.seconds())); - /// assert_eq!(5.seconds().checked_mul(-2), Some((-10).seconds())); - /// assert_eq!(5.seconds().checked_mul(0), Some(0.seconds())); - /// assert_eq!(Duration::MAX.checked_mul(2), None); - /// assert_eq!(Duration::MIN.checked_mul(2), None); - /// ``` - 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.get() as i64 * rhs as i64; - let extra_secs = total_nanos / Nanosecond::per(Second) as i64; - let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as i32; - let seconds = const_try_opt!( - const_try_opt!(self.seconds.checked_mul(rhs as i64)).checked_add(extra_secs) - ); - - // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above. - unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) } - } - - /// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// assert_eq!(10.seconds().checked_div(2), Some(5.seconds())); - /// assert_eq!(10.seconds().checked_div(-2), Some((-5).seconds())); - /// assert_eq!(1.seconds().checked_div(0), None); - /// ``` - pub const fn checked_div(self, rhs: i32) -> Option<Self> { - let (secs, extra_secs) = ( - const_try_opt!(self.seconds.checked_div(rhs as i64)), - self.seconds % (rhs as i64), - ); - let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs); - nanos += ((extra_secs * (Nanosecond::per(Second) as i64) + extra_nanos as i64) - / (rhs as i64)) as i32; - - // Safety: `nanoseconds` is in range. - unsafe { Some(Self::new_unchecked(secs, nanos)) } - } - - /// Computes `-self`, returning `None` if the result would overflow. - /// - /// ```rust - /// # use time::ext::NumericalDuration; - /// # use time::Duration; - /// assert_eq!(5.seconds().checked_neg(), Some((-5).seconds())); - /// assert_eq!(Duration::MIN.checked_neg(), None); - /// ``` - pub const fn checked_neg(self) -> Option<Self> { - if self.seconds == i64::MIN { - None - } else { - Some(Self::new_ranged_unchecked( - -self.seconds, - self.nanoseconds.neg(), - )) - } - } - - /// Computes `self + rhs`, saturating if an overflow occurred. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds()); - /// assert_eq!(Duration::MAX.saturating_add(1.nanoseconds()), Duration::MAX); - /// assert_eq!( - /// Duration::MIN.saturating_add((-1).nanoseconds()), - /// Duration::MIN - /// ); - /// assert_eq!((-5).seconds().saturating_add(5.seconds()), Duration::ZERO); - /// ``` - pub const fn saturating_add(self, rhs: Self) -> Self { - let (mut seconds, overflow) = self.seconds.overflowing_add(rhs.seconds); - if overflow { - if self.seconds > 0 { - return Self::MAX; - } - return Self::MIN; - } - let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get(); - - if nanoseconds >= Nanosecond::per(Second) as i32 || 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 <= -(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, - }; - } - - // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling. - unsafe { Self::new_unchecked(seconds, nanoseconds) } - } - - /// Computes `self - rhs`, saturating if an overflow occurred. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(5.seconds().saturating_sub(5.seconds()), Duration::ZERO); - /// assert_eq!(Duration::MIN.saturating_sub(1.nanoseconds()), Duration::MIN); - /// assert_eq!( - /// Duration::MAX.saturating_sub((-1).nanoseconds()), - /// Duration::MAX - /// ); - /// assert_eq!(5.seconds().saturating_sub(10.seconds()), (-5).seconds()); - /// ``` - pub const fn saturating_sub(self, rhs: Self) -> Self { - let (mut seconds, overflow) = self.seconds.overflowing_sub(rhs.seconds); - if overflow { - if self.seconds > 0 { - return Self::MAX; - } - return Self::MIN; - } - let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get(); - - if nanoseconds >= Nanosecond::per(Second) as i32 || 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 <= -(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, - }; - } - - // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling. - unsafe { Self::new_unchecked(seconds, nanoseconds) } - } - - /// Computes `self * rhs`, saturating if an overflow occurred. - /// - /// ```rust - /// # use time::{Duration, ext::NumericalDuration}; - /// assert_eq!(5.seconds().saturating_mul(2), 10.seconds()); - /// assert_eq!(5.seconds().saturating_mul(-2), (-10).seconds()); - /// assert_eq!(5.seconds().saturating_mul(0), Duration::ZERO); - /// assert_eq!(Duration::MAX.saturating_mul(2), Duration::MAX); - /// assert_eq!(Duration::MIN.saturating_mul(2), Duration::MIN); - /// assert_eq!(Duration::MAX.saturating_mul(-2), Duration::MIN); - /// assert_eq!(Duration::MIN.saturating_mul(-2), Duration::MAX); - /// ``` - pub const fn saturating_mul(self, rhs: i32) -> Self { - // Multiply nanoseconds as i64, because it cannot overflow that way. - let total_nanos = self.nanoseconds.get() as i64 * rhs as i64; - let extra_secs = total_nanos / Nanosecond::per(Second) as i64; - let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as i32; - let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as i64); - if overflow1 { - if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 { - return Self::MAX; - } - return Self::MIN; - } - let (seconds, overflow2) = seconds.overflowing_add(extra_secs); - if overflow2 { - if self.seconds > 0 && rhs > 0 { - return Self::MAX; - } - return Self::MIN; - } - - // Safety: `nanoseconds` is guaranteed to be in range because of to the modulus above. - unsafe { Self::new_unchecked(seconds, nanoseconds) } - } - - /// Runs a closure, returning the duration of time it took to run. The return value of the - /// closure is provided in the second part of the tuple. - #[doc(hidden)] - #[cfg(feature = "std")] - #[deprecated( - since = "0.3.32", - note = "extremely limited use case, not intended for benchmarking" - )] - #[allow(deprecated)] - pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) { - let start = Instant::now(); - let return_value = f(); - let end = Instant::now(); - - (end - start, return_value) - } -} - -/// The format returned by this implementation is not stable and must not be relied upon. -/// -/// By default this produces an exact, full-precision printout of the duration. -/// For a concise, rounded printout instead, you can use the `.N` format specifier: -/// -/// ``` -/// # use time::Duration; -/// # -/// let duration = Duration::new(123456, 789011223); -/// println!("{duration:.3}"); -/// ``` -/// -/// For the purposes of this implementation, a day is exactly 24 hours and a minute is exactly 60 -/// seconds. -impl fmt::Display for Duration { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_negative() { - f.write_str("-")?; - } - - if let Some(_precision) = f.precision() { - // Concise, rounded representation. - - if self.is_zero() { - // Write a zero value with the requested precision. - return (0.).fmt(f).and_then(|_| f.write_str("s")); - } - - /// Format the first item that produces a value greater than 1 and then break. - macro_rules! item { - ($name:literal, $value:expr) => { - let value = $value; - if value >= 1.0 { - return value.fmt(f).and_then(|_| f.write_str($name)); - } - }; - } - - // 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 / 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 * 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. - - if self.is_zero() { - return f.write_str("0s"); - } - - /// Format a single item. - macro_rules! item { - ($name:literal, $value:expr) => { - match $value { - 0 => Ok(()), - value => value.fmt(f).and_then(|_| f.write_str($name)), - } - }; - } - - let seconds = self.seconds.unsigned_abs(); - let nanoseconds = self.nanoseconds.get().unsigned_abs(); - - item!("d", seconds / Second::per(Day).extend::<u64>())?; - item!( - "h", - seconds / Second::per(Hour).extend::<u64>() % Hour::per(Day).extend::<u64>() - )?; - item!( - "m", - seconds / Second::per(Minute).extend::<u64>() % Minute::per(Hour).extend::<u64>() - )?; - item!("s", seconds % Second::per(Minute).extend::<u64>())?; - item!("ms", nanoseconds / Nanosecond::per(Millisecond))?; - item!( - "µs", - nanoseconds / Nanosecond::per(Microsecond).extend::<u32>() - % Microsecond::per(Millisecond).extend::<u32>() - )?; - item!( - "ns", - nanoseconds % Nanosecond::per(Microsecond).extend::<u32>() - )?; - } - - Ok(()) - } -} - -impl TryFrom<StdDuration> for Duration { - type Error = error::ConversionRange; - - fn try_from(original: StdDuration) -> Result<Self, error::ConversionRange> { - Ok(Self::new( - original - .as_secs() - .try_into() - .map_err(|_| error::ConversionRange)?, - original.subsec_nanos().cast_signed(), - )) - } -} - -impl TryFrom<Duration> for StdDuration { - type Error = error::ConversionRange; - - fn try_from(duration: Duration) -> Result<Self, error::ConversionRange> { - Ok(Self::new( - duration - .seconds - .try_into() - .map_err(|_| error::ConversionRange)?, - duration - .nanoseconds - .get() - .try_into() - .map_err(|_| error::ConversionRange)?, - )) - } -} - -impl Add for Duration { - type Output = Self; - - /// # Panics - /// - /// This may panic if an overflow occurs. - fn add(self, rhs: Self) -> Self::Output { - self.checked_add(rhs) - .expect("overflow when adding durations") - } -} - -impl Add<StdDuration> for Duration { - type Output = Self; - - /// # Panics - /// - /// This may panic if an overflow occurs. - fn add(self, std_duration: StdDuration) -> Self::Output { - self + Self::try_from(std_duration) - .expect("overflow converting `std::time::Duration` to `time::Duration`") - } -} - -impl Add<Duration> for StdDuration { - type Output = Duration; - - fn add(self, rhs: Duration) -> Self::Output { - rhs + self - } -} - -impl_add_assign!(Duration: Self, StdDuration); - -impl AddAssign<Duration> for StdDuration { - /// # Panics - /// - /// This may panic if the resulting addition cannot be represented. - fn add_assign(&mut self, rhs: Duration) { - *self = (*self + rhs).try_into().expect( - "Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \ - change the type.", - ); - } -} - -impl Neg for Duration { - type Output = Self; - - fn neg(self) -> Self::Output { - self.checked_neg().expect("overflow when negating duration") - } -} - -impl Sub for Duration { - type Output = Self; - - /// # Panics - /// - /// This may panic if an overflow occurs. - fn sub(self, rhs: Self) -> Self::Output { - self.checked_sub(rhs) - .expect("overflow when subtracting durations") - } -} - -impl Sub<StdDuration> for Duration { - type Output = Self; - - /// # Panics - /// - /// This may panic if an overflow occurs. - fn sub(self, rhs: StdDuration) -> Self::Output { - self - Self::try_from(rhs) - .expect("overflow converting `std::time::Duration` to `time::Duration`") - } -} - -impl Sub<Duration> for StdDuration { - type Output = Duration; - - /// # Panics - /// - /// This may panic if an overflow occurs. - fn sub(self, rhs: Duration) -> Self::Output { - Duration::try_from(self) - .expect("overflow converting `std::time::Duration` to `time::Duration`") - - rhs - } -} - -impl_sub_assign!(Duration: Self, StdDuration); - -impl SubAssign<Duration> for StdDuration { - /// # Panics - /// - /// This may panic if the resulting subtraction can not be represented. - fn sub_assign(&mut self, rhs: Duration) { - *self = (*self - rhs).try_into().expect( - "Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \ - change the type.", - ); - } -} - -/// Implement `Mul` (reflexively) and `Div` for `Duration` for various types. -macro_rules! duration_mul_div_int { - ($($type:ty),+) => {$( - impl Mul<$type> for Duration { - type Output = Self; - - fn mul(self, rhs: $type) -> Self::Output { - Self::nanoseconds_i128( - self.whole_nanoseconds() - .checked_mul(rhs.cast_signed().extend::<i128>()) - .expect("overflow when multiplying duration") - ) - } - } - - impl Mul<Duration> for $type { - type Output = Duration; - - fn mul(self, rhs: Duration) -> Self::Output { - rhs * self - } - } - - impl Div<$type> for Duration { - type Output = Self; - - fn div(self, rhs: $type) -> Self::Output { - Self::nanoseconds_i128( - self.whole_nanoseconds() / rhs.cast_signed().extend::<i128>() - ) - } - } - )+}; -} -duration_mul_div_int![i8, i16, i32, u8, u16, u32]; - -impl Mul<f32> for Duration { - type Output = Self; - - fn mul(self, rhs: f32) -> Self::Output { - Self::seconds_f32(self.as_seconds_f32() * rhs) - } -} - -impl Mul<Duration> for f32 { - type Output = Duration; - - fn mul(self, rhs: Duration) -> Self::Output { - rhs * self - } -} - -impl Mul<f64> for Duration { - type Output = Self; - - fn mul(self, rhs: f64) -> Self::Output { - Self::seconds_f64(self.as_seconds_f64() * rhs) - } -} - -impl Mul<Duration> for f64 { - type Output = Duration; - - fn mul(self, rhs: Duration) -> Self::Output { - rhs * self - } -} - -impl_mul_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64); - -impl Div<f32> for Duration { - type Output = Self; - - fn div(self, rhs: f32) -> Self::Output { - Self::seconds_f32(self.as_seconds_f32() / rhs) - } -} - -impl Div<f64> for Duration { - type Output = Self; - - fn div(self, rhs: f64) -> Self::Output { - Self::seconds_f64(self.as_seconds_f64() / rhs) - } -} - -impl_div_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64); - -impl Div for Duration { - type Output = f64; - - fn div(self, rhs: Self) -> Self::Output { - self.as_seconds_f64() / rhs.as_seconds_f64() - } -} - -impl Div<StdDuration> for Duration { - type Output = f64; - - fn div(self, rhs: StdDuration) -> Self::Output { - self.as_seconds_f64() / rhs.as_secs_f64() - } -} - -impl Div<Duration> for StdDuration { - type Output = f64; - - fn div(self, rhs: Duration) -> Self::Output { - self.as_secs_f64() / rhs.as_seconds_f64() - } -} - -impl PartialEq<StdDuration> for Duration { - fn eq(&self, rhs: &StdDuration) -> bool { - Ok(*self) == Self::try_from(*rhs) - } -} - -impl PartialEq<Duration> for StdDuration { - fn eq(&self, rhs: &Duration) -> bool { - rhs == self - } -} - -impl PartialOrd<StdDuration> for Duration { - fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> { - if rhs.as_secs() > i64::MAX.cast_unsigned() { - return Some(Ordering::Less); - } - - Some( - self.seconds - .cmp(&rhs.as_secs().cast_signed()) - .then_with(|| { - self.nanoseconds - .get() - .cmp(&rhs.subsec_nanos().cast_signed()) - }), - ) - } -} - -impl PartialOrd<Duration> for StdDuration { - fn partial_cmp(&self, rhs: &Duration) -> Option<Ordering> { - rhs.partial_cmp(self).map(Ordering::reverse) - } -} - -impl Sum for Duration { - fn sum<I: Iterator<Item = Self>>(iter: I) -> Self { - iter.reduce(|a, b| a + b).unwrap_or_default() - } -} - -impl<'a> Sum<&'a Self> for Duration { - fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self { - iter.copied().sum() - } -} - -#[cfg(feature = "std")] -impl Add<Duration> for SystemTime { - type Output = Self; - - fn add(self, duration: Duration) -> Self::Output { - if duration.is_zero() { - self - } else if duration.is_positive() { - self + duration.unsigned_abs() - } else { - debug_assert!(duration.is_negative()); - self - duration.unsigned_abs() - } - } -} - -impl_add_assign!(SystemTime: #[cfg(feature = "std")] Duration); - -#[cfg(feature = "std")] -impl Sub<Duration> for SystemTime { - type Output = Self; - - fn sub(self, duration: Duration) -> Self::Output { - if duration.is_zero() { - self - } else if duration.is_positive() { - self - duration.unsigned_abs() - } else { - debug_assert!(duration.is_negative()); - self + duration.unsigned_abs() - } - } -} - -impl_sub_assign!(SystemTime: #[cfg(feature = "std")] Duration); |
