use std::iter::{Fuse, FusedIterator};
pub(crate) trait IteratorExt {
fn windows<const S: usize>(self) -> Windows<Self, S>
where
Self: Iterator + Sized,
Self::Item: Default + Copy,
{
Windows::new(self)
}
}
impl<I> IteratorExt for I {}
#[derive(Debug, Clone)]
pub(crate) struct Windows<I: Iterator, const S: usize> {
iter: Fuse<I>,
window: [I::Item; S],
}
impl<I: Iterator, const S: usize> Windows<I, S> {
pub fn new<T>(iter: T) -> Self
where
T: IntoIterator<IntoIter = I>,
I::Item: Default + Copy,
{
if S == 0 {
panic!("A window size of zero is not allowed.");
}
let mut this = Self {
iter: iter.into_iter().fuse(),
window: [Default::default(); S],
};
for _ in 1..S {
this.next();
}
this
}
}
impl<I: Iterator, const S: usize> FusedIterator for Windows<I, S>
where
I: FusedIterator,
I::Item: Copy,
{
}
impl<I: Iterator, const S: usize> Iterator for Windows<I, S>
where
I::Item: Copy,
{
type Item = [I::Item; S];
fn next(&mut self) -> Option<Self::Item> {
let next_item = self.iter.next()?;
let mut window = rotate(self.window);
window[S - 1] = next_item;
self.window = window;
Some(window)
}
}
fn rotate<T, const N: usize>(array: [T; N]) -> [T; N]
where
T: Copy,
{
if N == 0 {
return array;
}
let mut rotated = array;
rotated[..(N - 1)].clone_from_slice(&array[1..N]);
rotated[N - 1] = array[0];
rotated
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rotate_array() {
assert_eq!(rotate([1, 2, 3]), [2, 3, 1]);
}
#[test]
fn rotate_empty() {
assert_eq!(rotate::<(), 0>([]), []);
}
#[test]
#[should_panic]
fn zero_window_size_should_panic() {
Windows::<_, 0>::new([] as [u8; 0]);
}
#[test]
fn single_window_length_2() {
let windows = Vec::from_iter(Windows::new([1, 2]));
assert_eq!(windows, [[1, 2]]);
}
#[test]
fn windows_length_3() {
let windows = Vec::from_iter(Windows::new([1, 2, 3, 4]));
assert_eq!(windows, [[1, 2, 3], [2, 3, 4]]);
}
}