lcd_async/
graphics.rs

1use embedded_graphics_core::pixelcolor::RgbColor;
2
3use crate::dcs::BitsPerPixel;
4
5impl BitsPerPixel {
6    /// Returns the bits per pixel for a embedded-graphics [`RgbColor`].
7    pub const fn from_rgb_color<C: RgbColor>() -> Self {
8        let bpp = C::MAX_R.trailing_ones() + C::MAX_G.trailing_ones() + C::MAX_B.trailing_ones();
9
10        match bpp {
11            3 => Self::Three,
12            8 => Self::Eight,
13            12 => Self::Twelve,
14            16 => Self::Sixteen,
15            18 => Self::Eighteen,
16            24 => Self::TwentyFour,
17            _ => panic!("invalid RgbColor bits per pixel"),
18        }
19    }
20}
21
22/// An iterator that alternately takes and skips elements of another iterator.
23#[allow(dead_code)]
24struct TakeSkip<I> {
25    iter: I,
26    take: u32,
27    take_remaining: u32,
28    skip: u32,
29}
30
31impl<I> TakeSkip<I> {
32    #[allow(dead_code)]
33    pub fn new(iter: I, take: u32, skip: u32) -> Self {
34        Self {
35            iter,
36            take,
37            take_remaining: take,
38            skip,
39        }
40    }
41}
42
43impl<I: Iterator> Iterator for TakeSkip<I> {
44    type Item = I::Item;
45
46    fn next(&mut self) -> Option<Self::Item> {
47        if self.take_remaining > 0 {
48            self.take_remaining -= 1;
49            self.iter.next()
50        } else if self.take > 0 {
51            self.take_remaining = self.take - 1;
52            nth_u32(&mut self.iter, self.skip)
53        } else {
54            None
55        }
56    }
57}
58
59#[cfg(not(target_pointer_width = "16"))]
60#[allow(dead_code)]
61fn take_u32<I: Iterator>(iter: I, max_count: u32) -> impl Iterator<Item = I::Item> {
62    iter.take(max_count.try_into().unwrap())
63}
64
65#[cfg(target_pointer_width = "16")]
66#[allow(dead_code)]
67fn take_u32<I: Iterator>(iter: I, max_count: u32) -> impl Iterator<Item = I::Item> {
68    let mut count = 0;
69    iter.take_while(move |_| {
70        count += 1;
71        count <= max_count
72    })
73}
74
75#[cfg(not(target_pointer_width = "16"))]
76#[allow(dead_code)]
77fn nth_u32<I: Iterator>(mut iter: I, n: u32) -> Option<I::Item> {
78    iter.nth(n.try_into().unwrap())
79}
80
81#[cfg(target_pointer_width = "16")]
82#[allow(dead_code)]
83fn nth_u32<I: Iterator>(mut iter: I, n: u32) -> Option<I::Item> {
84    for _ in 0..n {
85        iter.next();
86    }
87    iter.next()
88}
89
90#[cfg(test)]
91mod test {
92    use crate::dcs::BitsPerPixel;
93    use embedded_graphics_core::pixelcolor::*;
94
95    use super::TakeSkip;
96
97    #[test]
98    fn bpp_from_rgb_color_works() {
99        assert_eq!(
100            BitsPerPixel::from_rgb_color::<Rgb565>(),
101            BitsPerPixel::Sixteen
102        );
103        assert_eq!(
104            BitsPerPixel::from_rgb_color::<Rgb666>(),
105            BitsPerPixel::Eighteen
106        );
107        assert_eq!(
108            BitsPerPixel::from_rgb_color::<Rgb888>(),
109            BitsPerPixel::TwentyFour
110        );
111    }
112
113    #[test]
114    #[should_panic]
115    fn bpp_from_rgb_color_invalid_panics() {
116        BitsPerPixel::from_rgb_color::<Rgb555>();
117    }
118
119    #[test]
120    fn take_skip_iter() {
121        let mut iter = TakeSkip::new(0..11, 3, 2);
122        assert_eq!(iter.next(), Some(0));
123        assert_eq!(iter.next(), Some(1));
124        assert_eq!(iter.next(), Some(2));
125        // Skip 3 and 4
126        assert_eq!(iter.next(), Some(5));
127        assert_eq!(iter.next(), Some(6));
128        assert_eq!(iter.next(), Some(7));
129        // Skip 8 and 9
130        assert_eq!(iter.next(), Some(10));
131        assert_eq!(iter.next(), None);
132    }
133
134    #[test]
135    fn take_skip_with_take_equals_zero() {
136        // take == 0 should not cause an integer overflow or infinite loop and
137        // just return None
138        let mut iter = TakeSkip::new(0..11, 0, 2);
139        assert_eq!(iter.next(), None);
140    }
141}