Skip to main content

music21/common/
objects.rs

1//! music21's `common.objects`, as far as it is not about Python objects.
2
3use std::time::{Duration, Instant};
4
5/// music21's `Timer`: how long since it was started, or, once stopped, how
6/// long it ran.
7///
8/// ```
9/// use music21::common::objects::Timer;
10///
11/// let mut timer = Timer::new();
12/// timer.stop();
13/// assert_eq!(timer.elapsed(), timer.elapsed());
14/// ```
15#[derive(Debug, Clone, Copy)]
16pub struct Timer {
17    started: Instant,
18    ran: Option<Duration>,
19}
20
21impl Default for Timer {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl Timer {
28    /// A timer started now.
29    pub fn new() -> Self {
30        Self {
31            started: Instant::now(),
32            ran: None,
33        }
34    }
35
36    /// Starts again from now, running.
37    pub fn start(&mut self) {
38        *self = Self::new();
39    }
40
41    /// Stops, keeping how long it ran; stopping again keeps the later time.
42    pub fn stop(&mut self) {
43        self.ran = Some(self.started.elapsed());
44    }
45
46    /// The same as [`Timer::start`], which is what music21's `clear` does.
47    pub fn clear(&mut self) {
48        self.start();
49    }
50
51    /// Seconds since it started, or the seconds it ran if stopped.
52    pub fn elapsed(&self) -> f64 {
53        self.ran
54            .unwrap_or_else(|| self.started.elapsed())
55            .as_secs_f64()
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    /// A stopped timer stands still, and starting it again runs it from
64    /// nothing.
65    #[test]
66    fn a_stopped_timer_stands_still_until_started() {
67        let mut timer = Timer::new();
68        std::thread::sleep(Duration::from_millis(2));
69        timer.stop();
70        let ran = timer.elapsed();
71        assert!(ran > 0.0);
72        std::thread::sleep(Duration::from_millis(2));
73        assert_eq!(timer.elapsed(), ran);
74        timer.start();
75        assert!(timer.elapsed() < ran + 0.002);
76        assert!(timer.ran.is_none());
77    }
78}