use std::borrow::Borrow;
pub struct BitUnpacked<I, T>
where
I: Iterator<Item = T>,
T: Borrow<u8>,
{
iter: I,
byte: Option<u8>,
mask: u8,
}
impl<I, T> Iterator for BitUnpacked<I, T>
where
I: Iterator<Item = T>,
T: Borrow<u8>,
{
type Item = bool;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.mask == 0x01 {
self.byte = self.iter.next().map(|item| *item.borrow());
}
self.byte.map(|byte| {
let next = (byte & self.mask) != 0;
self.mask = self.mask.rotate_left(1);
next
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.iter.size_hint();
(
lower.saturating_mul(8),
upper.and_then(|bound| bound.checked_mul(8)),
)
}
}
impl<I, T> ExactSizeIterator for BitUnpacked<I, T>
where
I: ExactSizeIterator<Item = T>,
T: Borrow<u8>,
{
}
pub trait BitUnpackedExt<T>: Iterator<Item = T>
where
T: Borrow<u8>,
{
fn bit_unpacked(self) -> BitUnpacked<Self, T>
where
Self: Sized,
{
BitUnpacked {
iter: self,
byte: None,
mask: 0x01,
}
}
}
impl<I, T> BitUnpackedExt<T> for I
where
I: Iterator<Item = T>,
T: Borrow<u8>,
{
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iter() {
let iter = [u8::MAX, 1].iter().bit_unpacked();
assert_eq!(
iter.collect::<Vec<_>>(),
vec![
true, true, true, true, true, true, true, true, true, false, false, false, false,
false, false, false
]
);
}
#[test]
fn size_hint() {
let input = [u8::MAX, 1, 2, 3];
assert_eq!(
input.iter().bit_unpacked().size_hint(),
(input.len() * 8, Some(input.len() * 8))
);
}
}