1use endbasic_std::console::{SizeInPixels, RGB};
19use std::convert::TryFrom;
20use std::io;
21
22mod buffered;
23mod font8;
24
25pub(crate) use buffered::BufferedLcd;
26
27pub(crate) trait AsByteSlice {
28 fn as_slice(&self) -> &[u8];
29}
30
31#[derive(Clone, Copy)]
33pub(crate) struct RGB565Pixel(pub(crate) [u8; 2]);
34
35impl AsByteSlice for RGB565Pixel {
36 fn as_slice(&self) -> &[u8] {
37 &self.0
38 }
39}
40
41#[cfg(test)]
43#[derive(Clone, Copy)]
44pub(crate) struct RGB888Pixel(pub(crate) [u8; 3]);
45
46#[cfg(test)]
47impl AsByteSlice for RGB888Pixel {
48 fn as_slice(&self) -> &[u8] {
49 &self.0
50 }
51}
52
53pub(crate) trait Lcd {
55 type Pixel: AsByteSlice + Copy;
57
58 fn info(&self) -> (LcdSize, usize);
60
61 fn encode(&self, rgb: RGB) -> Self::Pixel;
63
64 fn set_data(&mut self, x1y1: LcdXY, x2y2: LcdXY, data: &[u8]) -> io::Result<()>;
67}
68
69#[derive(Clone, Copy)]
71#[cfg_attr(test, derive(Debug, PartialEq))]
72pub(crate) struct LcdXY {
73 pub(crate) x: usize,
74 pub(crate) y: usize,
75}
76
77#[derive(Clone, Copy)]
79#[cfg_attr(test, derive(Debug, PartialEq))]
80pub(crate) struct LcdSize {
81 pub(crate) width: usize,
82 pub(crate) height: usize,
83}
84
85impl LcdSize {
86 fn between(x1y1: LcdXY, x2y2: LcdXY) -> Self {
88 debug_assert!(x2y2.x >= x1y1.x);
89 debug_assert!(x2y2.y >= x1y1.y);
90 Self { width: x2y2.x - x1y1.x + 1, height: x2y2.y - x1y1.y + 1 }
91 }
92
93 fn new_buffer(&self, stride: usize) -> Vec<u8> {
96 Vec::with_capacity(self.width * self.height * stride)
97 }
98}
99
100impl From<LcdSize> for SizeInPixels {
101 fn from(value: LcdSize) -> Self {
102 Self::new(
103 u16::try_from(value.width).expect("Must fit"),
104 u16::try_from(value.height).expect("Must fit"),
105 )
106 }
107}
108
109pub(crate) fn to_xy_size(x1y1: LcdXY, x2y2: LcdXY) -> (LcdXY, LcdSize) {
111 let x1 = std::cmp::min(x1y1.x, x2y2.x);
112 let y1 = std::cmp::min(x1y1.y, x2y2.y);
113
114 let x2 = std::cmp::max(x1y1.x, x2y2.x);
115 let y2 = std::cmp::max(x1y1.y, x2y2.y);
116
117 (LcdXY { x: x1, y: y1 }, LcdSize { width: x2 + 1 - x1, height: y2 + 1 - y1 })
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 fn xy(x: usize, y: usize) -> LcdXY {
126 LcdXY { x, y }
127 }
128
129 fn size(width: usize, height: usize) -> LcdSize {
131 LcdSize { width, height }
132 }
133
134 #[test]
135 fn test_lcdsize_between_one_pixel() {
136 assert_eq!(size(1, 1), LcdSize::between(xy(15, 16), xy(15, 16)));
137 }
138
139 #[test]
140 fn test_lcdsize_between_rect() {
141 assert_eq!(size(4, 5), LcdSize::between(xy(10, 25), xy(13, 29)));
142 }
143
144 #[test]
145 fn test_lcdsize_new_buffer() {
146 let buffer = size(10, 20).new_buffer(3);
147 assert_eq!(10 * 20 * 3, buffer.capacity());
148 }
149
150 #[test]
151 fn test_to_xy_size_one_pixel() {
152 assert_eq!(
153 (LcdXY { x: 10, y: 20 }, LcdSize { width: 1, height: 1 }),
154 to_xy_size(xy(10, 20), xy(10, 20))
155 );
156 }
157
158 #[test]
159 fn test_to_xy_size_rect() {
160 assert_eq!(
161 (LcdXY { x: 10, y: 20 }, LcdSize { width: 5, height: 7 }),
162 to_xy_size(xy(10, 20), xy(14, 26))
163 );
164 }
165}