use crate::pixelcolor::raw::{
BigEndian, LittleEndian, RawData, RawU1, RawU16, RawU2, RawU24, RawU32, RawU4, RawU8,
};
use byteorder::{ByteOrder, BE, LE};
use core::marker::PhantomData;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct RawDataIter<'a, R, BO> {
data: &'a [u8],
byte_position: usize,
bits_left: u8,
raw_type: PhantomData<R>,
byte_order: PhantomData<BO>,
}
impl<'a, R, BO> RawDataIter<'a, R, BO> {
pub fn new(data: &'a [u8]) -> Self {
Self {
data,
byte_position: 0,
bits_left: 8,
raw_type: PhantomData,
byte_order: PhantomData,
}
}
pub fn set_byte_position(&mut self, position: usize) {
self.byte_position = position;
self.bits_left = 8;
}
pub fn align(&mut self) {
if self.bits_left == 8 {
return;
}
self.byte_position = self.data.len().min(self.byte_position + 1);
self.bits_left = 8;
}
fn next_bits(&mut self, bit_count: u8) -> Option<u8> {
if self.bits_left == 0 || self.byte_position >= self.data.len() {
return None;
}
let current_byte = self.data[self.byte_position];
let ret = current_byte >> (self.bits_left - bit_count);
self.bits_left -= bit_count;
if self.bits_left == 0 && self.byte_position < self.data.len() {
self.byte_position += 1;
self.bits_left = 8;
}
Some(ret)
}
fn next_bytes(&mut self, byte_count: usize) -> Option<&[u8]> {
if (self.data.len() - self.byte_position) >= byte_count {
let ret = &self.data[self.byte_position..];
self.byte_position += byte_count;
Some(ret)
} else {
None
}
}
}
impl<'a, R> Iterator for RawDataIter<'a, R, LittleEndian>
where
R: RawData,
{
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
R::next(self)
}
}
impl<'a, R> Iterator for RawDataIter<'a, R, BigEndian>
where
R: RawData,
{
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
R::next(self)
}
}
pub trait RawDataIterNext<BO>: Sized {
fn next<'a>(iter: &mut RawDataIter<'a, Self, BO>) -> Option<Self>;
}
macro_rules! impl_next_for_bits {
($raw_type:ident, $bit_count:expr) => {
impl<BO> RawDataIterNext<BO> for $raw_type {
fn next<'a>(iter: &mut RawDataIter<'a, $raw_type, BO>) -> Option<$raw_type> {
iter.next_bits($bit_count).map($raw_type::new)
}
}
};
}
impl_next_for_bits!(RawU1, 1);
impl_next_for_bits!(RawU2, 2);
impl_next_for_bits!(RawU4, 4);
impl<BO> RawDataIterNext<BO> for RawU8 {
fn next<'a>(iter: &mut RawDataIter<'a, RawU8, BO>) -> Option<RawU8> {
iter.next_bytes(1).map(|data| RawU8::new(data[0]))
}
}
macro_rules! impl_next_for_bytes {
($raw_type:ident, $byte_count:expr, $endian:ident, $read_function:path) => {
impl RawDataIterNext<$endian> for $raw_type {
fn next<'a>(iter: &mut RawDataIter<'a, $raw_type, $endian>) -> Option<$raw_type> {
iter.next_bytes($byte_count)
.map(|data| $raw_type::new($read_function(data)))
}
}
};
($raw_type:ident, $byte_count:expr, $read_function:ident) => {
impl_next_for_bytes!($raw_type, $byte_count, BigEndian, BE::$read_function);
impl_next_for_bytes!($raw_type, $byte_count, LittleEndian, LE::$read_function);
};
}
impl_next_for_bytes!(RawU16, 2, read_u16);
impl_next_for_bytes!(RawU24, 3, read_u24);
impl_next_for_bytes!(RawU32, 4, read_u32);
impl<BO> RawDataIterNext<BO> for () {
fn next<'a>(_iter: &mut RawDataIter<'a, (), BO>) -> Option<()> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
const BITS_DATA: &[u8] = &[0x12, 0x48, 0x5A, 0x0F];
const BYTES_DATA_1: &[u8] = &[0x10, 0x20, 0x30, 0x40, 0x50, 0x60];
const BYTES_DATA_2: &[u8] = &[0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80];
#[test]
fn align_advances_to_next_byte() {
let data = &[0x80, 0x80];
let mut iter: RawDataIter<RawU1, LittleEndian> = RawDataIter::new(data);
assert_eq!(iter.next(), Some(RawU1::new(1)));
assert_eq!(iter.next(), Some(RawU1::new(0)));
let mut iter: RawDataIter<RawU1, LittleEndian> = RawDataIter::new(data);
assert_eq!(iter.next(), Some(RawU1::new(1)));
iter.align();
assert_eq!(iter.next(), Some(RawU1::new(1)));
}
#[test]
fn calling_align_again_is_a_noop() {
let data = &[0x80, 0xFF, 0x00];
let mut iter: RawDataIter<RawU1, LittleEndian> = RawDataIter::new(data);
assert_eq!(iter.next(), Some(RawU1::new(1)));
iter.align();
iter.align();
assert_eq!(iter.next(), Some(RawU1::new(1)));
}
#[test]
fn set_byte_position_resets_bit_position() {
let data = &[0x0F, 0x0F];
let mut iter: RawDataIter<RawU4, LittleEndian> = RawDataIter::new(data);
assert_eq!(iter.next(), Some(RawU4::new(0)));
iter.set_byte_position(1);
assert_eq!(iter.next(), Some(RawU4::new(0)));
}
#[test]
fn raw_u1() {
#[rustfmt::skip]
let expected = [
0, 0, 0, 1,
0, 0, 1, 0,
0, 1, 0, 0,
1, 0, 0, 0,
0, 1, 0, 1,
1, 0, 1, 0,
0, 0, 0, 0,
1, 1, 1, 1,
]
.iter()
.copied()
.map(RawU1::new);
let data: RawDataIter<RawU1, LittleEndian> = RawDataIter::new(BITS_DATA);
assert!(data.eq(expected));
}
#[test]
fn raw_u2() {
let expected = [0, 1, 0, 2, 1, 0, 2, 0, 1, 1, 2, 2, 0, 0, 3, 3]
.iter()
.copied()
.map(RawU2::new);
let iter: RawDataIter<RawU2, LittleEndian> = RawDataIter::new(BITS_DATA);
assert!(iter.eq(expected));
}
#[test]
fn raw_u4() {
let expected = [0x1, 0x2, 0x4, 0x8, 0x5, 0xA, 0x0, 0xF]
.iter()
.copied()
.map(RawU4::new);
let iter: RawDataIter<RawU4, LittleEndian> = RawDataIter::new(BITS_DATA);
assert!(iter.eq(expected));
}
#[test]
fn raw_u8() {
let expected = BYTES_DATA_1.iter().map(|&v| RawU8::new(v));
let iter: RawDataIter<RawU8, LittleEndian> = RawDataIter::new(BYTES_DATA_1);
assert!(iter.eq(expected));
}
#[test]
fn raw_u16_le() {
let expected = [0x2010, 0x4030, 0x6050].iter().copied().map(RawU16::new);
let iter: RawDataIter<RawU16, LittleEndian> = RawDataIter::new(BYTES_DATA_1);
assert!(iter.eq(expected));
}
#[test]
fn raw_u16_be() {
let expected = [0x1020, 0x3040, 0x5060].iter().copied().map(RawU16::new);
let iter: RawDataIter<RawU16, BigEndian> = RawDataIter::new(BYTES_DATA_1);
assert!(iter.eq(expected));
}
#[test]
fn raw_u16_excess_bytes_are_ignored() {
let iter: RawDataIter<RawU16, LittleEndian> = RawDataIter::new(&[0; 3]);
assert_eq!(iter.count(), 1);
}
#[test]
fn raw_u24_le() {
let expected = [0x302010, 0x605040].iter().copied().map(RawU24::new);
let iter: RawDataIter<RawU24, LittleEndian> = RawDataIter::new(BYTES_DATA_1);
assert!(iter.into_iter().eq(expected));
}
#[test]
fn raw_u24_be() {
let expected = [0x102030, 0x405060].iter().copied().map(RawU24::new);
let iter: RawDataIter<RawU24, BigEndian> = RawDataIter::new(BYTES_DATA_1);
assert!(iter.into_iter().eq(expected));
}
#[test]
fn raw_u24_excess_bytes_are_ignored() {
let iter: RawDataIter<RawU24, LittleEndian> = RawDataIter::new(&[0; 7]);
assert_eq!(iter.count(), 2);
}
#[test]
fn raw_u32_le() {
let expected = [0x40302010, 0x80706050].iter().copied().map(RawU32::new);
let iter: RawDataIter<RawU32, LittleEndian> = RawDataIter::new(BYTES_DATA_2);
assert!(iter.into_iter().eq(expected));
}
#[test]
fn raw_u32_be() {
let expected = [0x10203040, 0x50607080].iter().copied().map(RawU32::new);
let iter: RawDataIter<RawU32, BigEndian> = RawDataIter::new(BYTES_DATA_2);
assert!(iter.into_iter().eq(expected));
}
#[test]
fn raw_u32_excess_bytes_are_ignored() {
let iter: RawDataIter<RawU32, LittleEndian> = RawDataIter::new(&[0; 13]);
assert_eq!(iter.count(), 3);
}
}