@@ -372,6 +372,40 @@ impl TimeDelta {
372
372
TimeDelta :: new ( secs, nanos as u32 )
373
373
}
374
374
375
+ /// Multiply a `TimeDelta` with a i32, returning `None` if overflow occurred.
376
+ #[ must_use]
377
+ pub const fn checked_mul ( & self , rhs : i32 ) -> Option < TimeDelta > {
378
+ // Multiply nanoseconds as i64, because it cannot overflow that way.
379
+ let total_nanos = self . nanos as i64 * rhs as i64 ;
380
+ let ( extra_secs, nanos) = div_mod_floor_64 ( total_nanos, NANOS_PER_SEC as i64 ) ;
381
+ // Multiply seconds as i128 to prevent overflow
382
+ let secs: i128 = self . secs as i128 * rhs as i128 + extra_secs as i128 ;
383
+ if secs <= i64:: MIN as i128 || secs >= i64:: MAX as i128 {
384
+ return None ;
385
+ } ;
386
+ Some ( TimeDelta { secs : secs as i64 , nanos : nanos as i32 } )
387
+ }
388
+
389
+ /// Divide a `TimeDelta` with a i32, returning `None` if dividing by 0.
390
+ #[ must_use]
391
+ pub const fn checked_div ( & self , rhs : i32 ) -> Option < TimeDelta > {
392
+ if rhs == 0 {
393
+ return None ;
394
+ }
395
+ let secs = self . secs / rhs as i64 ;
396
+ let carry = self . secs % rhs as i64 ;
397
+ let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64 ;
398
+ let nanos = self . nanos / rhs + extra_nanos as i32 ;
399
+
400
+ let ( secs, nanos) = match nanos {
401
+ i32:: MIN ..=-1 => ( secs - 1 , nanos + NANOS_PER_SEC ) ,
402
+ NANOS_PER_SEC ..=i32:: MAX => ( secs + 1 , nanos - NANOS_PER_SEC ) ,
403
+ _ => ( secs, nanos) ,
404
+ } ;
405
+
406
+ Some ( TimeDelta { secs, nanos } )
407
+ }
408
+
375
409
/// Returns the `TimeDelta` as an absolute (non-negative) value.
376
410
#[ inline]
377
411
pub const fn abs ( & self ) -> TimeDelta {
@@ -489,31 +523,15 @@ impl Mul<i32> for TimeDelta {
489
523
type Output = TimeDelta ;
490
524
491
525
fn mul ( self , rhs : i32 ) -> TimeDelta {
492
- // Multiply nanoseconds as i64, because it cannot overflow that way.
493
- let total_nanos = self . nanos as i64 * rhs as i64 ;
494
- let ( extra_secs, nanos) = div_mod_floor_64 ( total_nanos, NANOS_PER_SEC as i64 ) ;
495
- let secs = self . secs * rhs as i64 + extra_secs;
496
- TimeDelta { secs, nanos : nanos as i32 }
526
+ self . checked_mul ( rhs) . expect ( "`TimeDelta * i32` overflowed" )
497
527
}
498
528
}
499
529
500
530
impl Div < i32 > for TimeDelta {
501
531
type Output = TimeDelta ;
502
532
503
533
fn div ( self , rhs : i32 ) -> TimeDelta {
504
- let mut secs = self . secs / rhs as i64 ;
505
- let carry = self . secs - secs * rhs as i64 ;
506
- let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64 ;
507
- let mut nanos = self . nanos / rhs + extra_nanos as i32 ;
508
- if nanos >= NANOS_PER_SEC {
509
- nanos -= NANOS_PER_SEC ;
510
- secs += 1 ;
511
- }
512
- if nanos < 0 {
513
- nanos += NANOS_PER_SEC ;
514
- secs -= 1 ;
515
- }
516
- TimeDelta { secs, nanos }
534
+ self . checked_div ( rhs) . expect ( "`i32` is zero" )
517
535
}
518
536
}
519
537
@@ -1034,6 +1052,7 @@ mod tests {
1034
1052
#[ test]
1035
1053
fn test_duration_checked_ops ( ) {
1036
1054
let milliseconds = |ms| TimeDelta :: try_milliseconds ( ms) . unwrap ( ) ;
1055
+ let seconds = |s| TimeDelta :: try_seconds ( s) . unwrap ( ) ;
1037
1056
1038
1057
assert_eq ! (
1039
1058
milliseconds( i64 :: MAX ) . checked_add( & milliseconds( 0 ) ) ,
@@ -1056,6 +1075,10 @@ mod tests {
1056
1075
) ;
1057
1076
assert ! ( milliseconds( -i64 :: MAX ) . checked_sub( & milliseconds( 1 ) ) . is_none( ) ) ;
1058
1077
assert ! ( milliseconds( -i64 :: MAX ) . checked_sub( & TimeDelta :: nanoseconds( 1 ) ) . is_none( ) ) ;
1078
+
1079
+ assert ! ( seconds( i64 :: MAX / 1000 ) . checked_mul( 2000 ) . is_none( ) ) ;
1080
+ assert ! ( seconds( i64 :: MIN / 1000 ) . checked_mul( 2000 ) . is_none( ) ) ;
1081
+ assert ! ( seconds( 1 ) . checked_div( 0 ) . is_none( ) ) ;
1059
1082
}
1060
1083
1061
1084
#[ test]
0 commit comments