未验证 提交 1e14d397 编写于 作者: Y Yuki Okushi 提交者: GitHub

Rollup merge of #82179 - mbartlett21:patch-5, r=joshtriplett

Add functions `Duration::try_from_secs_{f32, f64}`

These functions allow constructing a Duration from a floating point value that could be out of range without panicking.

Tracking issue: #83400
......@@ -687,21 +687,47 @@ pub const fn as_secs_f32(&self) -> f32 {
#[inline]
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
pub const fn from_secs_f64(secs: f64) -> Duration {
match Duration::try_from_secs_f64(secs) {
Ok(v) => v,
Err(e) => crate::panicking::panic(e.description()),
}
}
/// 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() {
panic!("got non-finite value when converting float to duration");
}
if nanos >= MAX_NANOS_F64 {
panic!("overflow when converting float to duration");
}
if nanos < 0.0 {
panic!("underflow when converting float to duration");
}
let nanos = nanos as u128;
Duration {
secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
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::Underflow })
} 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,
})
}
}
......@@ -722,21 +748,47 @@ pub const fn from_secs_f64(secs: f64) -> Duration {
#[inline]
#[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
pub const fn from_secs_f32(secs: f32) -> Duration {
match Duration::try_from_secs_f32(secs) {
Ok(v) => v,
Err(e) => crate::panicking::panic(e.description()),
}
}
/// 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() {
panic!("got non-finite value when converting float to duration");
}
if nanos >= MAX_NANOS_F32 {
panic!("overflow when converting float to duration");
}
if nanos < 0.0 {
panic!("underflow when converting float to duration");
}
let nanos = nanos as u128;
Duration {
secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
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::Underflow })
} 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,
})
}
}
......@@ -1099,3 +1151,55 @@ fn fmt_decimal(
}
}
}
/// An error which can be returned when converting a floating-point value of seconds
/// into a [`Duration`].
///
/// This error is used as the error type for [`Duration::try_from_secs_f32`] and
/// [`Duration::try_from_secs_f64`].
///
/// # Example
///
/// ```
/// #![feature(duration_checked_float)]
///
/// use std::time::Duration;
///
/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
/// println!("Failed conversion to Duration: {}", e);
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[unstable(feature = "duration_checked_float", issue = "83400")]
pub struct FromSecsError {
kind: FromSecsErrorKind,
}
impl FromSecsError {
const fn description(&self) -> &'static str {
match self.kind {
FromSecsErrorKind::NonFinite => {
"got non-finite value when converting float to duration"
}
FromSecsErrorKind::Overflow => "overflow when converting float to duration",
FromSecsErrorKind::Underflow => "underflow when converting float to duration",
}
}
}
#[unstable(feature = "duration_checked_float", issue = "83400")]
impl fmt::Display for FromSecsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.description(), f)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum FromSecsErrorKind {
// Value is not a finite value (either infinity or NaN).
NonFinite,
// Value is too large to store in a `Duration`.
Overflow,
// Value is less than `0.0`.
Underflow,
}
......@@ -597,6 +597,9 @@ fn description(&self) -> &str {
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl Error for alloc::collections::TryReserveError {}
#[unstable(feature = "duration_checked_float", issue = "83400")]
impl Error for core::time::FromSecsError {}
// Copied from `any.rs`.
impl dyn Error + 'static {
/// Returns `true` if the boxed type is the same as `T`
......
......@@ -261,6 +261,7 @@
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
#![feature(dropck_eyepatch)]
#![feature(duration_checked_float)]
#![feature(duration_constants)]
#![feature(edition_panic)]
#![feature(exact_size_is_empty)]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册