chronometer/
lib.rs

1use std::time::{Duration, Instant};
2
3pub struct Chronometer {
4    chrono: Option<Instant>,
5    old: Option<Duration>,
6    
7    /// Vector of all the laps since last reset
8    pub laps: Vec<Duration>,
9
10    /// Has the chronometer started yet
11    pub started: bool,
12
13    /// Is the chronometer in pause mode
14    pub paused: bool,
15}
16
17impl Chronometer {
18    /// Create a new Chronometer
19    /// 
20    /// # Examples
21    /// 
22    /// Basic usage:
23    /// 
24    /// ```
25    /// use chronometer::Chronometer;
26    /// 
27    /// let mut chrono = Chronometer::new();
28    /// ```
29    pub fn new() -> Chronometer {
30        Chronometer {
31            chrono: None,
32            old: None,
33            started: false,
34            paused: false,
35            laps: vec![],
36        }
37    }
38
39    /// Start and "unpause" the chronometer
40    /// 
41    /// # Examples
42    /// 
43    /// Basic usage:
44    /// 
45    /// ```
46    /// chrono.start();
47    /// ```
48    pub fn start(&mut self) {
49        self.chrono = Some(Instant::now());
50        self.started = true;
51        self.paused = false;
52    }
53
54    /// Pause the chronometer
55    /// 
56    /// # Examples
57    /// 
58    /// Basic usage:
59    /// 
60    /// ```
61    /// chrono.start();
62    /// 
63    /// let time = time::Duration::from_millis(100);
64    /// 
65    /// thread::sleep(time);
66    /// chrono.pause(); // chrono.duration == Duration<0.1s>
67    /// thread::sleep(time);
68    /// 
69    /// // chrono.duration == Duration<0.1s>
70    /// 
71    /// chrono.start();
72    /// thread::sleep(time);
73    /// // chrono.duration == Duration<0.2s>
74    /// ```
75    pub fn pause(&mut self) {
76        self.old = match self.chrono {
77            Some(chrono) => match self.old {
78                Some(old) => Some(chrono.elapsed() + old),
79                None => Some(chrono.elapsed()),
80            },
81            None => None,
82        };
83        self.chrono = None;
84        self.paused = true;
85    }
86
87    /// Add a lap to the chronometer
88    /// 
89    /// # Examples
90    /// 
91    /// Basic usage:
92    /// 
93    /// ```
94    /// chrono.start();
95    /// 
96    /// let time = time::Duration::from_millis(100);
97    /// 
98    /// thread::sleep(time);
99    /// 
100    /// chrono.lap(); // chono.laps == [Duration<0.1s>, Duration<0.2s>]
101    /// 
102    /// thread::sleep(time);
103    /// 
104    /// chrono.lap(); // chono.laps == [Duration<0.1s>, Duration<0.2s>]
105    /// ```
106    pub fn lap(&mut self) {
107        if let Some(chrono) = self.chrono {
108            self.laps.push(chrono.elapsed());
109        }
110    }
111
112    /// Reset the chronometer, useful to restart everything and all the mesurements in your program
113    /// 
114    /// # Examples
115    /// 
116    /// Basic usage:
117    /// 
118    /// ```
119    /// chrono.start();
120    /// 
121    /// let time = time::Duration::from_millis(100);
122    /// 
123    /// thread::sleep(time);
124    /// 
125    /// chrono.lap(); // chono.laps == [Duration<0.1s>, Duration<0.2s>]
126    /// chrono.reset();
127    /// // chono == {
128    /// //  started: false,
129    /// //  paused: false,
130    /// //  laps: vec![],
131    /// // }
132    /// ```
133    pub fn reset(&mut self) {
134        self.chrono = None;
135        self.paused = false;
136        self.started = false;
137        self.old = None;
138        self.laps = vec![]
139    }
140
141    /// Gets you the elapsed time on your chronometer as a std::time::Duration
142    /// 
143    /// # Examples
144    /// 
145    /// Basic usage:
146    /// 
147    /// ```
148    /// chrono.start();
149    /// 
150    /// let time = time::Duration::from_millis(100);
151    /// 
152    /// thread::sleep(time);
153    /// 
154    /// println!("elapsed: {}", chrono.duration().as_millis()); // elapsed: 100
155    /// ```
156    pub fn duration(&self) -> Option<Duration> {
157        if self.started {
158            if self.paused {
159                self.old
160            } else {
161                match self.chrono {
162                    Some(chrono) => match self.old {
163                        Some(old) => Some(chrono.elapsed() + old),
164                        None => Some(chrono.elapsed()),
165                    },
166                    None => None,
167                }
168            }
169        } else {
170            None
171        }
172    }
173}
174
175/// Displays the current duration as milliseconds
176impl std::fmt::Display for Chronometer {
177    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
178        match self.duration() {
179            Some(duration) => write!(f, "{}", duration.as_millis()),
180            None => write!(f, "<not started>"),
181        }
182    }
183}
184
185/// Displays all the public chronometer informations
186impl std::fmt::Debug for Chronometer {
187    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
188        write!(f, "<Chronometer {{ started: {}, paused: {}, laps: {}, current value: {:?} }}>", self.started, self.paused, self.laps.len(), match self.duration() {
189            Some(duration) => duration,
190            None => std::time::Duration::new(0, 0),
191        })
192    }
193}
194
195
196#[cfg(test)]
197mod test {
198    use super::Chronometer;
199
200    #[test]
201    fn create() {
202        let chrono = Chronometer::new();
203
204        assert_eq!(chrono.started, false);
205        assert_eq!(chrono.paused, false);
206
207        assert_eq!(chrono.chrono, None);
208        assert_eq!(chrono.laps, vec![]);
209
210        assert_eq!(chrono.duration(), None);
211    }
212
213    #[test]
214    fn start() {
215        let mut chrono = Chronometer::new();
216
217        chrono.start();
218
219        assert_eq!(chrono.started, true);
220        assert_eq!(chrono.paused, false);
221
222        assert_ne!(chrono.chrono, None);
223
224        std::thread::sleep(std::time::Duration::from_millis(100));
225
226        match chrono.duration() {
227            Some(duration) => assert_eq!(duration.as_millis() > 0, true),
228            None => assert_eq!(true, false),
229        }
230    }
231
232    #[test]
233    fn pause() {
234        let mut chrono = Chronometer::new();
235
236        chrono.start();
237
238        assert_eq!(chrono.started, true);
239        assert_eq!(chrono.paused, false);
240
241        let time_before_pause = match chrono.duration() {
242            Some(duration) => duration.as_millis(),
243            None => 10000,
244        };
245
246        chrono.pause();
247
248        assert_eq!(chrono.started, true);
249        assert_eq!(chrono.paused, true);
250
251        let time_after_pause = match chrono.duration() {
252            Some(duration) => duration.as_millis(),
253            None => 10000,
254        };
255
256        assert_eq!(time_before_pause, time_after_pause);
257    }
258}