Skip to content

Commit

Permalink
Fix implementation of Duration::checked_div
Browse files Browse the repository at this point in the history
  • Loading branch information
jhpratt committed Jul 30, 2023
1 parent a9fea9f commit 8060100
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 10 deletions.
8 changes: 8 additions & 0 deletions tests/duration.rs
Expand Up @@ -388,6 +388,14 @@ fn checked_div() {
assert_eq!(Duration::MIN.checked_div(-1), None);
}

#[test]
fn checked_div_regression() {
assert_eq!(
Duration::new(1, 1).checked_div(7),
Some(Duration::new(0, 142_857_143)) // manually verified
);
}

#[test]
fn saturating_add() {
assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds());
Expand Down
20 changes: 10 additions & 10 deletions time/src/duration.rs
Expand Up @@ -994,16 +994,16 @@ impl Duration {
/// assert_eq!(1.seconds().checked_div(0), None);
/// ```
pub const fn checked_div(self, rhs: i32) -> Option<Self> {
let seconds = const_try_opt!(self.seconds.checked_div(rhs as i64));
let carry = self.seconds - seconds * (rhs as i64);
let extra_nanos =
const_try_opt!((carry * Nanosecond.per(Second) as i64).checked_div(rhs as i64));
let nanoseconds =
const_try_opt!(self.nanoseconds.get().checked_div(rhs)) + (extra_nanos as i32);

// Safety: TODO may not be safe? `nanoseconds` could overflow past a billion on final
// addition?
unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
let (secs, extra_secs) = (
const_try_opt!(self.seconds.checked_div(rhs as i64)),
self.seconds % (rhs as i64),
);
let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs);
nanos += ((extra_secs * (Nanosecond.per(Second) as i64) + extra_nanos as i64)
/ (rhs as i64)) as i32;

// Safety: `nanoseconds` is in range.
unsafe { Some(Self::new_unchecked(secs, nanos)) }
}
// endregion checked arithmetic

Expand Down

0 comments on commit 8060100

Please sign in to comment.