| 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 | |