1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
//! `rusty_time` is a simple timer library.
//!
//! Use it in a loop like this:
//!
//! ```rust
//! use std::time::{Duration, Instant};
//!
//! use rusty_time::Timer;
//!
//! fn main() {
//! let mut timer = Timer::new(Duration::from_secs_f32(1.5));
//!
//! let mut start_time = Instant::now();
//! loop {
//! timer.tick(start_time.elapsed());
//! start_time = Instant::now();
//! println!(
//! "Time on timer: {:.2}s ({:.1}%)",
//! timer.remaining().as_secs_f32(),
//! timer.percent_left() * 100.0
//! );
//! if timer.just_finished() {
//! break;
//! }
//! }
//! println!("Timer finished!");
//! }
//! ```
use std::time::Duration;
/// A simple timer that is externally driven. [`.tick()`](Timer::tick) must be called with a delta
/// time for the timer to advance.
///
/// Use it in a loop like this:
///
/// ```rust
/// use std::time::{Duration, Instant};
///
/// use rusty_time::Timer;
///
/// fn main() {
/// let mut timer = Timer::new(Duration::from_secs_f32(1.5));
///
/// let mut start_time = Instant::now();
/// loop {
/// timer.tick(start_time.elapsed());
/// start_time = Instant::now();
/// println!(
/// "Time on timer: {:.2}s ({:.1}%)",
/// timer.remaining().as_secs_f32(),
/// timer.percent_left() * 100.0
/// );
/// if timer.just_finished() {
/// break;
/// }
/// }
/// println!("Timer finished!");
/// }
/// ```
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Timer {
duration: Duration,
remaining: Duration,
finished: bool,
just_finished: bool,
}
impl Timer {
/// Create a new timer with the given duration
pub fn new(duration: Duration) -> Self {
Self {
duration,
remaining: duration,
finished: false,
just_finished: false,
}
}
/// Advance the timer by a specific duration. This _must_ be called for the timer to be useful.
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
}
/// Whether the timer hit zero since the last call to [`tick`](Timer::tick).
pub fn just_finished(&self) -> bool {
self.just_finished
}
/// Whether the timer is at zero.
pub fn finished(&self) -> bool {
self.finished
}
/// Reset the timer to the starting duration. Resets `finished` and `just_finished` as well.
pub fn reset(&mut self) {
self.set_remaining(self.duration);
}
/// Returns percent of timer elapsed (from 0.0 to 1.0)
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()
}
}
/// Returns percent of timer remaining (from 1.0 to 0.0)
pub fn percent_left(&self) -> f32 {
1.0 - self.percent()
}
/// Returns the full duration of the timer when newly started. See also
/// [`remaining`](Timer::remaining) and [`elapsed`](Timer::elapsed)
pub fn duration(&self) -> Duration {
self.duration
}
/// Sets the starting duration of the timer, but does not change the remaining time on the timer.
/// See [`reset`](Timer::reset) to reset the remaining time to the starting duration.
pub fn set_duration(&mut self, duration: Duration) {
self.duration = duration;
}
/// Returns the time currently remaining on the timer.
pub fn remaining(&self) -> Duration {
self.remaining
}
/// Sets the time currently remaining on the timer. Sets/unsets that the timer has finished as
/// appropriate.
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);
}
/// Returns the time that has elapsed on the timer.
pub fn elapsed(&self) -> Duration {
self.duration - self.remaining
}
/// Sets the time currently elapsed on the timer. Sets/unsets that the timer has finished as
/// appropriate.
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));
}
}