1use std::time::{Duration, Instant};
2
3use ratatui::prelude::Backend;
4
5use crate::{
6 canvas::Canvas, component::Component, context::Context, driver::Driver, error::RuntimeError,
7 transport::EventSource,
8};
9
10pub struct Runtime {
11 root: Component,
12 context: Context,
13}
14
15impl Runtime {
16 pub fn new(root: Component) -> Self {
17 let context = Context::default();
18 Self { root, context }
19 }
20
21 pub fn draw<D>(&self, driver: &mut D) -> Result<(), RuntimeError>
22 where
23 D: Driver,
24 RuntimeError: From<<D::Backend as Backend>::Error>,
25 {
26 let terminal = driver.terminal();
27 terminal.draw(|f| {
28 let mut canvas = Canvas::new(f.area(), f.buffer_mut());
29 self.root.render(&mut canvas);
30 })?;
31 Ok(())
32 }
33
34 pub fn update(&mut self, source: &EventSource) {
35 let deadline = Instant::now() + Duration::from_millis(16);
36 let msg = source.recv();
37
38 self.root.update(&msg, &mut self.context);
39
40 while Instant::now() < deadline {
41 let msg = source.recv_timeout(deadline - Instant::now());
42 if let Some(msg) = msg {
43 self.root.update(&msg, &mut self.context);
44 }
45 }
46 }
47
48 pub fn should_exit(&self) -> bool {
49 self.context.shutdown_requested
50 }
51}