Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functions Duration::try_from_secs_{f32, f64} #82179

Merged
merged 2 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions library/core/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,44 @@ impl Duration {
}
}

/// 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]
joshtriplett marked this conversation as resolved.
Show resolved Hide resolved
pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
mbartlett21 marked this conversation as resolved.
Show resolved Hide resolved
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::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,
})
}
}

/// Creates a new `Duration` from the specified number of seconds represented
/// as `f32`.
///
Expand Down Expand Up @@ -732,6 +770,44 @@ 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 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::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,
})
}
}

/// Multiplies `Duration` by `f64`.
///
/// # Panics
Expand Down Expand Up @@ -1081,3 +1157,55 @@ impl fmt::Debug for Duration {
}
}
}

/// 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 {
joshtriplett marked this conversation as resolved.
Show resolved Hide resolved
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,
}
3 changes: 3 additions & 0 deletions library/std/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,9 @@ impl Error for char::ParseCharError {
#[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`
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@
#![feature(doc_masked)]
#![feature(doc_spotlight)]
#![feature(dropck_eyepatch)]
#![feature(duration_checked_float)]
#![feature(duration_constants)]
#![feature(duration_zero)]
#![feature(exact_size_is_empty)]
Expand Down