@@ -711,14 +711,28 @@ impl Duration {
711
711
/// as `f64`.
712
712
///
713
713
/// # 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 .
715
715
///
716
716
/// # Examples
717
717
/// ```
718
718
/// use std::time::Duration;
719
719
///
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));
722
736
/// ```
723
737
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
724
738
#[ must_use]
@@ -731,55 +745,32 @@ impl Duration {
731
745
}
732
746
}
733
747
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
-
771
748
/// Creates a new `Duration` from the specified number of seconds represented
772
749
/// as `f32`.
773
750
///
774
751
/// # 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 .
776
753
///
777
754
/// # Examples
778
755
/// ```
779
756
/// use std::time::Duration;
780
757
///
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));
783
774
/// ```
784
775
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
785
776
#[ must_use]
@@ -792,47 +783,10 @@ impl Duration {
792
783
}
793
784
}
794
785
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
-
832
786
/// Multiplies `Duration` by `f64`.
833
787
///
834
788
/// # 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 .
836
790
///
837
791
/// # Examples
838
792
/// ```
@@ -854,17 +808,15 @@ impl Duration {
854
808
/// Multiplies `Duration` by `f32`.
855
809
///
856
810
/// # 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 .
858
812
///
859
813
/// # Examples
860
814
/// ```
861
815
/// use std::time::Duration;
862
816
///
863
817
/// 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
866
818
/// 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 ));
868
820
/// ```
869
821
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
870
822
#[ must_use = "this returns the result of the operation, \
@@ -878,7 +830,7 @@ impl Duration {
878
830
/// Divide `Duration` by `f64`.
879
831
///
880
832
/// # 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 .
882
834
///
883
835
/// # Examples
884
836
/// ```
@@ -901,7 +853,7 @@ impl Duration {
901
853
/// Divide `Duration` by `f32`.
902
854
///
903
855
/// # 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 .
905
857
///
906
858
/// # Examples
907
859
/// ```
@@ -910,7 +862,7 @@ impl Duration {
910
862
/// let dur = Duration::new(2, 700_000_000);
911
863
/// // note that due to rounding errors result is slightly
912
864
/// // 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 ));
914
866
/// // note that truncation is used, not rounding
915
867
/// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
916
868
/// ```
@@ -1267,33 +1219,180 @@ impl fmt::Debug for Duration {
1267
1219
/// ```
1268
1220
#[ derive( Debug , Clone , PartialEq , Eq ) ]
1269
1221
#[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1270
- pub struct FromSecsError {
1271
- kind : FromSecsErrorKind ,
1222
+ pub struct FromFloatSecsError {
1223
+ kind : FromFloatSecsErrorKind ,
1272
1224
}
1273
1225
1274
- impl FromSecsError {
1226
+ impl FromFloatSecsError {
1275
1227
const fn description ( & self ) -> & ' static str {
1276
1228
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
+ }
1280
1235
}
1281
1236
}
1282
1237
}
1283
1238
1284
1239
#[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1285
- impl fmt:: Display for FromSecsError {
1240
+ impl fmt:: Display for FromFloatSecsError {
1286
1241
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1287
- fmt :: Display :: fmt ( self . description ( ) , f)
1242
+ self . description ( ) . fmt ( f)
1288
1243
}
1289
1244
}
1290
1245
1291
1246
#[ 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 {
1297
1248
// Value is negative.
1298
1249
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
+ }
1299
1398
}
0 commit comments