From 4d2f0d7b9d0caadb1a1ceead658d42532b7985f7 Mon Sep 17 00:00:00 2001 From: Leo dev Date: Thu, 20 Nov 2025 17:17:18 +0100 Subject: [PATCH] State management --- examples/hello_world.rs | 16 +++++-- src/lib.rs | 1 + src/state.rs | 100 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 src/state.rs diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 2bed746..9bcc3d8 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,4 +1,4 @@ -use osui::{Context, Event, Node}; +use osui::{state::use_state, Context, Event, Node}; pub struct ClickEvent; @@ -10,10 +10,18 @@ impl Event for ClickEvent { fn app(cx: &mut Context) -> Node { // Hooks - cx.event(|_: &ClickEvent| {}); + let count = use_state(0); + cx.event({ + let count = count.clone(); + move |_: &ClickEvent| { + **count.get() += 1; + } + }); - Box::new(|renderer| { - renderer.draw_text("Hello, World!", 0, 0).unwrap(); + Box::new(move |renderer| { + renderer + .draw_text(&format!("Count: {count}"), 0, 0) + .unwrap(); }) } diff --git a/src/lib.rs b/src/lib.rs index a316c61..c1ecc8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use crate::renderer::{OsuiRenderer, Renderer}; pub mod error; pub mod renderer; +pub mod state; pub use error::Result; diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..aac8756 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,100 @@ +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 + } +} \ No newline at end of file