debouncer/
lib.rs

1use tokio::time::{sleep, Duration};
2use tokio::sync::Mutex;
3use std::sync::Arc;
4
5/// A debouncer that will call the last function after a delay.
6/// 
7/// # Examples
8/// ```rust
9/// use tokio::time::Duration;
10/// use debouncer::Debouncer;
11/// use std::sync::Arc;
12/// use tokio::sync::Mutex;
13/// #[tokio::main]
14/// async fn main() {
15///     let debouncer = Debouncer::new(Duration::from_secs(1));
16///     let counter: Arc<Mutex<i32>> = Arc::new(Mutex::new(0));
17/// 
18///     let counter_clone: Arc<Mutex<i32>> = Arc::clone(&counter);
19///     debouncer.call(move || {
20///         async move {
21///             let mut num = counter_clone.lock().await;
22///             *num += 1;
23///         }
24///     }).await;
25/// }
26/// ```
27pub struct Debouncer {
28    delay: Duration,
29    task: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
30}
31
32impl Debouncer {
33    /// Create a new debouncer with a delay.
34    pub fn new(delay: Duration) -> Self {
35        Debouncer {
36            delay,
37            task: Arc::new(Mutex::new(None)),
38        }
39    }
40
41    /// Call the function after the delay.
42    pub async fn call<F, Fut, R>(&self, f: F)
43    where
44        F: FnOnce() -> Fut + Send + 'static,
45        Fut: std::future::Future<Output = R> + Send + 'static,
46    {
47        let mut task = self.task.lock().await;
48
49        // Cancel existing timer if it exists
50        if let Some(handle) = task.take() {
51            handle.abort();
52        }
53
54        // Set a new timer
55        let delay = self.delay;
56        *task = Some(tokio::spawn(async move {
57            sleep(delay).await;
58            f().await;
59        }));
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use std::sync::Arc;
66    use tokio::sync::Mutex;
67    use tokio::time::Duration;
68    use crate::Debouncer;
69
70    #[tokio::test]
71    async fn should_call_last_only_test() {
72        let debouncer = Debouncer::new(Duration::from_secs(1));
73        let counter = Arc::new(Mutex::new(0));
74    
75        let counter_clone = Arc::clone(&counter);
76        debouncer.call(move || {
77            async move {
78                let mut num = counter_clone.lock().await;
79                *num += 1;
80            }
81        }).await;
82    
83        let counter_clone = Arc::clone(&counter);
84        debouncer.call(move || {
85            async move {
86                let mut num = counter_clone.lock().await;
87                *num += 1;
88            }
89        }).await;
90    
91        for _ in 0..5 {
92            let counter_clone = Arc::clone(&counter);
93            debouncer.call(move || {
94                async move {
95                    let mut num = counter_clone.lock().await;
96                    *num += 1;
97                }
98            }).await;
99            tokio::time::sleep(Duration::from_millis(200)).await;
100        }
101    
102        tokio::time::sleep(Duration::from_secs(2)).await;
103    
104        let final_value = *counter.lock().await;
105        assert_eq!(final_value, 1, "The final call should be executed once.");
106    }
107
108    #[tokio::test]
109    async fn should_call_all_if_duration_is_short_test() {
110        let debouncer = Debouncer::new(Duration::from_millis(100));
111        let counter = Arc::new(Mutex::new(0));
112    
113        let counter_clone = Arc::clone(&counter);
114        debouncer.call(move || {
115            async move {
116                let mut num = counter_clone.lock().await;
117                *num += 1;
118            }
119        }).await;
120    
121        let counter_clone = Arc::clone(&counter);
122        debouncer.call(move || {
123            async move {
124                let mut num = counter_clone.lock().await;
125                *num += 1;
126            }
127        }).await;
128    
129        for _ in 0..5 {
130            let counter_clone = Arc::clone(&counter);
131            debouncer.call(move || {
132                async move {
133                    let mut num = counter_clone.lock().await;
134                    *num += 1;
135                }
136            }).await;
137            tokio::time::sleep(Duration::from_millis(200)).await;
138        }
139    
140        tokio::time::sleep(Duration::from_secs(2)).await;
141    
142        let final_value = *counter.lock().await;
143        assert_eq!(final_value, 5, "The final call should be executed every time.");
144    }
145}