use std::sync::{Arc, Mutex};
type Listener<T> = Box<dyn Fn(&T) + Send + Sync>;
pub struct LiveData<T> {
value: Arc<Mutex<T>>,
listeners: Arc<Mutex<Vec<Listener<T>>>>,
}
impl<T> LiveData<T>
where
T: Clone + Send + Sync,
{
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();
}
pub fn update<F>(&self, updater: F)
where
F: FnOnce(&mut T),
{
{
let mut value = self.value.lock().unwrap();
updater(&mut *value);
}
self.notify();
}
pub fn observe<F>(&self, observer: F) -> usize
where
F: Fn(&T) + Send + Sync + 'static,
{
let mut listeners = self.listeners.lock().unwrap();
listeners.push(Box::new(observer));
listeners.len() - 1
}
fn notify(&self) {
let value = self.value.lock().unwrap();
let listeners = self.listeners.lock().unwrap();
for listener in listeners.iter() {
listener(&*value);
}
}
pub fn clear_observers(&self) {
let mut listeners = self.listeners.lock().unwrap();
listeners.clear();
}
pub fn observer_count(&self) -> usize {
self.listeners.lock().unwrap().len()
}
}
impl<T> Clone for LiveData<T> {
fn clone(&self) -> Self {
Self {
value: Arc::clone(&self.value),
listeners: Arc::clone(&self.listeners),
}
}
}
impl<T> std::fmt::Debug for LiveData<T>
where
T: std::fmt::Debug + Clone + Send + Sync,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LiveData")
.field("value", &self.get())
.field("observer_count", &self.observer_count())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicI32, Ordering};
#[test]
fn test_live_data_basic() {
let live_data = LiveData::new(10);
assert_eq!(live_data.get(), 10);
live_data.set(20);
assert_eq!(live_data.get(), 20);
}
#[test]
fn test_live_data_observer() {
let live_data = Arc::new(LiveData::new(0));
let counter = Arc::new(AtomicI32::new(0));
let counter_clone = Arc::clone(&counter);
live_data.observe(move |value| {
counter_clone.store(*value, Ordering::SeqCst);
});
live_data.set(42);
assert_eq!(counter.load(Ordering::SeqCst), 42);
live_data.set(100);
assert_eq!(counter.load(Ordering::SeqCst), 100);
}
#[test]
fn test_live_data_multiple_observers() {
let live_data = Arc::new(LiveData::new(0));
let counter1 = Arc::new(AtomicI32::new(0));
let counter2 = Arc::new(AtomicI32::new(0));
let c1 = Arc::clone(&counter1);
live_data.observe(move |value| {
c1.store(*value, Ordering::SeqCst);
});
let c2 = Arc::clone(&counter2);
live_data.observe(move |value| {
c2.store(*value * 2, Ordering::SeqCst);
});
live_data.set(10);
assert_eq!(counter1.load(Ordering::SeqCst), 10);
assert_eq!(counter2.load(Ordering::SeqCst), 20);
}
#[test]
fn test_live_data_update() {
let live_data = LiveData::new(5);
live_data.update(|v| *v += 10);
assert_eq!(live_data.get(), 15);
live_data.update(|v| *v *= 2);
assert_eq!(live_data.get(), 30);
}
#[test]
fn test_live_data_clear_observers() {
let live_data = Arc::new(LiveData::new(0));
let counter = Arc::new(AtomicI32::new(0));
let c = Arc::clone(&counter);
live_data.observe(move |value| {
c.store(*value, Ordering::SeqCst);
});
live_data.set(10);
assert_eq!(counter.load(Ordering::SeqCst), 10);
live_data.clear_observers();
live_data.set(20);
assert_eq!(counter.load(Ordering::SeqCst), 10);
}
#[test]
fn test_live_data_observer_count() {
let live_data = LiveData::new(0);
assert_eq!(live_data.observer_count(), 0);
live_data.observe(|_| {});
assert_eq!(live_data.observer_count(), 1);
live_data.observe(|_| {});
assert_eq!(live_data.observer_count(), 2);
live_data.clear_observers();
assert_eq!(live_data.observer_count(), 0);
}
#[test]
fn test_live_data_clone() {
let live_data1 = Arc::new(LiveData::new(10));
let live_data2 = live_data1.clone();
live_data1.set(20);
assert_eq!(live_data2.get(), 20);
}
#[test]
fn test_live_data_string() {
let live_data = Arc::new(LiveData::new(String::from("Hello")));
let result = Arc::new(Mutex::new(String::new()));
let r = Arc::clone(&result);
live_data.observe(move |value| {
*r.lock().unwrap() = value.clone();
});
live_data.set(String::from("World"));
assert_eq!(*result.lock().unwrap(), "World");
}
}