Skip to content

Commit c2c1ca0

Browse files
committed
Add functions Duration::try_from_secs_{f32, f64}
This also adds the error type used, `FromSecsError` and its `impl`s.
1 parent 26c2d1f commit c2c1ca0

File tree

3 files changed

+132
-0
lines changed

3 files changed

+132
-0
lines changed

library/core/src/time.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,44 @@ impl Duration {
697697
}
698698
}
699699

700+
/// The checked version of [`from_secs_f64`].
701+
///
702+
/// [`from_secs_f64`]: Duration::from_secs_f64
703+
///
704+
/// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
705+
///
706+
/// # Examples
707+
/// ```
708+
/// #![feature(duration_checked_float)]
709+
///
710+
/// use std::time::Duration;
711+
///
712+
/// let dur = Duration::try_from_secs_f64(2.7);
713+
/// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
714+
///
715+
/// let negative = Duration::try_from_secs_f64(-5.0);
716+
/// assert!(negative.is_err());
717+
/// ```
718+
#[unstable(feature = "duration_checked_float", issue = "83400")]
719+
#[inline]
720+
pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
721+
const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
722+
let nanos = secs * (NANOS_PER_SEC as f64);
723+
if !nanos.is_finite() {
724+
Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
725+
} else if nanos >= MAX_NANOS_F64 {
726+
Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
727+
} else if nanos < 0.0 {
728+
Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
729+
} else {
730+
let nanos = nanos as u128;
731+
Ok(Duration {
732+
secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
733+
nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
734+
})
735+
}
736+
}
737+
700738
/// Creates a new `Duration` from the specified number of seconds represented
701739
/// as `f32`.
702740
///
@@ -732,6 +770,44 @@ impl Duration {
732770
}
733771
}
734772

773+
/// The checked version of [`from_secs_f32`].
774+
///
775+
/// [`from_secs_f32`]: Duration::from_secs_f32
776+
///
777+
/// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
778+
///
779+
/// # Examples
780+
/// ```
781+
/// #![feature(duration_checked_float)]
782+
///
783+
/// use std::time::Duration;
784+
///
785+
/// let dur = Duration::try_from_secs_f32(2.7);
786+
/// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
787+
///
788+
/// let negative = Duration::try_from_secs_f32(-5.0);
789+
/// assert!(negative.is_err());
790+
/// ```
791+
#[unstable(feature = "duration_checked_float", issue = "83400")]
792+
#[inline]
793+
pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
794+
const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
795+
let nanos = secs * (NANOS_PER_SEC as f32);
796+
if !nanos.is_finite() {
797+
Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
798+
} else if nanos >= MAX_NANOS_F32 {
799+
Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
800+
} else if nanos < 0.0 {
801+
Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
802+
} else {
803+
let nanos = nanos as u128;
804+
Ok(Duration {
805+
secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
806+
nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
807+
})
808+
}
809+
}
810+
735811
/// Multiplies `Duration` by `f64`.
736812
///
737813
/// # Panics
@@ -1081,3 +1157,55 @@ impl fmt::Debug for Duration {
10811157
}
10821158
}
10831159
}
1160+
1161+
/// An error which can be returned when converting a floating-point value of seconds
1162+
/// into a [`Duration`].
1163+
///
1164+
/// This error is used as the error type for [`Duration::try_from_secs_f32`] and
1165+
/// [`Duration::try_from_secs_f64`].
1166+
///
1167+
/// # Example
1168+
///
1169+
/// ```
1170+
/// #![feature(duration_checked_float)]
1171+
///
1172+
/// use std::time::Duration;
1173+
///
1174+
/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
1175+
/// println!("Failed conversion to Duration: {}", e);
1176+
/// }
1177+
/// ```
1178+
#[derive(Debug, Clone, PartialEq, Eq)]
1179+
#[unstable(feature = "duration_checked_float", issue = "83400")]
1180+
pub struct FromSecsError {
1181+
kind: FromSecsErrorKind,
1182+
}
1183+
1184+
impl FromSecsError {
1185+
const fn description(&self) -> &'static str {
1186+
match self.kind {
1187+
FromSecsErrorKind::NonFinite => {
1188+
"got non-finite value when converting float to duration"
1189+
}
1190+
FromSecsErrorKind::Overflow => "overflow when converting float to duration",
1191+
FromSecsErrorKind::Underflow => "underflow when converting float to duration",
1192+
}
1193+
}
1194+
}
1195+
1196+
#[unstable(feature = "duration_checked_float", issue = "83400")]
1197+
impl fmt::Display for FromSecsError {
1198+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1199+
fmt::Display::fmt(self.description(), f)
1200+
}
1201+
}
1202+
1203+
#[derive(Debug, Clone, PartialEq, Eq)]
1204+
enum FromSecsErrorKind {
1205+
// Value is not a finite value (either infinity or NaN).
1206+
NonFinite,
1207+
// Value is too large to store in a `Duration`.
1208+
Overflow,
1209+
// Value is less than `0.0`.
1210+
Underflow,
1211+
}

library/std/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,9 @@ impl Error for char::ParseCharError {
529529
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
530530
impl Error for alloc::collections::TryReserveError {}
531531

532+
#[unstable(feature = "duration_checked_float", issue = "83400")]
533+
impl Error for core::time::FromSecsError {}
534+
532535
// Copied from `any.rs`.
533536
impl dyn Error + 'static {
534537
/// Returns `true` if the boxed type is the same as `T`

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@
256256
#![feature(doc_masked)]
257257
#![feature(doc_spotlight)]
258258
#![feature(dropck_eyepatch)]
259+
#![feature(duration_checked_float)]
259260
#![feature(duration_constants)]
260261
#![feature(duration_zero)]
261262
#![feature(exact_size_is_empty)]

0 commit comments

Comments
 (0)