use std::{convert::TryInto, slice::ChunksExact};
use crate::trusted_len::TrustedLen;
use super::{BitChunk, BitChunkIterExact};
#[derive(Debug)]
pub struct BitChunksExact<'a, T: BitChunk> {
iter: ChunksExact<'a, u8>,
remainder: &'a [u8],
remainder_len: usize,
phantom: std::marker::PhantomData<T>,
}
impl<'a, T: BitChunk> BitChunksExact<'a, T> {
#[inline]
pub fn new(bitmap: &'a [u8], length: usize) -> Self {
assert!(length <= bitmap.len() * 8);
let size_of = std::mem::size_of::<T>();
let bitmap = &bitmap[..length.saturating_add(7) / 8];
let split = (length / 8 / size_of) * size_of;
let (chunks, remainder) = bitmap.split_at(split);
let remainder_len = length - chunks.len() * 8;
let iter = chunks.chunks_exact(size_of);
Self {
iter,
remainder,
remainder_len,
phantom: std::marker::PhantomData,
}
}
#[inline]
pub fn len(&self) -> usize {
self.iter.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn remainder(&self) -> T {
let remainder_bytes = self.remainder;
if remainder_bytes.is_empty() {
return T::zero();
}
let remainder = match remainder_bytes.try_into() {
Ok(a) => a,
Err(_) => {
let mut remainder = T::zero().to_ne_bytes();
remainder_bytes
.iter()
.enumerate()
.for_each(|(index, b)| remainder[index] = *b);
remainder
}
};
T::from_ne_bytes(remainder)
}
}
impl<T: BitChunk> Iterator for BitChunksExact<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|x| match x.try_into() {
Ok(a) => T::from_ne_bytes(a),
Err(_) => unreachable!(),
})
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
unsafe impl<T: BitChunk> TrustedLen for BitChunksExact<'_, T> {}
impl<T: BitChunk> BitChunkIterExact<T> for BitChunksExact<'_, T> {
#[inline]
fn remainder(&self) -> T {
self.remainder()
}
#[inline]
fn remainder_len(&self) -> usize {
self.remainder_len
}
}