use crate::console::{RGB, SizeInPixels};
use std::convert::TryFrom;
use std::io;
mod buffered;
pub mod fonts;
pub use buffered::BufferedLcd;
pub trait AsByteSlice {
fn as_slice(&self) -> &[u8];
}
#[derive(Clone, Copy)]
pub struct RGB565Pixel(pub [u8; 2]);
impl AsByteSlice for RGB565Pixel {
fn as_slice(&self) -> &[u8] {
&self.0
}
}
pub trait Lcd {
type Pixel: AsByteSlice + Copy;
fn info(&self) -> (LcdSize, usize);
fn encode(&self, rgb: RGB) -> Self::Pixel;
fn set_data(&mut self, x1y1: LcdXY, x2y2: LcdXY, data: &[u8]) -> io::Result<()>;
}
#[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct LcdXY {
pub x: usize,
pub y: usize,
}
#[derive(Clone, Copy)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct LcdSize {
pub width: usize,
pub height: usize,
}
impl LcdSize {
fn between(x1y1: LcdXY, x2y2: LcdXY) -> Self {
debug_assert!(x2y2.x >= x1y1.x);
debug_assert!(x2y2.y >= x1y1.y);
Self { width: x2y2.x - x1y1.x + 1, height: x2y2.y - x1y1.y + 1 }
}
fn new_buffer(&self, stride: usize) -> Vec<u8> {
Vec::with_capacity(self.width * self.height * stride)
}
}
impl From<LcdSize> for SizeInPixels {
fn from(value: LcdSize) -> Self {
Self::new(
u16::try_from(value.width).expect("Must fit"),
u16::try_from(value.height).expect("Must fit"),
)
}
}
pub fn to_xy_size(x1y1: LcdXY, x2y2: LcdXY) -> (LcdXY, LcdSize) {
let x1 = std::cmp::min(x1y1.x, x2y2.x);
let y1 = std::cmp::min(x1y1.y, x2y2.y);
let x2 = std::cmp::max(x1y1.x, x2y2.x);
let y2 = std::cmp::max(x1y1.y, x2y2.y);
(LcdXY { x: x1, y: y1 }, LcdSize { width: x2 + 1 - x1, height: y2 + 1 - y1 })
}
#[cfg(test)]
mod tests {
use super::*;
fn xy(x: usize, y: usize) -> LcdXY {
LcdXY { x, y }
}
fn size(width: usize, height: usize) -> LcdSize {
LcdSize { width, height }
}
#[test]
fn test_lcdsize_between_one_pixel() {
assert_eq!(size(1, 1), LcdSize::between(xy(15, 16), xy(15, 16)));
}
#[test]
fn test_lcdsize_between_rect() {
assert_eq!(size(4, 5), LcdSize::between(xy(10, 25), xy(13, 29)));
}
#[test]
fn test_lcdsize_new_buffer() {
let buffer = size(10, 20).new_buffer(3);
assert_eq!(10 * 20 * 3, buffer.capacity());
}
#[test]
fn test_to_xy_size_one_pixel() {
assert_eq!(
(LcdXY { x: 10, y: 20 }, LcdSize { width: 1, height: 1 }),
to_xy_size(xy(10, 20), xy(10, 20))
);
}
#[test]
fn test_to_xy_size_rect() {
assert_eq!(
(LcdXY { x: 10, y: 20 }, LcdSize { width: 5, height: 7 }),
to_xy_size(xy(10, 20), xy(14, 26))
);
}
}