/
delayed_counter.rs
96 lines (85 loc) · 2.88 KB
/
delayed_counter.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::{future::Future, io::stdout, pin::Pin, time::Duration};
use fiadtui::{
event::{Event, KeyCode, KeyEvent, KeyEventKind},
App, EventLoop, Message,
};
use futures::executor::block_on;
use ratatui::widgets::Paragraph;
use tokio::task::spawn_blocking;
#[derive(Debug)]
enum CounterMessage {
Increment,
Decrement,
DelayedUpdate(i32),
}
#[derive(Default)]
struct CounterApp {
pending_update: bool,
counter: i32,
}
impl App for CounterApp {
type AppMessage = CounterMessage;
fn draw(&mut self, frame: &mut ratatui::Frame) {
frame.render_widget(Paragraph::new(self.counter.to_string()), frame.size());
}
fn handle_event(&self, event: Event) -> Option<Message<CounterMessage>> {
match event {
Event::Key(KeyEvent {
code: KeyCode::Char('+'),
kind: KeyEventKind::Press,
..
}) => Some(CounterMessage::Increment.into()),
Event::Key(KeyEvent {
code: KeyCode::Char('-'),
kind: KeyEventKind::Press,
..
}) => Some(CounterMessage::Decrement.into()),
_ => None,
}
}
// Need a concrete future type here, as multiple async blocks
// have different types.
fn handle_message(
&mut self,
message: Self::AppMessage,
) -> Option<Pin<Box<dyn Future<Output = Message<Self::AppMessage>> + Send + 'static>>> {
match message {
CounterMessage::Increment => {
if self.pending_update {
return None;
}
let future_value = self.counter + 1;
self.pending_update = true;
Some(Box::pin(async move {
let _ = tokio::time::sleep(Duration::from_secs(1)).await;
CounterMessage::DelayedUpdate(future_value).into()
}))
}
CounterMessage::Decrement => {
if self.pending_update {
return None;
}
let future_value = self.counter - 1;
self.pending_update = true;
Some(Box::pin(async move {
let _ = tokio::time::sleep(Duration::from_secs(1)).await;
CounterMessage::DelayedUpdate(future_value).into()
}))
}
CounterMessage::DelayedUpdate(v) => {
self.pending_update = false;
self.counter = v;
None
}
}
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
let counter = CounterApp::default();
let mut event_loop = EventLoop::new(stdout()).expect("Could not create event loop");
spawn_blocking(move || block_on(event_loop.event_loop(counter, 60)))
.await
.expect("Could not spawn event loop")
.expect("Error during event loop");
}