@@ -687,21 +687,47 @@ impl Duration {
687687 #[ inline]
688688 #[ rustc_const_unstable( feature = "duration_consts_2" , issue = "72440" ) ]
689689 pub const fn from_secs_f64 ( secs : f64 ) -> Duration {
690+ match Duration :: try_from_secs_f64 ( secs) {
691+ Ok ( v) => v,
692+ Err ( e) => crate :: panicking:: panic ( e. description ( ) ) ,
693+ }
694+ }
695+
696+ /// The checked version of [`from_secs_f64`].
697+ ///
698+ /// [`from_secs_f64`]: Duration::from_secs_f64
699+ ///
700+ /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
701+ ///
702+ /// # Examples
703+ /// ```
704+ /// #![feature(duration_checked_float)]
705+ ///
706+ /// use std::time::Duration;
707+ ///
708+ /// let dur = Duration::try_from_secs_f64(2.7);
709+ /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
710+ ///
711+ /// let negative = Duration::try_from_secs_f64(-5.0);
712+ /// assert!(negative.is_err());
713+ /// ```
714+ #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
715+ #[ inline]
716+ pub const fn try_from_secs_f64 ( secs : f64 ) -> Result < Duration , FromSecsError > {
690717 const MAX_NANOS_F64 : f64 = ( ( u64:: MAX as u128 + 1 ) * ( NANOS_PER_SEC as u128 ) ) as f64 ;
691718 let nanos = secs * ( NANOS_PER_SEC as f64 ) ;
692719 if !nanos. is_finite ( ) {
693- panic ! ( "got non-finite value when converting float to duration" ) ;
694- }
695- if nanos >= MAX_NANOS_F64 {
696- panic ! ( "overflow when converting float to duration" ) ;
697- }
698- if nanos < 0.0 {
699- panic ! ( "underflow when converting float to duration" ) ;
700- }
701- let nanos = nanos as u128 ;
702- Duration {
703- secs : ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
704- nanos : ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
720+ Err ( FromSecsError { kind : FromSecsErrorKind :: NonFinite } )
721+ } else if nanos >= MAX_NANOS_F64 {
722+ Err ( FromSecsError { kind : FromSecsErrorKind :: Overflow } )
723+ } else if nanos < 0.0 {
724+ Err ( FromSecsError { kind : FromSecsErrorKind :: Underflow } )
725+ } else {
726+ let nanos = nanos as u128 ;
727+ Ok ( Duration {
728+ secs : ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
729+ nanos : ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
730+ } )
705731 }
706732 }
707733
@@ -722,21 +748,47 @@ impl Duration {
722748 #[ inline]
723749 #[ rustc_const_unstable( feature = "duration_consts_2" , issue = "72440" ) ]
724750 pub const fn from_secs_f32 ( secs : f32 ) -> Duration {
751+ match Duration :: try_from_secs_f32 ( secs) {
752+ Ok ( v) => v,
753+ Err ( e) => crate :: panicking:: panic ( e. description ( ) ) ,
754+ }
755+ }
756+
757+ /// The checked version of [`from_secs_f32`].
758+ ///
759+ /// [`from_secs_f32`]: Duration::from_secs_f32
760+ ///
761+ /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
762+ ///
763+ /// # Examples
764+ /// ```
765+ /// #![feature(duration_checked_float)]
766+ ///
767+ /// use std::time::Duration;
768+ ///
769+ /// let dur = Duration::try_from_secs_f32(2.7);
770+ /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
771+ ///
772+ /// let negative = Duration::try_from_secs_f32(-5.0);
773+ /// assert!(negative.is_err());
774+ /// ```
775+ #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
776+ #[ inline]
777+ pub const fn try_from_secs_f32 ( secs : f32 ) -> Result < Duration , FromSecsError > {
725778 const MAX_NANOS_F32 : f32 = ( ( u64:: MAX as u128 + 1 ) * ( NANOS_PER_SEC as u128 ) ) as f32 ;
726779 let nanos = secs * ( NANOS_PER_SEC as f32 ) ;
727780 if !nanos. is_finite ( ) {
728- panic ! ( "got non-finite value when converting float to duration" ) ;
729- }
730- if nanos >= MAX_NANOS_F32 {
731- panic ! ( "overflow when converting float to duration" ) ;
732- }
733- if nanos < 0.0 {
734- panic ! ( "underflow when converting float to duration" ) ;
735- }
736- let nanos = nanos as u128 ;
737- Duration {
738- secs : ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
739- nanos : ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
781+ Err ( FromSecsError { kind : FromSecsErrorKind :: NonFinite } )
782+ } else if nanos >= MAX_NANOS_F32 {
783+ Err ( FromSecsError { kind : FromSecsErrorKind :: Overflow } )
784+ } else if nanos < 0.0 {
785+ Err ( FromSecsError { kind : FromSecsErrorKind :: Underflow } )
786+ } else {
787+ let nanos = nanos as u128 ;
788+ Ok ( Duration {
789+ secs : ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
790+ nanos : ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
791+ } )
740792 }
741793 }
742794
@@ -1099,3 +1151,55 @@ impl fmt::Debug for Duration {
10991151 }
11001152 }
11011153}
1154+
1155+ /// An error which can be returned when converting a floating-point value of seconds
1156+ /// into a [`Duration`].
1157+ ///
1158+ /// This error is used as the error type for [`Duration::try_from_secs_f32`] and
1159+ /// [`Duration::try_from_secs_f64`].
1160+ ///
1161+ /// # Example
1162+ ///
1163+ /// ```
1164+ /// #![feature(duration_checked_float)]
1165+ ///
1166+ /// use std::time::Duration;
1167+ ///
1168+ /// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
1169+ /// println!("Failed conversion to Duration: {}", e);
1170+ /// }
1171+ /// ```
1172+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
1173+ #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1174+ pub struct FromSecsError {
1175+ kind : FromSecsErrorKind ,
1176+ }
1177+
1178+ impl FromSecsError {
1179+ const fn description ( & self ) -> & ' static str {
1180+ match self . kind {
1181+ FromSecsErrorKind :: NonFinite => {
1182+ "got non-finite value when converting float to duration"
1183+ }
1184+ FromSecsErrorKind :: Overflow => "overflow when converting float to duration" ,
1185+ FromSecsErrorKind :: Underflow => "underflow when converting float to duration" ,
1186+ }
1187+ }
1188+ }
1189+
1190+ #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1191+ impl fmt:: Display for FromSecsError {
1192+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1193+ fmt:: Display :: fmt ( self . description ( ) , f)
1194+ }
1195+ }
1196+
1197+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
1198+ enum FromSecsErrorKind {
1199+ // Value is not a finite value (either infinity or NaN).
1200+ NonFinite ,
1201+ // Value is too large to store in a `Duration`.
1202+ Overflow ,
1203+ // Value is less than `0.0`.
1204+ Underflow ,
1205+ }
0 commit comments