state management
This commit is contained in:
+11
-6
@@ -18,20 +18,24 @@ fn main() {
|
||||
}
|
||||
|
||||
fn app(states: Arc<StateManager>) {
|
||||
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(20);
|
||||
let my_state = states.use_state(String::new());
|
||||
|
||||
screen
|
||||
.draw(Rect(0xffffff))
|
||||
.component(Transform::center().dimensions(30, 3));
|
||||
|
||||
screen
|
||||
.draw(format!("Type quit to quit {}", my_state.get()))
|
||||
.draw(format!(
|
||||
"Type exit to exit\nMy-State: {}",
|
||||
my_state.get().trim()
|
||||
))
|
||||
.component(Transform::new().bottom().margin(0, -1));
|
||||
|
||||
screen
|
||||
@@ -41,10 +45,11 @@ fn app(states: Arc<StateManager>) {
|
||||
events.on(
|
||||
move |events, event: Box<InputKeyPress>| match event.1.code {
|
||||
crossterm::event::KeyCode::Enter => {
|
||||
my_state.set(my_state.get() + 10);
|
||||
// if event.0 == "quit" {
|
||||
// events.dispatch(Close);
|
||||
// }
|
||||
my_state.set(my_state.get() + &format!("{}\n", event.0));
|
||||
if event.0 == "exit" {
|
||||
events.dispatch(Close);
|
||||
}
|
||||
my_state.update();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
||||
+68
-14
@@ -1,28 +1,82 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{
|
||||
any::Any,
|
||||
collections::HashMap,
|
||||
marker::PhantomData,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
pub struct StateManager(fn(Arc<StateManager>));
|
||||
/// ---------- public API ----------
|
||||
|
||||
pub struct State<S>(Arc<StateManager>, Arc<Mutex<S>>);
|
||||
pub struct StateManager {
|
||||
recall: fn(Arc<StateManager>),
|
||||
store: Mutex<HashMap<usize, Box<dyn Any + Send + Sync>>>,
|
||||
cursor: Mutex<usize>,
|
||||
}
|
||||
|
||||
pub struct State<S> {
|
||||
manager: Arc<StateManager>,
|
||||
id: usize,
|
||||
_pd: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl StateManager {
|
||||
pub fn new(recall: fn(Arc<StateManager>)) -> Arc<StateManager> {
|
||||
Arc::new(StateManager(recall))
|
||||
pub fn new(recall: fn(Arc<StateManager>)) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
recall,
|
||||
store: Mutex::new(HashMap::new()),
|
||||
cursor: Mutex::new(0),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn use_state<S>(self: Arc<Self>, state: S) -> State<S> {
|
||||
State(self.clone(), Arc::new(Mutex::new(state)))
|
||||
/// 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<S: 'static + Send + Sync>(self: &Arc<Self>, initial: S) -> State<S> {
|
||||
// `slot` == position of this call in the render
|
||||
let mut cur = self.cursor.lock().unwrap();
|
||||
let slot = *cur;
|
||||
*cur += 1;
|
||||
|
||||
// Insert the initial value only the first time we see this slot
|
||||
let mut store = self.store.lock().unwrap();
|
||||
store
|
||||
.entry(slot)
|
||||
.or_insert_with(|| Box::new(Mutex::new(initial)));
|
||||
|
||||
State {
|
||||
manager: Arc::clone(self),
|
||||
id: slot,
|
||||
_pd: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> State<S> {
|
||||
pub fn set(&self, to: S) {
|
||||
*self.1.lock().unwrap() = to;
|
||||
(self.0 .0)(self.0.clone())
|
||||
impl<S: 'static + Clone + Send + Sync> State<S> {
|
||||
pub fn get(&self) -> S {
|
||||
let store = self.manager.store.lock().unwrap();
|
||||
let x = store[&self.id]
|
||||
.downcast_ref::<Mutex<S>>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.clone();
|
||||
x
|
||||
}
|
||||
|
||||
pub fn set(&self, val: S) {
|
||||
{
|
||||
let store = self.manager.store.lock().unwrap();
|
||||
*store[&self.id]
|
||||
.downcast_ref::<Mutex<S>>()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap() = val;
|
||||
}
|
||||
}
|
||||
|
||||
impl State<i32> {
|
||||
pub fn get(&self) -> i32 {
|
||||
*self.1.lock().unwrap()
|
||||
pub fn update(&self) {
|
||||
(self.manager.recall)(Arc::clone(&self.manager));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user