thedes_tui_core/screen/
device.rs

1use std::fmt;
2
3use thedes_async_util::dyn_async_trait;
4use thiserror::Error;
5use tokio::io;
6
7use crate::{color::Color, geometry::CoordPair};
8
9pub mod native;
10pub mod null;
11
12#[cfg(feature = "testing")]
13pub mod mock;
14
15#[derive(Debug, Error)]
16pub enum Error {
17    #[error(transparent)]
18    Io(#[from] io::Error),
19    #[error("Failed to format command")]
20    Fmt(
21        #[from]
22        #[source]
23        fmt::Error,
24    ),
25    #[error("Invalid command: {:#?}", .0)]
26    InvalidCommand(Command),
27    #[error(transparent)]
28    Custom(#[from] Box<dyn std::error::Error + Send + Sync>),
29}
30
31#[derive(Debug, Clone, PartialEq)]
32pub enum Command {
33    Enter,
34    Leave,
35    Clear,
36    ResetBackground,
37    ResetForeground,
38    SetBackground(Color),
39    SetForeground(Color),
40    ShowCursor,
41    HideCursor,
42    MoveCursor(CoordPair),
43    Write(char),
44}
45
46#[dyn_async_trait]
47pub trait ScreenDevice: fmt::Debug + Send + Sync {
48    fn send_raw(
49        &mut self,
50        commands: &mut (dyn Iterator<Item = Command> + Send + Sync),
51    ) -> Result<(), Error>;
52
53    async fn flush(&mut self) -> Result<(), Error>;
54
55    fn blocking_get_size(&mut self) -> Result<CoordPair, Error>;
56}
57
58#[dyn_async_trait]
59impl<'a, D> ScreenDevice for &'a mut D
60where
61    D: ScreenDevice + ?Sized,
62{
63    fn send_raw(
64        &mut self,
65        commands: &mut (dyn Iterator<Item = Command> + Send + Sync),
66    ) -> Result<(), Error> {
67        (**self).send_raw(commands)
68    }
69
70    async fn flush(&mut self) -> Result<(), Error> {
71        (**self).flush().await
72    }
73
74    fn blocking_get_size(&mut self) -> Result<CoordPair, Error> {
75        (**self).blocking_get_size()
76    }
77}
78
79#[dyn_async_trait]
80impl<D> ScreenDevice for Box<D>
81where
82    D: ScreenDevice + ?Sized,
83{
84    fn send_raw(
85        &mut self,
86        commands: &mut (dyn Iterator<Item = Command> + Send + Sync),
87    ) -> Result<(), Error> {
88        (**self).send_raw(commands)
89    }
90
91    async fn flush(&mut self) -> Result<(), Error> {
92        (**self).flush().await
93    }
94
95    fn blocking_get_size(&mut self) -> Result<CoordPair, Error> {
96        (**self).blocking_get_size()
97    }
98}
99
100pub trait ScreenDeviceExt: ScreenDevice {
101    fn send<I>(&mut self, iterable: I) -> Result<(), Error>
102    where
103        I: IntoIterator<Item = Command>,
104        I::IntoIter: Send + Sync,
105    {
106        self.send_raw(&mut iterable.into_iter())
107    }
108}
109
110impl<S> ScreenDeviceExt for S where S: ScreenDevice {}