1use async_trait::async_trait;
2use std::sync::Arc;
3use std::time::{Duration, Instant};
4use tokio::sync::Mutex;
5use tokio::sync::Notify;
6use tokio::time;
7
8#[cfg(feature = "logging")]
9use log::{debug, error};
10
11use crate::errors::TimerError;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum TimerState {
16 Running,
17 Paused,
18 Stopped,
19}
20
21#[derive(Debug, Clone, Default)]
23pub struct TimerStatistics {
24 pub execution_count: usize,
26 pub elapsed_time: Duration,
28}
29
30#[async_trait]
32pub trait TimerCallback: Send + Sync {
33 async fn execute(&self) -> Result<(), TimerError>;
35}
36
37#[derive(Clone)]
38pub struct Timer {
40 state: Arc<Mutex<TimerState>>,
41 handle: Option<Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>>,
42 interval: Duration,
43 expiration_count: Option<usize>,
44 statistics: Arc<Mutex<TimerStatistics>>,
45 pause_notify: Arc<Notify>,
46}
47
48impl Timer {
49 pub fn new() -> Self {
51 Timer {
52 state: Arc::new(Mutex::new(TimerState::Stopped)),
53 handle: None,
54 interval: Duration::from_secs(0),
55 expiration_count: None,
56 statistics: Arc::new(Mutex::new(TimerStatistics::default())),
57 pause_notify: Arc::new(Notify::new()),
58 }
59 }
60
61 pub async fn start_once<F>(&mut self, delay: Duration, callback: F) -> Result<(), TimerError>
63 where
64 F: TimerCallback + 'static,
65 {
66 self.start_internal(delay, callback, false, None).await
67 }
68
69 pub async fn start_recurring<F>(
71 &mut self,
72 interval: Duration,
73 callback: F,
74 expiration_count: Option<usize>,
75 ) -> Result<(), TimerError>
76 where
77 F: TimerCallback + 'static,
78 {
79 self.start_internal(interval, callback, true, expiration_count)
80 .await
81 }
82
83 pub async fn pause(&self) -> Result<(), TimerError> {
85 let mut state = self.state.lock().await;
86 if *state == TimerState::Running {
87 *state = TimerState::Paused;
88 #[cfg(feature = "logging")]
89 debug!("Timer paused.");
90 Ok(())
91 } else {
92 Err(TimerError::TimerStopped)
93 }
94 }
95
96 pub async fn resume(&self) -> Result<(), TimerError> {
98 let mut state = self.state.lock().await;
99 if *state == TimerState::Paused {
100 *state = TimerState::Running;
101 self.pause_notify.notify_one();
102 #[cfg(feature = "logging")]
103 debug!("Timer resumed.");
104 Ok(())
105 } else {
106 Err(TimerError::InvalidParameter("Timer is not paused.".into()))
107 }
108 }
109
110 pub async fn stop(&mut self) -> Result<(), TimerError> {
112 let mut state = self.state.lock().await;
113 if *state != TimerState::Stopped {
114 *state = TimerState::Stopped;
115 if let Some(handle) = self.handle.take() {
116 drop(state); #[cfg(feature = "logging")]
118 debug!("Stopping timer.");
119 if let Some(handle) = handle.lock().await.take() {
120 handle.abort();
121 }
122 }
123 Ok(())
124 } else {
125 Err(TimerError::TimerStopped)
126 }
127 }
128
129 pub fn adjust_interval(&mut self, new_interval: Duration) -> Result<(), TimerError> {
131 if new_interval.as_nanos() == 0 {
132 return Err(TimerError::InvalidParameter(
133 "Interval must be greater than zero.".into(),
134 ));
135 }
136 self.interval = new_interval;
137 #[cfg(feature = "logging")]
138 debug!("Timer interval adjusted.");
139 Ok(())
140 }
141
142 pub async fn get_statistics(&self) -> TimerStatistics {
144 self.statistics.lock().await.clone()
145 }
146
147 pub async fn get_state(&self) -> TimerState {
149 *self.state.lock().await
150 }
151
152 pub fn get_expiration_count(&self) -> Option<usize> {
154 self.expiration_count
155 }
156
157 async fn start_internal<F>(
160 &mut self,
161 interval: Duration,
162 callback: F,
163 recurring: bool,
164 expiration_count: Option<usize>,
165 ) -> Result<(), TimerError>
166 where
167 F: TimerCallback + 'static,
168 {
169 if interval.as_nanos() == 0 {
170 return Err(TimerError::InvalidParameter(
171 "Interval must be greater than zero.".into(),
172 ));
173 }
174
175 if let Err(_e) = self.stop().await {
176 #[cfg(feature = "logging")]
177 error!("Failed to stop existing timer: {}", e);
178 }
179
180 {
182 let mut state_lock = self.state.lock().await;
183 *state_lock = TimerState::Running;
184 }
185
186 let state = Arc::clone(&self.state);
188 let statistics = Arc::clone(&self.statistics);
189 let pause_notify = Arc::clone(&self.pause_notify);
190 let interval = interval;
191 let expiration_count = expiration_count;
192 let callback = Arc::new(callback); #[cfg(feature = "logging")]
195 debug!("Starting timer.");
196
197 self.handle = Some(Arc::new(Mutex::new(Some(tokio::spawn(async move {
198 let mut tick_count = 0;
199 let start_time = Instant::now();
200
201 loop {
202 let current_state = {
204 let state_lock = state.lock().await;
205 *state_lock
206 };
207
208 if current_state == TimerState::Stopped {
209 break;
210 } else if current_state == TimerState::Paused {
211 pause_notify.notified().await;
212 continue;
213 }
214
215 time::sleep(interval).await;
217
218 if let Err(_e) = callback.execute().await {
220 #[cfg(feature = "logging")]
221 error!("Callback execution error: {}", e);
222 }
223
224 {
226 let mut stats = statistics.lock().await;
227 stats.execution_count += 1;
228 stats.elapsed_time = start_time.elapsed();
229 }
230 tick_count += 1;
231
232 if let Some(max_ticks) = expiration_count {
234 if tick_count >= max_ticks {
235 #[cfg(feature = "logging")]
236 debug!("Timer reached expiration count.");
237 break;
238 }
239 }
240
241 if !recurring {
242 break;
243 }
244 }
245
246 #[cfg(feature = "logging")]
247 debug!("Timer stopped.");
248 })))));
249
250 Ok(())
251 }
252}
253
254unsafe impl Send for Timer {}
255unsafe impl Sync for Timer {}