use std::{
sync::{atomic::AtomicBool, Arc, Mutex},
thread::{self, JoinHandle},
time::Duration,
};
pub struct Watcher<T: PartialEq + Send + 'static> {
value: Arc<Mutex<T>>,
changed: Arc<Mutex<bool>>,
handle: Option<JoinHandle<()>>,
shutdown: Arc<Mutex<AtomicBool>>,
}
impl<T: PartialEq + Send + Clone + 'static> Watcher<T> {
pub fn new(initial_value: T, poll_delay_ms: u64, shutdown: Arc<Mutex<AtomicBool>>) -> Self {
let value = Arc::new(Mutex::new(initial_value));
let changed = Arc::new(Mutex::new(false));
let value_watch = value.clone();
let changed_watch = changed.clone();
let shutdown = Arc::clone(&shutdown);
let shutdown2 = Arc::clone(&shutdown);
let handle = thread::spawn(move || {
let mut last_val = value_watch.lock().unwrap().clone();
loop {
{
let lock = shutdown.lock().unwrap();
if lock.load(std::sync::atomic::Ordering::Relaxed) {
break;
}
}
let current_val = value_watch.lock().unwrap().clone();
if current_val != last_val {
*changed_watch.lock().unwrap() = true;
last_val = current_val;
}
thread::sleep(Duration::from_millis(poll_delay_ms));
}
});
Self {
value,
changed,
handle: Some(handle),
shutdown: shutdown2,
}
}
pub fn set_value(&self, new_value: T) {
let mut value = self.value.lock().unwrap();
if *value != new_value {
*value = new_value;
*self.changed.lock().unwrap() = true;
}
}
pub fn get_value(&self) -> T
where T: Clone {
self.value.lock().unwrap().clone()
}
pub fn has_changed(&self) -> bool {
*self.changed.lock().unwrap()
}
pub fn reset_changed(&self) {
*self.changed.lock().unwrap() = false;
}
}
impl<T: PartialEq + Send + 'static> Watcher<T> {
pub fn shutdown_thread(&mut self) {
self.shutdown.lock().unwrap().store(true, std::sync::atomic::Ordering::Relaxed);
}
}
impl<T: PartialEq + Send + 'static> Drop for Watcher<T> {
fn drop(&mut self) {
self.shutdown_thread();
if let Some(handle) = self.handle.take() {
handle.join().ok();
}
}
}