use std::iter::FusedIterator;
pub struct SteppedWindows<'a, const N: usize, T> {
slice: &'a [T],
final_partial_window: &'a [T],
step: usize,
}
impl<'a, T, const N: usize> SteppedWindows<'a, N, T> {
pub fn new(slice: &'a [T], step: usize) -> Self {
assert!(step > 0, "`step` must be non-zero");
const { assert!(N > 0, "`N` must be non-zero") };
let final_partial_window_start = if let Some(max_window_start) = slice.len().checked_sub(N) {
let num_steps_to_take = max_window_start / step;
std::cmp::min((num_steps_to_take + 1) * step, slice.len())
} else {
0
};
Self {
slice,
final_partial_window: &slice[final_partial_window_start..],
step,
}
}
#[inline]
#[must_use]
pub fn final_partial_window(&self) -> &'a [T] {
self.final_partial_window
}
}
impl<'a, T, const N: usize> Iterator for SteppedWindows<'a, N, T> {
type Item = &'a [T; N];
fn next(&mut self) -> Option<Self::Item> {
let window = self.slice.first_chunk()?;
self.slice = self.slice.get(self.step..).unwrap_or(&[]);
Some(window)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = if let Some(max_window_start) = self.slice.len().checked_sub(N) {
let num_valid_starts = max_window_start + 1;
num_valid_starts.div_ceil(self.step)
} else {
0
};
(size, Some(size))
}
}
impl<T, const N: usize> ExactSizeIterator for SteppedWindows<'_, N, T> {}
impl<T, const N: usize> FusedIterator for SteppedWindows<'_, N, T> {}