diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index df139965753..466f28f0ef0 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -161,6 +161,20 @@ fn checked_div() { assert_eq!(Duration::new(2, 0).checked_div(0), None); } +#[test] +fn correct_sum() { + let durations = [ + Duration::new(1, 999_999_999), + Duration::new(2, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(5, 0), + ]; + let sum = durations.iter().sum::(); + assert_eq!(sum, Duration::new(1+2+5+4, 1_000_000_000 - 5)); +} + #[test] fn debug_formatting_extreme_values() { assert_eq!( diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 563eea0066d..25721b7fcec 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -524,17 +524,47 @@ impl DivAssign for Duration { } } +macro_rules! sum_durations { + ($iter:expr) => {{ + let mut total_secs: u64 = 0; + let mut total_nanos: u64 = 0; + + for entry in $iter { + total_secs = total_secs + .checked_add(entry.secs) + .expect("overflow in iter::sum over durations"); + total_nanos = match total_nanos.checked_add(entry.nanos as u64) { + Some(n) => n, + None => { + total_secs = total_secs + .checked_add(total_nanos / NANOS_PER_SEC as u64) + .expect("overflow in iter::sum over durations"); + (total_nanos % NANOS_PER_SEC as u64) + entry.nanos as u64 + } + }; + } + total_secs = total_secs + .checked_add(total_nanos / NANOS_PER_SEC as u64) + .expect("overflow in iter::sum over durations"); + total_nanos = total_nanos % NANOS_PER_SEC as u64; + Duration { + secs: total_secs, + nanos: total_nanos as u32, + } + }}; +} + #[stable(feature = "duration_sum", since = "1.16.0")] impl Sum for Duration { fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + b) + sum_durations!(iter) } } #[stable(feature = "duration_sum", since = "1.16.0")] impl<'a> Sum<&'a Duration> for Duration { fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + *b) + sum_durations!(iter) } }