chronograf/
lib.rs

1use ::core::{fmt::Debug, time::Duration};
2
3/// Starts and returns a new stopwatch.
4#[inline]
5pub fn start() -> Sw<quanta::Instant> {
6    Sw {
7        elapsed: Duration::ZERO,
8        started: Some(quanta::Instant::now()),
9    }
10}
11
12pub trait Instant: Copy + Debug + Sized {
13    fn now() -> Self;
14    fn checked_add(&self, duration: Duration) -> Option<Self>;
15    fn checked_sub(&self, duration: Duration) -> Option<Self>;
16    fn saturating_duration_since(&self, earlier: Self) -> Duration;
17}
18
19impl Instant for quanta::Instant {
20    fn now() -> Self {
21        quanta::Instant::now()
22    }
23
24    fn checked_add(&self, duration: Duration) -> Option<Self> {
25        self.checked_add(duration)
26    }
27
28    fn checked_sub(&self, duration: Duration) -> Option<Self> {
29        self.checked_sub(duration)
30    }
31
32    fn saturating_duration_since(&self, earlier: Self) -> Duration {
33        self.saturating_duration_since(earlier)
34    }
35}
36
37#[derive(Clone, Copy, Debug)]
38pub struct Sw<I> {
39    elapsed: Duration,
40    started: Option<I>,
41}
42
43impl<I: Instant> Sw<I> {
44    /// Create a new stopwatch without starting it.
45    /// 
46    /// By creating a stopwatch in this way, it is possible to select an alternate
47    /// implementation of [`Instant`].
48    #[inline]
49    pub fn new() -> Self {
50        Sw {
51            elapsed: Duration::ZERO,
52            started: None,
53        }
54    }
55
56    /// Starts the stopwatch.
57    ///
58    /// Starting a stopwatch that is already running will have the effect of resetting the stopwatch.
59    #[inline]
60    pub fn start(&mut self) {
61        self.started = Some(I::now())
62    }
63
64    /// Stops the stopwatch.
65    ///
66    /// Stopping a stopwatch that has not been started will have no effect.
67    #[inline]
68    pub fn stop(&mut self) {
69        self.elapsed += self
70            .started
71            .take()
72            .map(|earlier| I::now().saturating_duration_since(earlier))
73            .unwrap_or(Duration::ZERO);
74    }
75
76    /// Stops the stopwatch, both consuming the stopwatch and returning the time elapsed.
77    #[inline]
78    pub fn finish(mut self) -> Duration {
79        self.stop();
80        self.elapsed
81    }
82}
83
84impl<I: Instant> Default for Sw<I> {
85    fn default() -> Self {
86        Sw::new()
87    }
88}