//! Simple timers and the global "time since last update" registry. use std::collections::HashMap; use std::sync::Mutex; use std::sync::OnceLock; use std::time::Instant; /// The timer class. A simple chronometer. #[derive(Debug, Clone)] pub struct Timer { duration: f64, target: Instant, } impl Timer { pub fn new(duration: f64) -> Self { let mut timer = Self { duration, target: Instant::now() }; timer.start(); timer } pub fn start(&mut self) { self.target = Instant::now() + std::time::Duration::from_secs_f64(self.duration.max(0.0)); } pub fn reset(&mut self, duration: Option) { if let Some(duration) = duration { self.set(duration); } self.start(); } /// Elapsed seconds since the timer was started. pub fn get(&self) -> f64 { self.duration - self.target.saturating_duration_since(Instant::now()).as_secs_f64() } pub fn set(&mut self, duration: f64) { self.duration = duration; } pub fn duration(&self) -> f64 { self.duration } pub fn finished(&self) -> bool { Instant::now() > self.target } } /// The counter class, used to log durations. #[derive(Debug, Clone)] pub struct Counter { start: Instant, } impl Default for Counter { fn default() -> Self { Self::new() } } impl Counter { pub fn new() -> Self { Self { start: Instant::now() } } pub fn reset(&mut self) { self.start = Instant::now(); } pub fn get(&self) -> f64 { self.start.elapsed().as_secs_f64() } } fn last_update_times() -> &'static Mutex> { static MAP: OnceLock>> = OnceLock::new(); MAP.get_or_init(|| Mutex::new(HashMap::new())) } /// Return the elapsed time since the last update for the given key. /// /// The first call for a key returns 1 second, mirroring the Python /// implementation. pub fn get_time_since_last_update(key: &str) -> f64 { let now = Instant::now(); let mut map = last_update_times().lock().unwrap(); let since = match map.get(key) { Some(last) => now.duration_since(*last).as_secs_f64(), None => 1.0, }; map.insert(key.to_string(), now); since } #[cfg(test)] mod tests { use super::*; #[test] fn timer_finished() { let timer = Timer::new(0.0); std::thread::sleep(std::time::Duration::from_millis(5)); assert!(timer.finished()); } #[test] fn time_since_first_call_is_one() { let v = get_time_since_last_update("test-key"); assert_eq!(v, 1.0); } }