/// as `f64`.
///
/// # Panics
- /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+ /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// use std::time::Duration;
///
- /// let dur = Duration::from_secs_f64(2.7);
- /// assert_eq!(dur, Duration::new(2, 700_000_000));
+ /// let res = Duration::from_secs_f64(0.0);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f64(1e-20);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f64(4.2e-7);
+ /// assert_eq!(res, Duration::new(0, 420));
+ /// let res = Duration::from_secs_f64(2.7);
+ /// assert_eq!(res, Duration::new(2, 700_000_000));
+ /// let res = Duration::from_secs_f64(3e10);
+ /// assert_eq!(res, Duration::new(30_000_000_000, 0));
+ /// // subnormal float
+ /// let res = Duration::from_secs_f64(f64::from_bits(1));
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::from_secs_f64(0.999e-9);
+ /// assert_eq!(res, Duration::new(0, 0));
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
}
}
- /// The checked version of [`from_secs_f64`].
- ///
- /// [`from_secs_f64`]: Duration::from_secs_f64
- ///
- /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
- ///
- /// # Examples
- /// ```
- /// #![feature(duration_checked_float)]
- /// use std::time::Duration;
- ///
- /// let dur = Duration::try_from_secs_f64(2.7);
- /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
- ///
- /// let negative = Duration::try_from_secs_f64(-5.0);
- /// assert!(negative.is_err());
- /// ```
- #[unstable(feature = "duration_checked_float", issue = "83400")]
- #[inline]
- pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
- const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
- let nanos = secs * (NANOS_PER_SEC as f64);
- if !nanos.is_finite() {
- Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
- } else if nanos >= MAX_NANOS_F64 {
- Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
- } else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Negative })
- } else {
- let nanos = nanos as u128;
- Ok(Duration {
- secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
- nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
- })
- }
- }
-
/// Creates a new `Duration` from the specified number of seconds represented
/// as `f32`.
///
/// # Panics
- /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+ /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// use std::time::Duration;
///
- /// let dur = Duration::from_secs_f32(2.7);
- /// assert_eq!(dur, Duration::new(2, 700_000_000));
+ /// let res = Duration::from_secs_f32(0.0);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f32(1e-20);
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// let res = Duration::from_secs_f32(4.2e-7);
+ /// assert_eq!(res, Duration::new(0, 419));
+ /// let res = Duration::from_secs_f32(2.7);
+ /// assert_eq!(res, Duration::new(2, 700_000_047));
+ /// let res = Duration::from_secs_f32(3e10);
+ /// assert_eq!(res, Duration::new(30_000_001_024, 0));
+ /// // subnormal float
+ /// let res = Duration::from_secs_f32(f32::from_bits(1));
+ /// assert_eq!(res, Duration::new(0, 0));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::from_secs_f32(0.999e-9);
+ /// assert_eq!(res, Duration::new(0, 0));
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use]
}
}
- /// The checked version of [`from_secs_f32`].
- ///
- /// [`from_secs_f32`]: Duration::from_secs_f32
- ///
- /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
- ///
- /// # Examples
- /// ```
- /// #![feature(duration_checked_float)]
- /// use std::time::Duration;
- ///
- /// let dur = Duration::try_from_secs_f32(2.7);
- /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
- ///
- /// let negative = Duration::try_from_secs_f32(-5.0);
- /// assert!(negative.is_err());
- /// ```
- #[unstable(feature = "duration_checked_float", issue = "83400")]
- #[inline]
- pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
- const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
- let nanos = secs * (NANOS_PER_SEC as f32);
- if !nanos.is_finite() {
- Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
- } else if nanos >= MAX_NANOS_F32 {
- Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
- } else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Negative })
- } else {
- let nanos = nanos as u128;
- Ok(Duration {
- secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
- nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
- })
- }
- }
-
/// Multiplies `Duration` by `f64`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// Multiplies `Duration` by `f32`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// use std::time::Duration;
///
/// let dur = Duration::new(2, 700_000_000);
- /// // note that due to rounding errors result is slightly different
- /// // from 8.478 and 847800.0
/// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
- /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256));
+ /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0));
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[must_use = "this returns the result of the operation, \
/// Divide `Duration` by `f64`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// Divide `Duration` by `f32`.
///
/// # Panics
- /// This method will panic if result is not finite, negative or overflows `Duration`.
+ /// This method will panic if result is negative, overflows `Duration` or not finite.
///
/// # Examples
/// ```
/// let dur = Duration::new(2, 700_000_000);
/// // note that due to rounding errors result is slightly
/// // different from 0.859_872_611
- /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576));
+ /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_579));
/// // note that truncation is used, not rounding
/// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
/// ```
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[unstable(feature = "duration_checked_float", issue = "83400")]
-pub struct FromSecsError {
- kind: FromSecsErrorKind,
+pub struct FromFloatSecsError {
+ kind: FromFloatSecsErrorKind,
}
-impl FromSecsError {
+impl FromFloatSecsError {
const fn description(&self) -> &'static str {
match self.kind {
- FromSecsErrorKind::NonFinite => "non-finite value when converting float to duration",
- FromSecsErrorKind::Overflow => "overflow when converting float to duration",
- FromSecsErrorKind::Negative => "negative value when converting float to duration",
+ FromFloatSecsErrorKind::Negative => {
+ "can not convert float seconds to Duration: value is negative"
+ }
+ FromFloatSecsErrorKind::OverflowOrNan => {
+ "can not convert float seconds to Duration: value is either too big or NaN"
+ }
}
}
}
#[unstable(feature = "duration_checked_float", issue = "83400")]
-impl fmt::Display for FromSecsError {
+impl fmt::Display for FromFloatSecsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(self.description(), f)
+ self.description().fmt(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
-enum FromSecsErrorKind {
- // Value is not a finite value (either + or - infinity or NaN).
- NonFinite,
- // Value is too large to store in a `Duration`.
- Overflow,
+enum FromFloatSecsErrorKind {
// Value is negative.
Negative,
+ // Value is either too big to be represented as `Duration` or `NaN`.
+ OverflowOrNan,
+}
+
+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,
+ double_ty = $double_ty:ty,
+ ) => {{
+ 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;
+
+ if $secs.is_sign_negative() {
+ return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::Negative });
+ }
+
+ 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 < -30 {
+ // the input represents less than 1ns.
+ (0u64, 0u32)
+ } else if exp < 0 {
+ // the input is less than 1 second
+ let t = <$double_ty>::from(mant) << ($offset + exp);
+ let nanos = (u128::from(NANOS_PER_SEC) * u128::from(t)) >> ($mant_bits + $offset);
+ (0, nanos as u32)
+ } else if exp < $mant_bits {
+ let secs = mant >> ($mant_bits - exp);
+ let t = <$double_ty>::from((mant << exp) & MANT_MASK);
+ let nanos = (<$double_ty>::from(NANOS_PER_SEC) * t) >> $mant_bits;
+ (u64::from(secs), nanos as u32)
+ } else if exp < 64 {
+ // the input has no fractional part
+ let secs = u64::from(mant) << (exp - $mant_bits);
+ (secs, 0)
+ } else {
+ return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::OverflowOrNan });
+ };
+
+ Ok(Duration { secs, nanos })
+ }};
+}
+
+impl Duration {
+ /// The checked version of [`from_secs_f32`].
+ ///
+ /// [`from_secs_f32`]: Duration::from_secs_f32
+ ///
+ /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_checked_float)]
+ ///
+ /// use std::time::Duration;
+ ///
+ /// let res = Duration::try_from_secs_f32(0.0);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f32(1e-20);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f32(4.2e-7);
+ /// assert_eq!(res, Ok(Duration::new(0, 419)));
+ /// let res = Duration::try_from_secs_f32(2.7);
+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_047)));
+ /// let res = Duration::try_from_secs_f32(3e10);
+ /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0)));
+ /// // subnormal float:
+ /// let res = Duration::try_from_secs_f32(f32::from_bits(1));
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::try_from_secs_f32(0.999e-9);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ ///
+ /// let res = Duration::try_from_secs_f32(-5.0);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f32(f32::NAN);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f32(2e19);
+ /// assert!(res.is_err());
+ /// ```
+ #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[inline]
+ pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromFloatSecsError> {
+ try_from_secs!(
+ secs = secs,
+ mantissa_bits = 23,
+ exponent_bits = 8,
+ offset = 41,
+ bits_ty = u32,
+ double_ty = u64,
+ )
+ }
+
+ /// The checked version of [`from_secs_f64`].
+ ///
+ /// [`from_secs_f64`]: Duration::from_secs_f64
+ ///
+ /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_checked_float)]
+ ///
+ /// use std::time::Duration;
+ ///
+ /// let res = Duration::try_from_secs_f64(0.0);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f64(1e-20);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// let res = Duration::try_from_secs_f64(4.2e-7);
+ /// assert_eq!(res, Ok(Duration::new(0, 420)));
+ /// let res = Duration::try_from_secs_f64(2.7);
+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_000)));
+ /// let res = Duration::try_from_secs_f64(3e10);
+ /// assert_eq!(res, Ok(Duration::new(30_000_000_000, 0)));
+ /// // subnormal float
+ /// let res = Duration::try_from_secs_f64(f64::from_bits(1));
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ /// // conversion uses truncation, not rounding
+ /// let res = Duration::try_from_secs_f32(0.999e-9);
+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
+ ///
+ /// let res = Duration::try_from_secs_f64(-5.0);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f64(f64::NAN);
+ /// assert!(res.is_err());
+ /// let res = Duration::try_from_secs_f64(2e19);
+ /// assert!(res.is_err());
+ /// ```
+ #[unstable(feature = "duration_checked_float", issue = "83400")]
+ #[inline]
+ pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromFloatSecsError> {
+ try_from_secs!(
+ secs = secs,
+ mantissa_bits = 52,
+ exponent_bits = 11,
+ offset = 44,
+ bits_ty = u64,
+ double_ty = u128,
+ )
+ }
}