Fix integer overflow in TempoMap::bar_beat_at_tick for i64::MIN

Found while testing crates/time/src/tempo.rs:271

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-21 01:12:42 +02:00
co-authored by Claude Haiku 5.5
parent 7b339fe921
commit 4ef6458e4e
+15 -3
View File
@@ -268,9 +268,12 @@ impl TempoMap {
let first = self.meter_at_tick(0);
if tick < 0 {
let tpb = first.ticks_per_bar();
let bars_back = (-tick + tpb - 1) / tpb;
let bar_tick = -bars_back * tpb;
let within = tick - bar_tick;
let abs = tick.unsigned_abs();
let tpb_u = tpb.unsigned_abs();
let bars_back_u = abs / tpb_u + u64::from(!abs.is_multiple_of(tpb_u));
let bars_back = i64::try_from(bars_back_u).unwrap_or(i64::MAX);
// Offset of `tick` inside its bar, without negating `i64::MIN`.
let within = ((tpb_u - abs % tpb_u) % tpb_u) as i64;
let beat_t = first.ticks_per_beat();
return BarBeat { bar: 1 - bars_back, beat: within / beat_t + 1, tick: within % beat_t };
}
@@ -341,6 +344,15 @@ mod tests {
assert_eq!(m.bar_start_tick(0), -TICKS_PER_QUARTER * 4);
}
#[test]
fn bar_beat_at_min_tick_does_not_overflow() {
let m = TempoMap::default();
let bb = m.bar_beat_at_tick(i64::MIN);
assert!(bb.bar < 1);
assert!(bb.beat >= 1 && bb.tick >= 0);
assert_eq!(m.bar_beat_at_tick(-1).bar, 0);
}
#[test]
fn tempo_change_is_integrated() {
let mut m = TempoMap::default();