use std::sync::{Arc, Mutex};
type Listener<T> = Box<dyn Fn(&T)>;
pub struct ValueNotifier<T> {
value: Arc<Mutex<T>>,
listeners: Arc<Mutex<Vec<Listener<T>>>>,
}
impl<T> ValueNotifier<T>
where
T: Clone,
{
pub fn new(initial_value: T) -> Self {
Self {
value: Arc::new(Mutex::new(initial_value)),
listeners: Arc::new(Mutex::new(Vec::new())),
}
}
pub fn get(&self) -> T {
self.value.lock().unwrap().clone()
}
pub fn set(&self, new_value: T) {
{
let mut value = self.value.lock().unwrap();
*value = new_value;
}
self.notify_listeners();
}
pub fn update<F>(&self, updater: F)
where
F: FnOnce(&mut T),
{
{
let mut value = self.value.lock().unwrap();
updater(&mut *value);
}
self.notify_listeners();
}
pub fn add_listener<F>(&self, listener: F)
where
F: Fn(&T) + 'static,
{
let mut listeners = self.listeners.lock().unwrap();
listeners.push(Box::new(listener));
}
fn notify_listeners(&self) {
let value = self.value.lock().unwrap();
let listeners = self.listeners.lock().unwrap();
for listener in listeners.iter() {
listener(&*value);
}
}
pub fn clear_listeners(&self) {
let mut listeners = self.listeners.lock().unwrap();
listeners.clear();
}
pub fn listener_count(&self) -> usize {
self.listeners.lock().unwrap().len()
}
}
impl<T> Clone for ValueNotifier<T> {
fn clone(&self) -> Self {
Self {
value: Arc::clone(&self.value),
listeners: Arc::clone(&self.listeners),
}
}
}
impl<T> std::fmt::Debug for ValueNotifier<T>
where
T: std::fmt::Debug + Clone,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ValueNotifier")
.field("value", &self.get())
.field("listener_count", &self.listener_count())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
#[test]
fn test_value_notifier_basic() {
let notifier = ValueNotifier::new(10);
assert_eq!(notifier.get(), 10);
notifier.set(20);
assert_eq!(notifier.get(), 20);
}
#[test]
fn test_value_notifier_listener() {
let notifier = ValueNotifier::new(0);
let captured = Arc::new(RefCell::new(0));
let c = captured.clone();
notifier.add_listener(move |value| {
*c.borrow_mut() = *value;
});
notifier.set(42);
assert_eq!(*captured.borrow(), 42);
notifier.set(100);
assert_eq!(*captured.borrow(), 100);
}
#[test]
fn test_value_notifier_multiple_listeners() {
let notifier = ValueNotifier::new(0);
let captured1 = Arc::new(RefCell::new(0));
let captured2 = Arc::new(RefCell::new(0));
let c1 = captured1.clone();
notifier.add_listener(move |value| {
*c1.borrow_mut() = *value;
});
let c2 = captured2.clone();
notifier.add_listener(move |value| {
*c2.borrow_mut() = *value * 2;
});
notifier.set(10);
assert_eq!(*captured1.borrow(), 10);
assert_eq!(*captured2.borrow(), 20);
}
#[test]
fn test_value_notifier_update() {
let notifier = ValueNotifier::new(5);
notifier.update(|v| *v += 10);
assert_eq!(notifier.get(), 15);
notifier.update(|v| *v *= 2);
assert_eq!(notifier.get(), 30);
}
#[test]
fn test_value_notifier_clear_listeners() {
let notifier = ValueNotifier::new(0);
let captured = Arc::new(RefCell::new(0));
let c = captured.clone();
notifier.add_listener(move |value| {
*c.borrow_mut() = *value;
});
notifier.set(10);
assert_eq!(*captured.borrow(), 10);
notifier.clear_listeners();
notifier.set(20);
assert_eq!(*captured.borrow(), 10);
}
#[test]
fn test_value_notifier_listener_count() {
let notifier = ValueNotifier::new(0);
assert_eq!(notifier.listener_count(), 0);
notifier.add_listener(|_| {});
assert_eq!(notifier.listener_count(), 1);
notifier.add_listener(|_| {});
assert_eq!(notifier.listener_count(), 2);
notifier.clear_listeners();
assert_eq!(notifier.listener_count(), 0);
}
#[test]
fn test_value_notifier_clone() {
let notifier1 = ValueNotifier::new(10);
let notifier2 = notifier1.clone();
notifier1.set(20);
assert_eq!(notifier2.get(), 20);
}
#[test]
fn test_value_notifier_string() {
let notifier = ValueNotifier::new(String::from("Hello"));
let captured = Arc::new(RefCell::new(String::new()));
let c = captured.clone();
notifier.add_listener(move |value| {
*c.borrow_mut() = value.clone();
});
notifier.set(String::from("World"));
assert_eq!(*captured.borrow(), "World");
}
}