@@ -711,14 +711,28 @@ impl Duration {
711711 /// as `f64`.
712712 ///
713713 /// # Panics
714- /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
714+ /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite .
715715 ///
716716 /// # Examples
717717 /// ```
718718 /// use std::time::Duration;
719719 ///
720- /// let dur = Duration::from_secs_f64(2.7);
721- /// assert_eq!(dur, Duration::new(2, 700_000_000));
720+ /// let res = Duration::from_secs_f64(0.0);
721+ /// assert_eq!(res, Duration::new(0, 0));
722+ /// let res = Duration::from_secs_f64(1e-20);
723+ /// assert_eq!(res, Duration::new(0, 0));
724+ /// let res = Duration::from_secs_f64(4.2e-7);
725+ /// assert_eq!(res, Duration::new(0, 420));
726+ /// let res = Duration::from_secs_f64(2.7);
727+ /// assert_eq!(res, Duration::new(2, 700_000_000));
728+ /// let res = Duration::from_secs_f64(3e10);
729+ /// assert_eq!(res, Duration::new(30_000_000_000, 0));
730+ /// // subnormal float
731+ /// let res = Duration::from_secs_f64(f64::from_bits(1));
732+ /// assert_eq!(res, Duration::new(0, 0));
733+ /// // conversion uses truncation, not rounding
734+ /// let res = Duration::from_secs_f64(0.999e-9);
735+ /// assert_eq!(res, Duration::new(0, 0));
722736 /// ```
723737 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
724738 #[ must_use]
@@ -731,55 +745,32 @@ impl Duration {
731745 }
732746 }
733747
734- /// The checked version of [`from_secs_f64`].
735- ///
736- /// [`from_secs_f64`]: Duration::from_secs_f64
737- ///
738- /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
739- ///
740- /// # Examples
741- /// ```
742- /// #![feature(duration_checked_float)]
743- /// use std::time::Duration;
744- ///
745- /// let dur = Duration::try_from_secs_f64(2.7);
746- /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
747- ///
748- /// let negative = Duration::try_from_secs_f64(-5.0);
749- /// assert!(negative.is_err());
750- /// ```
751- #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
752- #[ inline]
753- pub const fn try_from_secs_f64 ( secs : f64 ) -> Result < Duration , FromSecsError > {
754- const MAX_NANOS_F64 : f64 = ( ( u64:: MAX as u128 + 1 ) * ( NANOS_PER_SEC as u128 ) ) as f64 ;
755- let nanos = secs * ( NANOS_PER_SEC as f64 ) ;
756- if !nanos. is_finite ( ) {
757- Err ( FromSecsError { kind : FromSecsErrorKind :: NonFinite } )
758- } else if nanos >= MAX_NANOS_F64 {
759- Err ( FromSecsError { kind : FromSecsErrorKind :: Overflow } )
760- } else if nanos < 0.0 {
761- Err ( FromSecsError { kind : FromSecsErrorKind :: Negative } )
762- } else {
763- let nanos = nanos as u128 ;
764- Ok ( Duration {
765- secs : ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
766- nanos : ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
767- } )
768- }
769- }
770-
771748 /// Creates a new `Duration` from the specified number of seconds represented
772749 /// as `f32`.
773750 ///
774751 /// # Panics
775- /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
752+ /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite .
776753 ///
777754 /// # Examples
778755 /// ```
779756 /// use std::time::Duration;
780757 ///
781- /// let dur = Duration::from_secs_f32(2.7);
782- /// assert_eq!(dur, Duration::new(2, 700_000_000));
758+ /// let res = Duration::from_secs_f32(0.0);
759+ /// assert_eq!(res, Duration::new(0, 0));
760+ /// let res = Duration::from_secs_f32(1e-20);
761+ /// assert_eq!(res, Duration::new(0, 0));
762+ /// let res = Duration::from_secs_f32(4.2e-7);
763+ /// assert_eq!(res, Duration::new(0, 419));
764+ /// let res = Duration::from_secs_f32(2.7);
765+ /// assert_eq!(res, Duration::new(2, 700_000_047));
766+ /// let res = Duration::from_secs_f32(3e10);
767+ /// assert_eq!(res, Duration::new(30_000_001_024, 0));
768+ /// // subnormal float
769+ /// let res = Duration::from_secs_f32(f32::from_bits(1));
770+ /// assert_eq!(res, Duration::new(0, 0));
771+ /// // conversion uses truncation, not rounding
772+ /// let res = Duration::from_secs_f32(0.999e-9);
773+ /// assert_eq!(res, Duration::new(0, 0));
783774 /// ```
784775 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
785776 #[ must_use]
@@ -792,47 +783,10 @@ impl Duration {
792783 }
793784 }
794785
795- /// The checked version of [`from_secs_f32`].
796- ///
797- /// [`from_secs_f32`]: Duration::from_secs_f32
798- ///
799- /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
800- ///
801- /// # Examples
802- /// ```
803- /// #![feature(duration_checked_float)]
804- /// use std::time::Duration;
805- ///
806- /// let dur = Duration::try_from_secs_f32(2.7);
807- /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
808- ///
809- /// let negative = Duration::try_from_secs_f32(-5.0);
810- /// assert!(negative.is_err());
811- /// ```
812- #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
813- #[ inline]
814- pub const fn try_from_secs_f32 ( secs : f32 ) -> Result < Duration , FromSecsError > {
815- const MAX_NANOS_F32 : f32 = ( ( u64:: MAX as u128 + 1 ) * ( NANOS_PER_SEC as u128 ) ) as f32 ;
816- let nanos = secs * ( NANOS_PER_SEC as f32 ) ;
817- if !nanos. is_finite ( ) {
818- Err ( FromSecsError { kind : FromSecsErrorKind :: NonFinite } )
819- } else if nanos >= MAX_NANOS_F32 {
820- Err ( FromSecsError { kind : FromSecsErrorKind :: Overflow } )
821- } else if nanos < 0.0 {
822- Err ( FromSecsError { kind : FromSecsErrorKind :: Negative } )
823- } else {
824- let nanos = nanos as u128 ;
825- Ok ( Duration {
826- secs : ( nanos / ( NANOS_PER_SEC as u128 ) ) as u64 ,
827- nanos : ( nanos % ( NANOS_PER_SEC as u128 ) ) as u32 ,
828- } )
829- }
830- }
831-
832786 /// Multiplies `Duration` by `f64`.
833787 ///
834788 /// # Panics
835- /// This method will panic if result is not finite, negative or overflows `Duration`.
789+ /// This method will panic if result is negative, overflows `Duration` or not finite .
836790 ///
837791 /// # Examples
838792 /// ```
@@ -854,17 +808,15 @@ impl Duration {
854808 /// Multiplies `Duration` by `f32`.
855809 ///
856810 /// # Panics
857- /// This method will panic if result is not finite, negative or overflows `Duration`.
811+ /// This method will panic if result is negative, overflows `Duration` or not finite .
858812 ///
859813 /// # Examples
860814 /// ```
861815 /// use std::time::Duration;
862816 ///
863817 /// let dur = Duration::new(2, 700_000_000);
864- /// // note that due to rounding errors result is slightly different
865- /// // from 8.478 and 847800.0
866818 /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
867- /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256 ));
819+ /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0 ));
868820 /// ```
869821 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
870822 #[ must_use = "this returns the result of the operation, \
@@ -878,7 +830,7 @@ impl Duration {
878830 /// Divide `Duration` by `f64`.
879831 ///
880832 /// # Panics
881- /// This method will panic if result is not finite, negative or overflows `Duration`.
833+ /// This method will panic if result is negative, overflows `Duration` or not finite .
882834 ///
883835 /// # Examples
884836 /// ```
@@ -901,7 +853,7 @@ impl Duration {
901853 /// Divide `Duration` by `f32`.
902854 ///
903855 /// # Panics
904- /// This method will panic if result is not finite, negative or overflows `Duration`.
856+ /// This method will panic if result is negative, overflows `Duration` or not finite .
905857 ///
906858 /// # Examples
907859 /// ```
@@ -910,7 +862,7 @@ impl Duration {
910862 /// let dur = Duration::new(2, 700_000_000);
911863 /// // note that due to rounding errors result is slightly
912864 /// // different from 0.859_872_611
913- /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576 ));
865+ /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_579 ));
914866 /// // note that truncation is used, not rounding
915867 /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
916868 /// ```
@@ -1267,33 +1219,180 @@ impl fmt::Debug for Duration {
12671219/// ```
12681220#[ derive( Debug , Clone , PartialEq , Eq ) ]
12691221#[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1270- pub struct FromSecsError {
1271- kind : FromSecsErrorKind ,
1222+ pub struct FromFloatSecsError {
1223+ kind : FromFloatSecsErrorKind ,
12721224}
12731225
1274- impl FromSecsError {
1226+ impl FromFloatSecsError {
12751227 const fn description ( & self ) -> & ' static str {
12761228 match self . kind {
1277- FromSecsErrorKind :: NonFinite => "non-finite value when converting float to duration" ,
1278- FromSecsErrorKind :: Overflow => "overflow when converting float to duration" ,
1279- FromSecsErrorKind :: Negative => "negative value when converting float to duration" ,
1229+ FromFloatSecsErrorKind :: Negative => {
1230+ "can not convert float seconds to Duration: value is negative"
1231+ }
1232+ FromFloatSecsErrorKind :: OverflowOrNan => {
1233+ "can not convert float seconds to Duration: value is either too big or NaN"
1234+ }
12801235 }
12811236 }
12821237}
12831238
12841239#[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1285- impl fmt:: Display for FromSecsError {
1240+ impl fmt:: Display for FromFloatSecsError {
12861241 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1287- fmt :: Display :: fmt ( self . description ( ) , f)
1242+ self . description ( ) . fmt ( f)
12881243 }
12891244}
12901245
12911246#[ derive( Debug , Clone , PartialEq , Eq ) ]
1292- enum FromSecsErrorKind {
1293- // Value is not a finite value (either + or - infinity or NaN).
1294- NonFinite ,
1295- // Value is too large to store in a `Duration`.
1296- Overflow ,
1247+ enum FromFloatSecsErrorKind {
12971248 // Value is negative.
12981249 Negative ,
1250+ // Value is either too big to be represented as `Duration` or `NaN`.
1251+ OverflowOrNan ,
1252+ }
1253+
1254+ macro_rules! try_from_secs {
1255+ (
1256+ secs = $secs: expr,
1257+ mantissa_bits = $mant_bits: literal,
1258+ exponent_bits = $exp_bits: literal,
1259+ offset = $offset: literal,
1260+ bits_ty = $bits_ty: ty,
1261+ double_ty = $double_ty: ty,
1262+ ) => { {
1263+ const MIN_EXP : i16 = 1 - ( 1i16 << $exp_bits) / 2 ;
1264+ const MANT_MASK : $bits_ty = ( 1 << $mant_bits) - 1 ;
1265+ const EXP_MASK : $bits_ty = ( 1 << $exp_bits) - 1 ;
1266+
1267+ if $secs. is_sign_negative( ) {
1268+ return Err ( FromFloatSecsError { kind: FromFloatSecsErrorKind :: Negative } ) ;
1269+ }
1270+
1271+ let bits = $secs. to_bits( ) ;
1272+ let mant = ( bits & MANT_MASK ) | ( MANT_MASK + 1 ) ;
1273+ let exp = ( ( bits >> $mant_bits) & EXP_MASK ) as i16 + MIN_EXP ;
1274+
1275+ let ( secs, nanos) = if exp < -30 {
1276+ // the input represents less than 1ns.
1277+ ( 0u64 , 0u32 )
1278+ } else if exp < 0 {
1279+ // the input is less than 1 second
1280+ let t = <$double_ty>:: from( mant) << ( $offset + exp) ;
1281+ let nanos = ( u128 :: from( NANOS_PER_SEC ) * u128 :: from( t) ) >> ( $mant_bits + $offset) ;
1282+ ( 0 , nanos as u32 )
1283+ } else if exp < $mant_bits {
1284+ let secs = mant >> ( $mant_bits - exp) ;
1285+ let t = <$double_ty>:: from( ( mant << exp) & MANT_MASK ) ;
1286+ let nanos = ( <$double_ty>:: from( NANOS_PER_SEC ) * t) >> $mant_bits;
1287+ ( u64 :: from( secs) , nanos as u32 )
1288+ } else if exp < 64 {
1289+ // the input has no fractional part
1290+ let secs = u64 :: from( mant) << ( exp - $mant_bits) ;
1291+ ( secs, 0 )
1292+ } else {
1293+ return Err ( FromFloatSecsError { kind: FromFloatSecsErrorKind :: OverflowOrNan } ) ;
1294+ } ;
1295+
1296+ Ok ( Duration { secs, nanos } )
1297+ } } ;
1298+ }
1299+
1300+ impl Duration {
1301+ /// The checked version of [`from_secs_f32`].
1302+ ///
1303+ /// [`from_secs_f32`]: Duration::from_secs_f32
1304+ ///
1305+ /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
1306+ ///
1307+ /// # Examples
1308+ /// ```
1309+ /// #![feature(duration_checked_float)]
1310+ ///
1311+ /// use std::time::Duration;
1312+ ///
1313+ /// let res = Duration::try_from_secs_f32(0.0);
1314+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1315+ /// let res = Duration::try_from_secs_f32(1e-20);
1316+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1317+ /// let res = Duration::try_from_secs_f32(4.2e-7);
1318+ /// assert_eq!(res, Ok(Duration::new(0, 419)));
1319+ /// let res = Duration::try_from_secs_f32(2.7);
1320+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_047)));
1321+ /// let res = Duration::try_from_secs_f32(3e10);
1322+ /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0)));
1323+ /// // subnormal float:
1324+ /// let res = Duration::try_from_secs_f32(f32::from_bits(1));
1325+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1326+ /// // conversion uses truncation, not rounding
1327+ /// let res = Duration::try_from_secs_f32(0.999e-9);
1328+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1329+ ///
1330+ /// let res = Duration::try_from_secs_f32(-5.0);
1331+ /// assert!(res.is_err());
1332+ /// let res = Duration::try_from_secs_f32(f32::NAN);
1333+ /// assert!(res.is_err());
1334+ /// let res = Duration::try_from_secs_f32(2e19);
1335+ /// assert!(res.is_err());
1336+ /// ```
1337+ #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1338+ #[ inline]
1339+ pub const fn try_from_secs_f32 ( secs : f32 ) -> Result < Duration , FromFloatSecsError > {
1340+ try_from_secs ! (
1341+ secs = secs,
1342+ mantissa_bits = 23 ,
1343+ exponent_bits = 8 ,
1344+ offset = 41 ,
1345+ bits_ty = u32 ,
1346+ double_ty = u64 ,
1347+ )
1348+ }
1349+
1350+ /// The checked version of [`from_secs_f64`].
1351+ ///
1352+ /// [`from_secs_f64`]: Duration::from_secs_f64
1353+ ///
1354+ /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
1355+ ///
1356+ /// # Examples
1357+ /// ```
1358+ /// #![feature(duration_checked_float)]
1359+ ///
1360+ /// use std::time::Duration;
1361+ ///
1362+ /// let res = Duration::try_from_secs_f64(0.0);
1363+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1364+ /// let res = Duration::try_from_secs_f64(1e-20);
1365+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1366+ /// let res = Duration::try_from_secs_f64(4.2e-7);
1367+ /// assert_eq!(res, Ok(Duration::new(0, 420)));
1368+ /// let res = Duration::try_from_secs_f64(2.7);
1369+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_000)));
1370+ /// let res = Duration::try_from_secs_f64(3e10);
1371+ /// assert_eq!(res, Ok(Duration::new(30_000_000_000, 0)));
1372+ /// // subnormal float
1373+ /// let res = Duration::try_from_secs_f64(f64::from_bits(1));
1374+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1375+ /// // conversion uses truncation, not rounding
1376+ /// let res = Duration::try_from_secs_f32(0.999e-9);
1377+ /// assert_eq!(res, Ok(Duration::new(0, 0)));
1378+ ///
1379+ /// let res = Duration::try_from_secs_f64(-5.0);
1380+ /// assert!(res.is_err());
1381+ /// let res = Duration::try_from_secs_f64(f64::NAN);
1382+ /// assert!(res.is_err());
1383+ /// let res = Duration::try_from_secs_f64(2e19);
1384+ /// assert!(res.is_err());
1385+ /// ```
1386+ #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1387+ #[ inline]
1388+ pub const fn try_from_secs_f64 ( secs : f64 ) -> Result < Duration , FromFloatSecsError > {
1389+ try_from_secs ! (
1390+ secs = secs,
1391+ mantissa_bits = 52 ,
1392+ exponent_bits = 11 ,
1393+ offset = 44 ,
1394+ bits_ty = u64 ,
1395+ double_ty = u128 ,
1396+ )
1397+ }
12991398}
0 commit comments