use std::time::Duration;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Timer {
duration: Duration,
remaining: Duration,
finished: bool,
just_finished: bool,
}
impl Timer {
pub fn new(duration: Duration) -> Self {
Self {
duration,
remaining: duration,
finished: false,
just_finished: false,
}
}
pub fn tick(&mut self, delta: Duration) -> &mut Self {
self.just_finished = false;
if self.finished {
return self;
}
self.remaining = self.remaining.saturating_sub(delta);
if self.remaining == Duration::ZERO {
self.just_finished = true;
self.finished = true;
}
self
}
pub fn just_finished(&self) -> bool {
self.just_finished
}
pub fn finished(&self) -> bool {
self.finished
}
pub fn reset(&mut self) {
self.set_remaining(self.duration);
}
pub fn percent(&self) -> f32 {
if self.duration == Duration::ZERO {
1.0
} else {
(self.duration - self.remaining).as_secs_f32() / self.duration.as_secs_f32()
}
}
pub fn percent_left(&self) -> f32 {
1.0 - self.percent()
}
pub fn duration(&self) -> Duration {
self.duration
}
pub fn set_duration(&mut self, duration: Duration) {
self.duration = duration;
}
pub fn remaining(&self) -> Duration {
self.remaining
}
pub fn set_remaining(&mut self, remaining: Duration) {
if remaining == Duration::ZERO && self.remaining != Duration::ZERO {
self.just_finished = true;
self.finished = true;
} else {
self.just_finished = false;
self.finished = false;
}
self.remaining = remaining.clamp(Duration::ZERO, self.duration);
}
pub fn elapsed(&self) -> Duration {
self.duration - self.remaining
}
pub fn set_elapsed(&mut self, elapsed: Duration) {
self.set_remaining(self.duration.saturating_sub(elapsed));
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn timer_works() {
let mut timer = Timer::new(Duration::from_millis(500));
assert_eq!(timer.percent(), 0.0);
assert_eq!(timer.percent_left(), 1.0);
timer.tick(Duration::from_millis(300));
assert_eq!(timer.finished(), false);
assert_eq!(timer.just_finished(), false);
timer.tick(Duration::from_millis(300));
assert_eq!(timer.finished(), true);
assert_eq!(timer.just_finished(), true);
assert_eq!(timer.remaining(), Duration::ZERO);
timer.tick(Duration::from_millis(300));
assert_eq!(timer.finished(), true);
assert_eq!(timer.just_finished(), false);
assert_eq!(timer.remaining(), Duration::ZERO);
timer.reset();
assert_eq!(timer.finished, false);
assert_eq!(timer.remaining, Duration::from_millis(500));
timer.set_elapsed(Duration::from_millis(250));
assert_eq!(timer.percent(), 0.5);
assert_eq!(timer.percent_left(), 0.5);
assert_eq!(timer.remaining(), Duration::from_millis(250));
}
}