diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..e44eadd --- /dev/null +++ b/src/state.rs @@ -0,0 +1,97 @@ +use std::{ + fmt::{Debug, Display, Formatter, Result as FmtResult}, + ops::{Deref, DerefMut}, + sync::{Arc, Mutex, MutexGuard}, +}; + +#[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 + } +} + +pub trait DependencyHandler: std::fmt::Debug + Send + Sync { + fn add(&self); + fn check(&self) -> bool; +}