clock_core/
timer.rs

1//! # Timer
2//!
3//! A timer that mimics iOS's timer.
4//!
5//! ## Usage
6//!
7//! - Use `Timer::new(<duration>)` to initialise a new timer instance. `<duration>` is a
8//! `chrono::Duration`. The timer is paused at the duration you specified and will **not**
9//! run until you call `.resume()` or `.pause_or_resume()`.
10//! - While running, call `.pause_or_resume()`, `.pause()` or `.resume()` to pause or resume.
11//! - When you want to stop (reset), call `.stop()`, which resets the timer and returns
12//!   [`TimerData`](struct.TimerData.html)
13
14use chrono::{DateTime, Duration, Local};
15
16#[derive(Debug, Clone)]
17pub struct TimerData {
18    pub total: Duration,
19    pub remaining: Duration,
20    pub start_moments: Vec<DateTime<Local>>, // moments at which the timer resumes; the first is the start monent
21    pub pause_moments: Vec<DateTime<Local>>, // moments at which the timer is paused; the last is the stop moment
22}
23
24impl TimerData {
25    fn new(duration: Duration) -> Self {
26        Self {
27            total: duration,
28            remaining: duration,
29            start_moments: Vec::new(),
30            pause_moments: Vec::new(),
31        }
32    }
33    pub fn start(&self) -> DateTime<Local> {
34        self.start_moments[0]
35    }
36    pub fn stop(&self) -> DateTime<Local> {
37        self.pause_moments[self.pause_moments.len() - 1]
38    }
39    pub fn duration_expected(&self) -> Duration {
40        self.total
41    }
42    pub fn duration_actual(&self) -> Duration {
43        self.stop() - self.start()
44    }
45}
46
47/// A countdown timer
48#[derive(Clone, Debug)]
49pub struct Timer {
50    pub paused: bool,
51    pub data: TimerData,
52}
53
54impl Timer {
55    /// Returns stopwatch reset to zero
56    pub fn new(duration: Duration) -> Self {
57        Self {
58            paused: true, // finished by default; start by explicitly calling `.resume()`
59            data: TimerData::new(duration),
60        }
61    }
62    /// Read the timer. Returns the duration passed.
63    pub fn read(&self) -> Duration {
64        if self.paused {
65            self.data.remaining
66        } else {
67            self.data.remaining - (Local::now() - self.last_start())
68        }
69    }
70    /// Pause or resume the timer. (If paused, resume, and vice versa.)
71    pub fn pause_or_resume(&mut self) {
72        self.pause_or_resume_at(Local::now());
73    }
74
75    pub fn pause_or_resume_at(&mut self, moment: DateTime<Local>) {
76        if self.paused {
77            self.resume_at(moment);
78        } else {
79            self.pause_at(moment);
80        }
81    }
82
83    /// Pause the timer (suggest using `pause_or_resume` instead.)
84    pub fn pause(&mut self) {
85        self.pause_at(Local::now());
86    }
87
88    pub fn pause_at(&mut self, moment: DateTime<Local>) {
89        self.data.pause_moments.push(moment);
90        self.data.remaining = self.data.remaining - (moment - self.last_start());
91        self.paused = true;
92    }
93    /// Resume the timer (suggest using `pause_or_resume` instead.)
94    pub fn resume(&mut self) {
95        self.resume_at(Local::now());
96    }
97
98    pub fn resume_at(&mut self, moment: DateTime<Local>) {
99        self.data.start_moments.push(moment);
100        self.paused = false;
101    }
102
103    /// Stop the timer, return the data, and reset the timer with the previously set duration.
104    pub fn stop(&mut self) -> TimerData {
105        self.stop_at(Local::now())
106    }
107
108    pub fn stop_at(&mut self, moment: DateTime<Local>) -> TimerData {
109        self.data.pause_moments.push(moment);
110        let duration = self.data.total;
111        let data = std::mem::replace(&mut self.data, TimerData::new(duration));
112        data
113    }
114
115    fn last_start(&self) -> DateTime<Local> {
116        self.data.start_moments[self.data.start_moments.len() - 1]
117    }
118}