1 | //! Raw data iterator. |
2 | //! |
3 | //! Raw data iterators are used to implement rendering of custom image formats. Most users |
4 | //! won't need to use these types directly and should instead use [`ImageRaw`]. |
5 | //! |
6 | //! The [`RawDataSlice`] is used to specify the raw data format for a byte slice. This slice can |
7 | //! than be converted into an optimized iterator for that data format by using `into_iter()`. |
8 | //! |
9 | //! # Examples |
10 | //! |
11 | //! ``` |
12 | //! use embedded_graphics::{iterator::raw::RawDataSlice, pixelcolor::raw::{RawU16, BigEndian}}; |
13 | //! |
14 | //! let data = [0xAA, 0xBB, 0x12, 0x34]; |
15 | //! |
16 | //! // The data type and byte order needs to be specified explicitly to set the data format. |
17 | //! let slice = RawDataSlice::<RawU16, BigEndian>::new(&data); |
18 | //! |
19 | //! let mut iter = slice.into_iter(); |
20 | //! assert_eq!(iter.next(), Some(RawU16::new(0xAABB))); |
21 | //! assert_eq!(iter.next(), Some(RawU16::new(0x1234))); |
22 | //! assert_eq!(iter.next(), None); |
23 | //! ``` |
24 | //! |
25 | //! [`ImageRaw`]: super::super::image::ImageRaw |
26 | |
27 | use core::{marker::PhantomData, slice}; |
28 | |
29 | use byteorder::{ByteOrder, BE, LE}; |
30 | |
31 | use crate::pixelcolor::raw::{ |
32 | BigEndian, LittleEndian, RawData, RawU1, RawU16, RawU2, RawU24, RawU32, RawU4, RawU8, |
33 | }; |
34 | |
35 | /// Raw data slice. |
36 | /// |
37 | /// This type is a wrapper around a byte array to specify the stored data format. |
38 | /// |
39 | /// See the [module-level documentation] for more information. |
40 | /// |
41 | /// [module-level documentation]: self |
42 | #[derive (Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
43 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
44 | pub struct RawDataSlice<'a, R, BO> { |
45 | data: &'a [u8], |
46 | raw_type: PhantomData<R>, |
47 | byte_order: PhantomData<BO>, |
48 | } |
49 | |
50 | impl<'a, R, BO> RawDataSlice<'a, R, BO> { |
51 | /// Creates a new raw data slice. |
52 | pub const fn new(data: &'a [u8]) -> Self { |
53 | Self { |
54 | data, |
55 | raw_type: PhantomData, |
56 | byte_order: PhantomData, |
57 | } |
58 | } |
59 | } |
60 | |
61 | macro_rules! impl_bits_iterator { |
62 | ($type:ident, $bit_index_bits:expr) => { |
63 | impl<'a, BO> IntoIterator for RawDataSlice<'a, $type, BO> { |
64 | type Item = $type; |
65 | type IntoIter = BitsIterator<'a, $type>; |
66 | |
67 | fn into_iter(self) -> Self::IntoIter { |
68 | BitsIterator::new(self.data) |
69 | } |
70 | } |
71 | |
72 | impl<'a> Iterator for BitsIterator<'a, $type> { |
73 | type Item = $type; |
74 | |
75 | #[inline] |
76 | fn next(&mut self) -> Option<Self::Item> { |
77 | self.data.get(self.index >> $bit_index_bits).map(|byte| { |
78 | // Number of bits the value needs to be shifted to the right for the first pixel. |
79 | let first_pixel_shift = 8 - $type::BITS_PER_PIXEL; |
80 | |
81 | // Index to one of the pixels inside this byte. |
82 | let sub_index = self.index & (1 << $bit_index_bits) - 1; |
83 | |
84 | // Number of bits the value needs to be shifted. |
85 | let shift = first_pixel_shift - (sub_index << 3 - $bit_index_bits); |
86 | |
87 | self.index += 1; |
88 | |
89 | $type::new(*byte >> shift) |
90 | }) |
91 | } |
92 | |
93 | #[inline] |
94 | fn nth(&mut self, n: usize) -> Option<Self::Item> { |
95 | self.index = self.index.saturating_add(n); |
96 | self.next() |
97 | } |
98 | |
99 | fn size_hint(&self) -> (usize, Option<usize>) { |
100 | let size = |
101 | (self.data.len() * (8 / $type::BITS_PER_PIXEL)).saturating_sub(self.index); |
102 | |
103 | (size, Some(size)) |
104 | } |
105 | } |
106 | }; |
107 | } |
108 | |
109 | impl_bits_iterator!(RawU1, 3); |
110 | impl_bits_iterator!(RawU2, 2); |
111 | impl_bits_iterator!(RawU4, 1); |
112 | |
113 | impl<'a, BO> IntoIterator for RawDataSlice<'a, RawU8, BO> { |
114 | type Item = RawU8; |
115 | type IntoIter = ByteIterator<'a>; |
116 | |
117 | fn into_iter(self) -> Self::IntoIter { |
118 | ByteIterator::new(self.data) |
119 | } |
120 | } |
121 | |
122 | /// Iterator for raw data slices with less than 8 BPP. |
123 | /// |
124 | /// See the [module-level documentation] for more information. |
125 | /// |
126 | /// [module-level documentation]: self |
127 | #[derive (Debug)] |
128 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
129 | pub struct BitsIterator<'a, R> { |
130 | data: &'a [u8], |
131 | index: usize, |
132 | raw_type: PhantomData<R>, |
133 | } |
134 | |
135 | impl<'a, R: RawData> BitsIterator<'a, R> { |
136 | const fn new(data: &'a [u8]) -> Self { |
137 | Self { |
138 | data, |
139 | index: 0, |
140 | raw_type: PhantomData, |
141 | } |
142 | } |
143 | } |
144 | |
145 | /// Iterator for raw data slices with 8 BPP. |
146 | /// |
147 | /// See the [module-level documentation] for more information. |
148 | /// |
149 | /// [module-level documentation]: self |
150 | #[derive (Debug)] |
151 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
152 | pub struct ByteIterator<'a> { |
153 | data: slice::Iter<'a, u8>, |
154 | } |
155 | |
156 | impl<'a> ByteIterator<'a> { |
157 | fn new(data: &'a [u8]) -> Self { |
158 | Self { data: data.iter() } |
159 | } |
160 | } |
161 | |
162 | impl<'a> Iterator for ByteIterator<'a> { |
163 | type Item = RawU8; |
164 | |
165 | #[inline ] |
166 | fn next(&mut self) -> Option<Self::Item> { |
167 | self.data.next().copied().map(RawU8::new) |
168 | } |
169 | |
170 | #[inline ] |
171 | fn nth(&mut self, n: usize) -> Option<Self::Item> { |
172 | self.data.nth(n).copied().map(RawU8::new) |
173 | } |
174 | |
175 | fn size_hint(&self) -> (usize, Option<usize>) { |
176 | self.data.size_hint() |
177 | } |
178 | } |
179 | |
180 | /// Iterator for raw data slices more than 8 BPP. |
181 | /// |
182 | /// See the [module-level documentation] for more information. |
183 | /// |
184 | /// [module-level documentation]: self |
185 | #[derive (Debug)] |
186 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
187 | pub struct BytesIterator<'a, R, BO> { |
188 | // MSRV: replace by ArrayChunks when the feature is stabilized |
189 | data: slice::ChunksExact<'a, u8>, |
190 | raw_type: PhantomData<R>, |
191 | byte_order: PhantomData<BO>, |
192 | } |
193 | |
194 | impl<'a, R: RawData, BO> BytesIterator<'a, R, BO> { |
195 | fn new(data: &'a [u8]) -> Self { |
196 | Self { |
197 | data: data.chunks_exact(R::BITS_PER_PIXEL / 8), |
198 | raw_type: PhantomData, |
199 | byte_order: PhantomData, |
200 | } |
201 | } |
202 | } |
203 | |
204 | macro_rules! impl_bytes_iterator { |
205 | ($type:ident, $byte_order:ident, $read_function:path) => { |
206 | impl<'a> Iterator for BytesIterator<'a, $type, $byte_order> { |
207 | type Item = $type; |
208 | |
209 | #[inline] |
210 | fn next(&mut self) -> Option<Self::Item> { |
211 | self.data.next().map(|raw| $read_function(raw).into()) |
212 | } |
213 | |
214 | #[inline] |
215 | fn nth(&mut self, n: usize) -> Option<Self::Item> { |
216 | self.data.nth(n).map(|raw| $read_function(raw).into()) |
217 | } |
218 | |
219 | fn size_hint(&self) -> (usize, Option<usize>) { |
220 | self.data.size_hint() |
221 | } |
222 | } |
223 | |
224 | impl<'a> IntoIterator for RawDataSlice<'a, $type, $byte_order> { |
225 | type Item = $type; |
226 | type IntoIter = BytesIterator<'a, $type, $byte_order>; |
227 | |
228 | fn into_iter(self) -> Self::IntoIter { |
229 | BytesIterator::new(self.data) |
230 | } |
231 | } |
232 | }; |
233 | |
234 | ($type:ident, $read_function:ident) => { |
235 | impl_bytes_iterator!($type, LittleEndian, LE::$read_function); |
236 | impl_bytes_iterator!($type, BigEndian, BE::$read_function); |
237 | }; |
238 | } |
239 | |
240 | impl_bytes_iterator!(RawU16, read_u16); |
241 | impl_bytes_iterator!(RawU24, read_u24); |
242 | impl_bytes_iterator!(RawU32, read_u32); |
243 | |
244 | #[cfg (test)] |
245 | mod tests { |
246 | use super::*; |
247 | |
248 | const BITS_DATA: &[u8] = &[0x12, 0x48, 0x5A, 0x0F]; |
249 | const BYTES_DATA_1: &[u8] = &[0x10, 0x20, 0x30, 0x40, 0x50, 0x60]; |
250 | const BYTES_DATA_2: &[u8] = &[0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]; |
251 | |
252 | #[test ] |
253 | fn raw_u1() { |
254 | #[rustfmt::skip] |
255 | let expected = [ |
256 | 0, 0, 0, 1, |
257 | 0, 0, 1, 0, |
258 | 0, 1, 0, 0, |
259 | 1, 0, 0, 0, |
260 | 0, 1, 0, 1, |
261 | 1, 0, 1, 0, |
262 | 0, 0, 0, 0, |
263 | 1, 1, 1, 1, |
264 | ] |
265 | .iter() |
266 | .copied() |
267 | .map(RawU1::new); |
268 | |
269 | let iter = RawDataSlice::<RawU1, LittleEndian>::new(BITS_DATA).into_iter(); |
270 | assert!(iter.eq(expected)); |
271 | } |
272 | |
273 | #[test ] |
274 | fn raw_u2() { |
275 | let expected = [0, 1, 0, 2, 1, 0, 2, 0, 1, 1, 2, 2, 0, 0, 3, 3] |
276 | .iter() |
277 | .copied() |
278 | .map(RawU2::new); |
279 | |
280 | let iter = RawDataSlice::<RawU2, LittleEndian>::new(BITS_DATA).into_iter(); |
281 | assert!(iter.eq(expected)); |
282 | } |
283 | |
284 | #[test ] |
285 | fn raw_u4() { |
286 | let expected = [0x1, 0x2, 0x4, 0x8, 0x5, 0xA, 0x0, 0xF] |
287 | .iter() |
288 | .copied() |
289 | .map(RawU4::new); |
290 | |
291 | let iter = RawDataSlice::<RawU4, LittleEndian>::new(BITS_DATA).into_iter(); |
292 | assert!(iter.eq(expected)); |
293 | } |
294 | |
295 | #[test ] |
296 | fn raw_u8() { |
297 | let expected = BYTES_DATA_1.iter().map(|&v| RawU8::new(v)); |
298 | |
299 | let iter = RawDataSlice::<RawU8, LittleEndian>::new(BYTES_DATA_1).into_iter(); |
300 | assert!(iter.eq(expected)); |
301 | } |
302 | |
303 | #[test ] |
304 | fn raw_u16_le() { |
305 | let expected = [0x2010, 0x4030, 0x6050].iter().copied().map(RawU16::new); |
306 | |
307 | let iter = RawDataSlice::<RawU16, LittleEndian>::new(BYTES_DATA_1).into_iter(); |
308 | assert!(iter.eq(expected)); |
309 | } |
310 | |
311 | #[test ] |
312 | fn raw_u16_be() { |
313 | let expected = [0x1020, 0x3040, 0x5060].iter().copied().map(RawU16::new); |
314 | |
315 | let iter = RawDataSlice::<RawU16, BigEndian>::new(BYTES_DATA_1).into_iter(); |
316 | assert!(iter.eq(expected)); |
317 | } |
318 | |
319 | #[test ] |
320 | fn raw_u16_excess_bytes_are_ignored() { |
321 | let iter = RawDataSlice::<RawU16, LittleEndian>::new(&[0; 3]).into_iter(); |
322 | assert_eq!(iter.count(), 1); |
323 | } |
324 | |
325 | #[test ] |
326 | fn raw_u24_le() { |
327 | let expected = [0x302010, 0x605040].iter().copied().map(RawU24::new); |
328 | |
329 | let iter = RawDataSlice::<RawU24, LittleEndian>::new(BYTES_DATA_1).into_iter(); |
330 | assert!(iter.into_iter().eq(expected)); |
331 | } |
332 | |
333 | #[test ] |
334 | fn raw_u24_be() { |
335 | let expected = [0x102030, 0x405060].iter().copied().map(RawU24::new); |
336 | |
337 | let iter = RawDataSlice::<RawU24, BigEndian>::new(BYTES_DATA_1).into_iter(); |
338 | assert!(iter.into_iter().eq(expected)); |
339 | } |
340 | |
341 | #[test ] |
342 | fn raw_u24_excess_bytes_are_ignored() { |
343 | let iter = RawDataSlice::<RawU24, LittleEndian>::new(&[0; 7]).into_iter(); |
344 | assert_eq!(iter.count(), 2); |
345 | } |
346 | |
347 | #[test ] |
348 | fn raw_u32_le() { |
349 | let expected = [0x40302010, 0x80706050].iter().copied().map(RawU32::new); |
350 | |
351 | let iter = RawDataSlice::<RawU32, LittleEndian>::new(BYTES_DATA_2).into_iter(); |
352 | assert!(iter.into_iter().eq(expected)); |
353 | } |
354 | |
355 | #[test ] |
356 | fn raw_u32_be() { |
357 | let expected = [0x10203040, 0x50607080].iter().copied().map(RawU32::new); |
358 | |
359 | let iter = RawDataSlice::<RawU32, BigEndian>::new(BYTES_DATA_2).into_iter(); |
360 | assert!(iter.into_iter().eq(expected)); |
361 | } |
362 | |
363 | #[test ] |
364 | fn raw_u32_excess_bytes_are_ignored() { |
365 | let iter = RawDataSlice::<RawU32, LittleEndian>::new(&[0; 13]).into_iter(); |
366 | assert_eq!(iter.count(), 3); |
367 | } |
368 | } |
369 | |