Saturate the bar offset for bars before 1 (#249)

bar_start_tick subtracted 1 from the bar before its saturating multiply,
so the minimum i64 bar panicked under overflow checks. Parsing
"-9223372036854775808|01|000" as Bars|Beats now returns a saturated
negative position instead.
This commit is contained in:
NetterSilver 2026-10-12 08:52:59 +02:00
parent acb08ff5f0
commit cfce845f70
2 changed files with 17 additions and 1 deletions

View File

@ -143,6 +143,15 @@ mod tests {
assert_eq!(format_position(12345, TimeFormat::Samples, sr, &map, rate, 0), "12345");
}
#[test]
fn minimum_bar_parses_without_overflow() {
let (sr, map, rate) = ctx();
let p = |t: &str| parse_position(t, TimeFormat::BarsBeats, sr, &map, rate, 0);
assert!(p("-9223372036854775808|01|000").is_ok_and(|s| s < 0));
assert_eq!(p("2|3|000").ok(), Some(144_000));
assert_eq!(p("0|1|000").ok(), Some(-96_000));
}
#[test]
fn parse_round_trips() {
let (sr, map, rate) = ctx();

View File

@ -200,7 +200,7 @@ impl TempoMap {
let mut cur_tick = 0i64;
let first = self.meter_at_tick(0);
if bar < 1 {
return (bar - 1).saturating_mul(first.ticks_per_bar());
return bar.saturating_sub(1).saturating_mul(first.ticks_per_bar());
}
for (i, m) in self.meters.iter().enumerate() {
let next_tick = self.meters.get(i + 1).map(|n| n.tick);
@ -288,6 +288,13 @@ mod tests {
assert_eq!(m.bar_beat_at(24_000, sr), BarBeat { bar: 1, beat: 2, tick: 0 });
}
#[test]
fn minimum_bar_saturates_instead_of_overflowing() {
let m = TempoMap::default();
assert_eq!(m.bar_start_tick(i64::MIN), i64::MIN);
assert_eq!(m.bar_start_tick(0), -TICKS_PER_QUARTER * 4);
}
#[test]
fn tempo_change_is_integrated() {
let mut m = TempoMap::default();