1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use crate::buffer::{BufferGet, EventBuffer, MixedEventBuffer, State};
use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
use std::time::Duration;

struct DebouncerThread<B> {
    mutex: Arc<Mutex<B>>,
    thread: JoinHandle<()>,
}

impl<B> DebouncerThread<B> {
    fn new<F, T>(buffer: B, f: F) -> Self
    where
        B: BufferGet<T> + Send + 'static,
        F: Fn(T) -> () + Send + 'static,
        T: Send + 'static,
    {
        let mutex = Arc::new(Mutex::new(buffer));
        let mutex_clone = mutex.clone();
        let thread = thread::spawn(move || loop {
            let state = mutex_clone.lock().unwrap().get();
            match state {
                State::Empty => thread::park(),
                State::Wait(duration) => thread::sleep(duration),
                State::Ready(data) => f(data),
            }
        });
        Self { mutex, thread }
    }
}

/// Threaded debouncer wrapping `EventBuffer`. Accepts a common delay and a
/// callback function which is going to be called by a background thread with
/// debounced events.
pub struct EventDebouncer<T>(DebouncerThread<EventBuffer<T>>);

impl<T: PartialEq> EventDebouncer<T> {
    pub fn new<F>(delay: Duration, f: F) -> Self
    where
        F: Fn(T) -> () + Send + 'static,
        T: Send + 'static,
    {
        Self(DebouncerThread::new(EventBuffer::new(delay), f))
    }

    pub fn put(&self, data: T) {
        self.0.mutex.lock().unwrap().put(data);
        self.0.thread.thread().unpark();
    }
}

/// Threaded debouncer wrapping `MixedEventBuffer`. Accepts a callback function
/// which is going to be called by a background thread with debounced events.
/// The delay is specified separately for each event as an argument to `.put()`.
pub struct MixedEventDebouncer<T>(DebouncerThread<MixedEventBuffer<T>>);

impl<T: Eq> MixedEventDebouncer<T> {
    pub fn new<F>(f: F) -> Self
    where
        F: Fn(T) -> () + Send + 'static,
        T: Send + 'static,
    {
        Self(DebouncerThread::new(MixedEventBuffer::new(), f))
    }

    pub fn put(&self, data: T, delay: Duration) {
        self.0.mutex.lock().unwrap().put(data, delay);
        self.0.thread.thread().unpark();
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn event_debouncer() {
        let result = Arc::new(Mutex::new(vec![]));
        let result_clone = Arc::clone(&result);
        let debouncer = EventDebouncer::new(Duration::from_millis(10), move |s: String| {
            result_clone.lock().unwrap().push(s);
        });
        debouncer.put(String::from("Test"));
        debouncer.put(String::from("Test"));
        thread::sleep(Duration::from_millis(20));
        assert_eq!(result.lock().unwrap().as_slice(), [String::from("Test")]);
    }

    #[test]
    fn mixed_event_debouncer() {
        let result = Arc::new(Mutex::new(vec![]));
        let result_clone = Arc::clone(&result);
        let debouncer = MixedEventDebouncer::new(move |s: String| {
            result_clone.lock().unwrap().push(s);
        });
        debouncer.put(String::from("Test"), Duration::from_millis(10));
        debouncer.put(String::from("Test"), Duration::from_millis(10));
        thread::sleep(Duration::from_millis(20));
        assert_eq!(result.lock().unwrap().as_slice(), [String::from("Test")]);
    }
}