Improved state management

This commit is contained in:
2025-11-23 11:10:07 +01:00
parent 8740bbee89
commit b326fc48ed
2 changed files with 57 additions and 55 deletions
+3 -1
View File
@@ -34,7 +34,9 @@ fn app(cx: &Arc<Context>) -> Vec<Node> {
cx.on_event({ cx.on_event({
let count = count.clone(); let count = count.clone();
move |_cx, _event: &KeyPress| { move |_cx, _event: &KeyPress| {
*count.get() += 1; #[allow(unused_mut)]
let mut count = count.get();
*count += 1;
} }
}); });
+54 -54
View File
@@ -1,103 +1,103 @@
use std::{ use std::{
fmt::{Debug, Display, Formatter, Result as FmtResult}, fmt::{Debug, Display, Formatter, Result as FmtResult},
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}, ops::{Deref, DerefMut},
sync::{Arc, Mutex, MutexGuard}, sync::{Arc, Mutex, MutexGuard},
}; };
#[derive(Clone)]
pub struct HookEffect(Arc<Mutex<dyn Fn() + Send + Sync>>);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct State<T> { pub struct State<T> {
inner: Arc<Mutex<T>>, value: Arc<Mutex<T>>,
dependents: Arc<Mutex<Vec<HookEffect>>>,
}
pub struct Inner<'a, T> {
value: MutexGuard<'a, T>,
dependents: Arc<Mutex<Vec<HookEffect>>>,
updated: bool,
} }
pub fn use_state<T>(v: T) -> State<T> { pub fn use_state<T>(v: T) -> State<T> {
State { State {
inner: Arc::new(Mutex::new(v)), value: Arc::new(Mutex::new(v)),
dependents: Arc::new(Mutex::new(Vec::new())),
} }
} }
impl<T: Clone> State<T> { impl<T: Clone> State<T> {
/// Gets the cloned value, recommended for preventing deadlocks /// Gets the cloned value, recommended for preventing deadlocks
pub fn get_dl(&self) -> T { pub fn get_dl(&self) -> T {
self.inner.lock().unwrap().clone() self.value.lock().unwrap().clone()
} }
} }
impl<T> State<T> { impl<T> State<T> {
/// Gets a lock on the state for read/write access. /// Gets a lock on the state for read/write access.
pub fn get(&self) -> MutexGuard<'_, T> { pub fn get(&self) -> Inner<'_, T> {
self.inner.lock().unwrap() Inner {
value: self.value.lock().unwrap(),
dependents: self.dependents.clone(),
updated: false,
}
} }
/// Sets the value and marks it as changed. /// Sets the value and marks it as changed.
pub fn set(&self, v: T) { pub fn set(&self, v: T) {
*self.inner.lock().unwrap() = v; *self.value.lock().unwrap() = v;
self.update();
}
pub fn update(&self) {
for d in self.dependents.lock().unwrap().iter() {
d.call();
}
} }
} }
impl<T: Display> Display for State<T> { impl<T: Display> Display for State<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "{}", self.inner.lock().unwrap()) write!(f, "{}", self.value.lock().unwrap())
} }
} }
impl<T: Add<Output = T> + Clone> Add<T> for State<T> { impl Debug for HookEffect {
type Output = T; fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "HookEffect")
fn add(self, rhs: T) -> Self::Output {
let v = self.inner.lock().unwrap().clone();
v.add(rhs)
} }
} }
impl<T: Sub<Output = T> + Clone> Sub<T> for State<T> { impl HookEffect {
type Output = T; pub fn new<F: Fn() + Send + Sync + 'static>(f: F) -> Self {
Self(Arc::new(Mutex::new(f)))
}
fn sub(self, rhs: T) -> Self::Output { pub fn call(&self) {
let v = self.inner.lock().unwrap().clone(); (self.0.lock().unwrap())()
v.sub(rhs)
} }
} }
impl<T: Mul<Output = T> + Clone> Mul<T> for State<T> { impl<T> Drop for Inner<'_, T> {
type Output = T; fn drop(&mut self) {
if self.updated {
fn mul(self, rhs: T) -> Self::Output { for d in self.dependents.lock().unwrap().iter() {
let v = self.inner.lock().unwrap().clone(); d.call();
v.mul(rhs) }
}
} }
} }
impl<T: Div<Output = T> + Clone> Div<T> for State<T> { impl<T> Deref for Inner<'_, T> {
type Output = T; type Target = T;
fn deref(&self) -> &Self::Target {
fn div(self, rhs: T) -> Self::Output { &self.value
let v = self.inner.lock().unwrap().clone();
v.div(rhs)
} }
} }
// Assign impl<T> DerefMut for Inner<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
impl<T: AddAssign> AddAssign<T> for State<T> { self.updated = true;
fn add_assign(&mut self, rhs: T) { &mut self.value
self.get().add_assign(rhs);
}
}
impl<T: SubAssign> SubAssign<T> for State<T> {
fn sub_assign(&mut self, rhs: T) {
self.get().sub_assign(rhs);
}
}
impl<T: MulAssign> MulAssign<T> for State<T> {
fn mul_assign(&mut self, rhs: T) {
self.get().mul_assign(rhs);
}
}
impl<T: DivAssign> DivAssign<T> for State<T> {
fn div_assign(&mut self, rhs: T) {
self.get().div_assign(rhs);
} }
} }