1#[doc(hidden)]
7extern crate alloc;
8
9#[cfg(feature = "std")]
10extern crate std;
11
12use crate::error::Error;
14use dimas_core::builder_states::{
15 Callback, Interval, NoCallback, NoInterval, NoSelector, NoStorage, Selector, Storage,
16};
17
18use super::{ArcTimerCallback, Timer};
19
20use alloc::{
21 format,
22 string::{String, ToString},
23 sync::Arc,
24};
25use core::time::Duration;
26use dimas_core::{Result, enums::OperationState, traits::Context};
27use std::{
28 collections::HashMap,
29 sync::{Mutex, RwLock},
30};
31#[derive(Clone)]
36pub struct TimerBuilder<P, K, I, C, S>
37where
38 P: Send + Sync + 'static,
39{
40 context: Context<P>,
41 activation_state: OperationState,
42 selector: K,
43 interval: I,
44 callback: C,
45 storage: S,
46 delay: Option<Duration>,
47}
48
49impl<P> TimerBuilder<P, NoSelector, NoInterval, NoCallback, NoStorage>
50where
51 P: Send + Sync + 'static,
52{
53 #[must_use]
55 pub const fn new(context: Context<P>) -> Self {
56 Self {
57 context,
58 activation_state: OperationState::Active,
59 selector: NoSelector,
60 interval: NoInterval,
61 callback: NoCallback,
62 storage: NoStorage,
63 delay: None,
64 }
65 }
66}
67
68impl<P, K, I, C, S> TimerBuilder<P, K, I, C, S>
69where
70 P: Send + Sync + 'static,
71{
72 #[must_use]
74 pub const fn activation_state(mut self, state: OperationState) -> Self {
75 self.activation_state = state;
76 self
77 }
78
79 #[must_use]
81 pub const fn delay(mut self, delay: Duration) -> Self {
82 self.delay.replace(delay);
83 self
84 }
85}
86
87impl<P, I, C, S> TimerBuilder<P, NoSelector, I, C, S>
88where
89 P: Send + Sync + 'static,
90{
91 #[must_use]
93 pub fn selector(self, selector: &str) -> TimerBuilder<P, Selector, I, C, S> {
94 let Self {
95 context,
96 activation_state,
97 interval,
98 callback,
99 storage,
100 delay,
101 ..
102 } = self;
103 TimerBuilder {
104 context,
105 activation_state,
106 selector: Selector {
107 selector: selector.into(),
108 },
109 interval,
110 callback,
111 storage,
112 delay,
113 }
114 }
115
116 #[must_use]
119 pub fn name(self, topic: &str) -> TimerBuilder<P, Selector, I, C, S> {
120 let selector = self
121 .context
122 .prefix()
123 .map_or_else(|| topic.to_string(), |prefix| format!("{prefix}/{topic}"));
124 let Self {
125 context,
126 activation_state,
127 interval,
128 callback,
129 storage,
130 delay,
131 ..
132 } = self;
133 TimerBuilder {
134 context,
135 activation_state,
136 selector: Selector { selector },
137 interval,
138 callback,
139 storage,
140 delay,
141 }
142 }
143}
144
145impl<P, K, C, S> TimerBuilder<P, K, NoInterval, C, S>
146where
147 P: Send + Sync + 'static,
148{
149 #[must_use]
151 pub fn interval(self, interval: Duration) -> TimerBuilder<P, K, Interval, C, S> {
152 let Self {
153 context,
154 activation_state,
155 selector: name,
156 callback,
157 storage,
158 delay,
159 ..
160 } = self;
161 TimerBuilder {
162 context,
163 activation_state,
164 selector: name,
165 interval: Interval { interval },
166 callback,
167 storage,
168 delay,
169 }
170 }
171}
172
173impl<P, K, I, S> TimerBuilder<P, K, I, NoCallback, S>
174where
175 P: Send + Sync + 'static,
176{
177 #[must_use]
179 pub fn callback<F>(self, callback: F) -> TimerBuilder<P, K, I, Callback<ArcTimerCallback<P>>, S>
180 where
181 F: FnMut(Context<P>) -> Result<()> + Send + Sync + 'static,
182 {
183 let Self {
184 context,
185 activation_state,
186 selector: name,
187 interval,
188 storage,
189 delay,
190 ..
191 } = self;
192 let callback: ArcTimerCallback<P> = Arc::new(Mutex::new(callback));
193 TimerBuilder {
194 context,
195 activation_state,
196 selector: name,
197 interval,
198 callback: Callback { callback },
199 storage,
200 delay,
201 }
202 }
203}
204
205impl<P, K, I, C> TimerBuilder<P, K, I, C, NoStorage>
206where
207 P: Send + Sync + 'static,
208{
209 #[must_use]
211 pub fn storage(
212 self,
213 storage: Arc<RwLock<HashMap<String, Timer<P>>>>,
214 ) -> TimerBuilder<P, K, I, C, Storage<Timer<P>>> {
215 let Self {
216 context,
217 activation_state,
218 selector: name,
219 interval,
220 callback,
221 delay,
222 ..
223 } = self;
224 TimerBuilder {
225 context,
226 activation_state,
227 selector: name,
228 interval,
229 callback,
230 storage: Storage { storage },
231 delay,
232 }
233 }
234}
235
236impl<P, S> TimerBuilder<P, Selector, Interval, Callback<ArcTimerCallback<P>>, S>
237where
238 P: Send + Sync + 'static,
239{
240 pub fn build(self) -> Result<Timer<P>> {
244 let Self {
245 context,
246 activation_state,
247 selector: name,
248 interval,
249 callback,
250 delay,
251 ..
252 } = self;
253
254 Ok(Timer::new(
255 name.selector,
256 context,
257 activation_state,
258 callback.callback,
259 interval.interval,
260 delay,
261 ))
262 }
263}
264
265impl<P> TimerBuilder<P, Selector, Interval, Callback<ArcTimerCallback<P>>, Storage<Timer<P>>>
266where
267 P: Send + Sync + 'static,
268{
269 pub fn add(self) -> Result<Option<Timer<P>>> {
273 let name = self.selector.selector.clone();
274 let collection = self.storage.storage.clone();
275 let t = self.build()?;
276
277 let r = collection
278 .write()
279 .map_err(|_| Error::MutexPoison(String::from("TimerBuilder")))?
280 .insert(name, t);
281 Ok(r)
282 }
283}
284#[cfg(test)]
287mod tests {
288 use super::*;
289
290 #[derive(Debug)]
291 struct Props {}
292
293 const fn is_normal<T: Sized + Send + Sync>() {}
295
296 #[test]
297 const fn normal_types() {
298 is_normal::<TimerBuilder<Props, NoSelector, NoInterval, NoCallback, NoStorage>>();
299 }
300}