use core::iter::FusedIterator;
pub trait IterArrayWindows: Iterator {
#[inline]
fn array_windows<const N: usize>(self) -> ArrayWindows<Self, N>
where
Self: Sized,
Self::Item: Clone,
{
ArrayWindows::new(self)
}
}
impl<I: ?Sized> IterArrayWindows for I where I: Iterator {}
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct ArrayWindows<I, const N: usize>
where
I: Iterator,
{
iter: I,
last: Option<[I::Item; N]>,
}
impl<I, const N: usize> ArrayWindows<I, N>
where
I: Iterator,
I::Item: Clone,
{
fn new(iter: I) -> Self {
assert!(N != 0, "window size must be non-zero");
Self { iter, last: None }
}
}
impl<I: Iterator, const N: usize> Iterator for ArrayWindows<I, N>
where
I: Iterator,
I::Item: Clone,
{
type Item = [I::Item; N];
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let Self { iter, last } = self;
match last {
Some(last) => {
let item = iter.next()?;
last.rotate_left(1);
if let Some(end) = last.last_mut() {
*end = item;
}
Some(last.clone())
}
None => {
let tmp = arrays::from_iter(iter).ok()?;
*last = Some(tmp.clone());
Some(tmp)
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.iter.size_hint();
(
lower.saturating_sub(N - 1),
upper.map(|n| n.saturating_sub(N - 1)),
)
}
#[inline]
fn count(self) -> usize {
self.iter.count().saturating_sub(N - 1)
}
}
impl<I, const N: usize> ExactSizeIterator for ArrayWindows<I, N>
where
I: ExactSizeIterator,
I::Item: Clone,
{
#[inline]
fn len(&self) -> usize {
self.iter.len().saturating_sub(N - 1)
}
}
impl<I, const N: usize> FusedIterator for ArrayWindows<I, N>
where
I: FusedIterator + Clone,
I::Item: Clone,
{
}