1use std::sync::mpsc::{Receiver, Sender};
2
3use ratatui::Frame;
4
5use crate::{component::Component, events::Message, listeners::DrawContext};
6
7pub struct Runtime {
8 root: Component,
9}
10
11impl Runtime {
12 pub fn new(root: Component) -> Self {
13 Self { root }
14 }
15
16 pub fn draw(&self, frame: &mut Frame) {
17 let mut ctx = DrawContext {
18 rect: frame.area(),
19 buf: frame.buffer_mut(),
20 };
21
22 self.root.render(&mut ctx)
23 }
24
25 pub fn update(&mut self, msg: Message) {
26 self.root.update(&msg)
27 }
28
29 pub fn should_exit(&self) -> bool {
30 false
31 }
32}
33
34pub struct EventSource {
35 tx: Sender<Message>,
36 rx: Receiver<Message>,
37}
38
39impl Default for EventSource {
40 fn default() -> Self {
41 let (tx, rx) = std::sync::mpsc::channel();
42 Self { tx, rx }
43 }
44}
45
46impl EventSource {
47 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn recv(&self) -> Message {
52 self.rx.recv().unwrap()
53 }
54
55 pub fn subscribe(&self, producer: &impl EventProducer) {
56 producer.spawn(self.tx.clone());
57 }
58}
59
60pub trait EventProducer {
61 fn subscribe(tx: Sender<Message>);
62
63 fn spawn(&self, tx: Sender<Message>) {
64 std::thread::spawn(move || {
65 Self::subscribe(tx);
66 });
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use std::{any::Any, cell::RefCell, rc::Rc};
73
74 use crate::{
75 component::Component,
76 events::{Message, Tick},
77 runtime::Runtime,
78 };
79
80 #[test]
81 fn test_event_listen() {
82 let mut root = Component::default();
83 let state = Rc::new(RefCell::new(false));
84 let state_c = state.clone();
85
86 root.listen::<Tick>(move |_| {
87 *state_c.borrow_mut() = true;
88 });
89
90 let mut runtime = Runtime::new(root);
91 let event = Tick {};
92 let message = Message {
93 type_id: event.type_id(),
94 event: Box::new(event),
95 };
96
97 assert!(!*state.borrow());
98
99 runtime.update(message);
100
101 assert!(*state.borrow());
102 }
103}