diff --git a/src/timer.rs b/src/timer.rs index ae60b07..2e7d544 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -178,7 +178,7 @@ impl<'a> Timer<'a> { } } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct ClockFrequency { hz: usize, } @@ -196,21 +196,53 @@ pub struct ClockValue { } impl ClockValue { + pub const fn new(num_ticks: isize, clock_hz: usize) -> ClockValue { + ClockValue { + num_ticks, + clock_frequency: ClockFrequency { hz: clock_hz }, + } + } + pub fn num_ticks(&self) -> isize { self.num_ticks } + // Computes (value * factor) / divisor, even when value * factor >= isize::MAX. + fn scale_int(value: isize, factor: isize, divisor: isize) -> isize { + // As long as isize is not i64, this should be fine. If not, this is an alternative: + // factor * (value / divisor) + ((value % divisor) * factor) / divisor + ((value as i64 * factor as i64) / divisor as i64) as isize + } + pub fn ms(&self) -> isize { - if self.num_ticks.abs() < isize::MAX / 1000 { - (1000 * self.num_ticks) / self.clock_frequency.hz() as isize - } else { - 1000 * (self.num_ticks / self.clock_frequency.hz() as isize) - } + ClockValue::scale_int(self.num_ticks, 1000, self.clock_frequency.hz() as isize) } pub fn ms_f64(&self) -> f64 { 1000.0 * (self.num_ticks as f64) / (self.clock_frequency.hz() as f64) } + + pub fn wrapping_add(self, duration: Duration) -> ClockValue { + // This is a precision preserving formula for scaling an isize. + let duration_ticks = + ClockValue::scale_int(duration.ms, self.clock_frequency.hz() as isize, 1000); + ClockValue { + num_ticks: self.num_ticks.wrapping_add(duration_ticks), + clock_frequency: self.clock_frequency, + } + } + + pub fn wrapping_sub(self, other: ClockValue) -> Option> { + if self.clock_frequency == other.clock_frequency { + let clock_duration = ClockValue { + num_ticks: self.num_ticks - other.num_ticks, + clock_frequency: self.clock_frequency, + }; + Some(Duration::from_ms(clock_duration.ms())) + } else { + None + } + } } pub struct Alarm {