use core::any::Any;
pub trait BindingListener: Any + Send {
fn on_value_changed(&mut self, key: &str);
}
pub type BoxedListener = Box<dyn BindingListener>;
pub struct FnListener<F: FnMut(&str) + Send> {
f: F,
}
impl<F: FnMut(&str) + Send + 'static> FnListener<F> {
pub fn new(f: F) -> Self {
Self { f }
}
}
impl<F: FnMut(&str) + Send + 'static> BindingListener for FnListener<F> {
fn on_value_changed(&mut self, key: &str) {
(self.f)(key);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::compat::Mutex;
use alloc::sync::Arc;
use core::sync::atomic::{AtomicI32, Ordering};
#[test]
fn test_fn_listener_invocation() {
let invoked_key = Arc::new(Mutex::new(String::new()));
let ik = invoked_key.clone();
let mut listener = FnListener::new(move |key| {
*ik.lock().unwrap() = key.to_string();
});
listener.on_value_changed("test_key");
assert_eq!(*invoked_key.lock().unwrap(), "test_key");
}
#[test]
fn test_fn_listener_multiple_calls() {
let count = Arc::new(AtomicI32::new(0));
let c = count.clone();
let mut listener = FnListener::new(move |_| {
c.fetch_add(1, Ordering::SeqCst);
});
listener.on_value_changed("a");
listener.on_value_changed("b");
listener.on_value_changed("c");
assert_eq!(count.load(Ordering::SeqCst), 3);
}
#[test]
fn test_boxed_listener_send() {
let listener: BoxedListener = Box::new(FnListener::new(|_| {}));
let handle = std::thread::spawn(move || {
let _ = listener;
});
handle.join().unwrap();
}
}