use core::iter::FusedIterator;
use arrays::IntoIter;
pub trait IterArrayChunks: Iterator {
#[inline]
fn array_chunks<const N: usize>(self) -> ArrayChunks<Self, N>
where
Self: Sized,
{
ArrayChunks::new(self)
}
#[inline]
fn arrays<const N: usize>(self) -> ArrayChunks<Self, N>
where
Self: Sized,
{
ArrayChunks::new(self)
}
}
impl<I: ?Sized> IterArrayChunks for I where I: Iterator {}
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ArrayChunks<I, const N: usize>
where
I: Iterator,
{
iter: I,
remainder: Option<IntoIter<I::Item, N>>,
}
impl<I, const N: usize> ArrayChunks<I, N>
where
I: Iterator,
{
#[track_caller]
fn new(iter: I) -> Self {
assert!(N != 0, "chunk size must be non-zero");
Self {
iter,
remainder: None,
}
}
#[inline]
pub fn into_remainder(mut self) -> IntoIter<I::Item, N> {
if self.remainder.is_none() {
self.by_ref().for_each(drop);
}
self.remainder.unwrap()
}
}
impl<I: Iterator, const N: usize> Iterator for ArrayChunks<I, N>
where
I: Iterator,
{
type Item = [I::Item; N];
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let Self { iter, remainder } = self;
match arrays::from_iter(iter) {
Ok(chunk) => Some(chunk),
Err(rem) => {
remainder.get_or_insert(rem);
None
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.iter.size_hint();
(lower / N, upper.map(|n| n / N))
}
#[inline]
fn count(self) -> usize {
self.iter.count() / N
}
}
impl<I, const N: usize> DoubleEndedIterator for ArrayChunks<I, N>
where
I: DoubleEndedIterator + ExactSizeIterator,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.next_back_remainder();
let mut rev = self.iter.by_ref().rev();
let mut chunk = arrays::from_iter(&mut rev).ok()?;
chunk.reverse();
Some(chunk)
}
}
impl<I, const N: usize> ExactSizeIterator for ArrayChunks<I, N>
where
I: ExactSizeIterator,
{
#[inline]
fn len(&self) -> usize {
self.iter.len() / N
}
}
impl<I, const N: usize> ArrayChunks<I, N>
where
I: DoubleEndedIterator + ExactSizeIterator,
{
#[inline]
fn next_back_remainder(&mut self) {
if self.remainder.is_some() {
return;
}
let rem = self.iter.len() % N;
let mut rev = self.iter.by_ref().rev().take(rem);
let mut remainder = unsafe { arrays::from_iter(&mut rev).unwrap_err_unchecked() };
remainder.as_mut_slice().reverse();
self.remainder = Some(remainder);
}
}
impl<I, const N: usize> FusedIterator for ArrayChunks<I, N> where I: FusedIterator {}