use std::{ fmt::{Debug, Display, Formatter, Result as FmtResult}, ops::{Deref, DerefMut}, sync::{Arc, Mutex, MutexGuard}, }; /// Trait for tracking dependencies and reactivity. pub trait DependencyHandler: std::fmt::Debug + Send + Sync { /// Called when a dependent is registered. fn add(&self); /// Returns `true` if the state has changed since the last check. fn check(&self) -> bool; } #[derive(Debug, Clone)] pub struct State { inner: Arc>>, } #[derive(Debug)] pub struct Inner { value: T, dependencies: usize, changed: usize, } pub fn use_state(v: T) -> State { State { inner: Arc::new(Mutex::new(Inner { value: v, dependencies: 0, changed: 0, })), } } impl State { /// Gets the cloned value, recommended for preventing deadlocks pub fn get_dl(&self) -> T { self.inner.lock().unwrap().value.clone() } } impl State { /// Gets a lock on the state for read/write access. pub fn get(&self) -> MutexGuard<'_, Inner> { self.inner.lock().unwrap() } /// Sets the value and marks it as changed. pub fn set(&self, v: T) { let mut inner = self.inner.lock().unwrap(); inner.value = v; inner.changed = inner.dependencies; } /// Marks the state as updated. pub fn update(&self) { let mut inner = self.inner.lock().unwrap(); inner.changed = inner.dependencies; } } impl DependencyHandler for State { fn check(&self) -> bool { let mut inner = self.inner.lock().unwrap(); let i = inner.changed > 0; if i { inner.changed -= 1; } i } fn add(&self) { let mut inner = self.inner.lock().unwrap(); inner.dependencies += 1; } } impl Display for State { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { let inner = self.inner.lock().unwrap(); write!(f, "{}", inner.value) } } impl Deref for Inner { type Target = T; fn deref(&self) -> &Self::Target { &self.value } } impl DerefMut for Inner { fn deref_mut(&mut self) -> &mut Self::Target { self.changed = self.dependencies; &mut self.value } }