From 551a062021d2fb5e278f2a814c86b5d4284ec7ca Mon Sep 17 00:00:00 2001 From: Leo dev Date: Sat, 28 Jun 2025 01:57:36 +0200 Subject: [PATCH] better state management --- src/events.rs | 13 +++++++++++-- src/main.rs | 47 ++++++++++++++++++----------------------------- src/state.rs | 27 ++++++++++++++++++--------- 3 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/events.rs b/src/events.rs index 7790d10..052f00e 100644 --- a/src/events.rs +++ b/src/events.rs @@ -4,7 +4,7 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::event; +use crate::{event, state::StateManager}; event!(Close); @@ -21,15 +21,16 @@ impl std::fmt::Debug for EventHandlerFn { } } -#[derive(Debug)] pub struct EventManager { handlers: HashMap>, + states: Option>, } impl EventManager { pub fn new() -> EventManager { EventManager { handlers: HashMap::new(), + states: None, } } @@ -37,10 +38,14 @@ impl EventManager { &mut self, mut f: F, ) { + let states = self.states.clone(); let wrapper = Arc::new(Mutex::new( move |e: &mut EventManager, evt: Box| { if let Ok(concrete) = evt.as_any().downcast::() { f(e, concrete); + if let Some(states) = &states { + states.clone().flush(); + } } }, )) as Arc)>>; @@ -68,4 +73,8 @@ impl EventManager { std::process::exit(0); } } + + pub fn set_state_manager(&mut self, states: Arc) { + self.states = Some(states); + } } diff --git a/src/main.rs b/src/main.rs index 21af7e1..d30269f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,8 @@ use std::sync::Arc; +use crossterm::event::KeyEvent; use osui::{ - element::{ - input::{Input, InputKeyPress}, - rect::Rect, - }, + element::rect::Rect, events::{Close, EventManager}, extensions::{keypress::KeyPressExtension, tick_rate::TickRate, ExtensionManager}, state::StateManager, @@ -18,42 +16,33 @@ fn main() { } fn app(states: Arc) { - states.begin(); let mut screen = Screen::new(); let mut extensions = ExtensionManager::new(); let mut events = EventManager::new(); - extensions.add(KeyPressExtension); - extensions.add(TickRate(255)); - let my_state = states.use_state(String::new()); + extensions.add(TickRate(50)); + extensions.add(KeyPressExtension); + + events.set_state_manager(states.clone()); + + let count = states.use_state(0); screen .draw(Rect(0xffffff)) .component(Transform::center().dimensions(30, 3)); screen - .draw(format!( - "Type exit to exit\nMy-State: {}", - my_state.get().trim() - )) - .component(Transform::new().bottom().margin(0, -1)); + .draw(format!("Count: {}", count.get())) + .component(Transform::center()); - screen - .draw(Input::new()) - .component(Transform::new().bottom()); - - events.on( - move |events, event: Box| match event.1.code { - crossterm::event::KeyCode::Enter => { - my_state.set(my_state.get() + &format!("{}\n", event.0)); - if event.0 == "exit" { - events.dispatch(Close); - } - my_state.update(); - } - _ => {} - }, - ); + events.on(move |events, event: Box| match event.code { + crossterm::event::KeyCode::Enter => { + count.set(count.get() + 1); + } + _ => { + events.dispatch(Close); + } + }); screen.run(&mut events, &mut extensions).unwrap(); } diff --git a/src/state.rs b/src/state.rs index 21ad6b0..27bd17c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -11,6 +11,7 @@ pub struct StateManager { recall: fn(Arc), store: Mutex>>, cursor: Mutex, + dirty: Mutex, } pub struct State { @@ -25,14 +26,10 @@ impl StateManager { recall, store: Mutex::new(HashMap::new()), cursor: Mutex::new(0), + dirty: Mutex::new(false), }) } - /// Call this at the very top of every “render” before doing any `use_state` calls - pub fn begin(&self) { - *self.cursor.lock().unwrap() = 0; - } - pub fn use_state(self: &Arc, initial: S) -> State { // `slot` == position of this call in the render let mut cur = self.cursor.lock().unwrap(); @@ -51,9 +48,24 @@ impl StateManager { _pd: PhantomData, } } + + pub fn flush(self: Arc) { + let mut d = self.dirty.lock().unwrap(); + if *d { + *d = false; + drop(d); + + *self.cursor.lock().unwrap() = 0; + (self.recall)(self) + } + } } impl State { + pub fn dirty(&self) { + *self.manager.dirty.lock().unwrap() = true; + } + pub fn get(&self) -> S { let store = self.manager.store.lock().unwrap(); let x = store[&self.id] @@ -74,9 +86,6 @@ impl State { .lock() .unwrap() = val; } - } - - pub fn update(&self) { - (self.manager.recall)(Arc::clone(&self.manager)); + self.dirty(); } }