use super::{reverse::ReverseWindows, LinearWindows};
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum WindowsState<const N: usize> {
Init,
First([u8; N]),
FirstAndLast([u8; N], [u8; N]),
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CircularWindows<const N: usize, I> {
state: WindowsState<N>,
iter: LinearWindows<N, I>,
counter: usize,
}
impl<const N: usize, I> CircularWindows<N, I> {
pub const fn new(iter: I) -> Self {
Self {
state: WindowsState::<N>::Init,
iter: LinearWindows::<N, I>::new(iter),
counter: 0,
}
}
}
fn shift_left<const N: usize>(first: &[u8; N], last: &[u8; N], index: usize) -> [u8; N] {
let mut buffer = [0; N];
buffer[..(N - 1)].copy_from_slice(&last[1..((N - 1) + 1)]);
buffer[N - 1] = first[index];
buffer
}
impl<const N: usize, I> Iterator for CircularWindows<N, I>
where
I: Iterator<Item = u8>,
{
type Item = [u8; N];
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(item) => match self.state {
WindowsState::Init => {
self.state = WindowsState::First(item);
Some(item)
}
WindowsState::First(first_item) => {
self.state = WindowsState::FirstAndLast(first_item, item);
Some(item)
}
WindowsState::FirstAndLast(first_item, _) => {
self.state = WindowsState::FirstAndLast(first_item, item);
Some(item)
}
},
None => match self.state {
WindowsState::Init => None,
WindowsState::First(_) => None,
WindowsState::FirstAndLast(first_item, last_item) => {
if self.counter < N {
let item = shift_left(&first_item, &last_item, self.counter);
self.counter += 1;
self.state = WindowsState::FirstAndLast(first_item, item);
return Some(item);
}
None
}
},
}
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CircularWindowsReversed<const N: usize, I> {
state: WindowsState<N>,
iter: ReverseWindows<N, I>,
counter: usize,
}
impl<const N: usize, I> CircularWindowsReversed<N, I> {
pub const fn new(iter: I) -> Self {
Self {
state: WindowsState::<N>::Init,
iter: ReverseWindows::<N, I>::new(iter),
counter: 0,
}
}
}
fn shift_right<const N: usize>(first: &[u8; N], last: &[u8; N], index: usize) -> [u8; N] {
let mut buffer = [0; N];
buffer[1..].copy_from_slice(&last[..(N - 1)]);
buffer[0] = first[N - 1 - index];
buffer
}
impl<const N: usize, I> Iterator for CircularWindowsReversed<N, I>
where
I: DoubleEndedIterator<Item = u8>,
{
type Item = [u8; N];
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
Some(item) => match self.state {
WindowsState::Init => {
self.state = WindowsState::First(item);
Some(item)
}
WindowsState::First(first_item) => {
self.state = WindowsState::FirstAndLast(first_item, item);
Some(item)
}
WindowsState::FirstAndLast(first_item, _) => {
self.state = WindowsState::FirstAndLast(first_item, item);
Some(item)
}
},
None => match self.state {
WindowsState::Init => None,
WindowsState::First(_) => None,
WindowsState::FirstAndLast(first_item, last_item) => {
if self.counter < N {
let item = shift_right(&first_item, &last_item, self.counter);
self.counter += 1;
self.state = WindowsState::FirstAndLast(first_item, item);
return Some(item);
}
None
}
},
}
}
}
#[cfg(test)]
mod test {
extern crate std;
use std::vec;
use std::vec::Vec;
use super::*;
#[test]
fn shift_left_test() {
let first = [b'l', b'o', b'r'];
let last = [b'r', b'e', b'm'];
assert_eq!([b'e', b'm', b'l'], shift_left(&first, &last, 0));
}
#[test]
fn less_than_n() {
let iter = b"".iter().copied();
let windows = CircularWindows::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[0, 0, 0, 0],], collected);
let iter = b"1".iter().copied();
let windows = CircularWindows::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', 0, 0, 0],], collected);
let iter = b"12".iter().copied();
let windows = CircularWindows::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', b'2', 0, 0],], collected);
let iter = b"123".iter().copied();
let windows = CircularWindows::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', b'2', b'3', 0],], collected);
}
#[test]
fn equals_n() {
let iter = b"1234".iter().copied();
let windows = CircularWindows::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', b'2', b'3', b'4']], collected);
}
#[test]
fn greater_than_n() {
let iter = b"12345678".iter().copied();
let windows = CircularWindows::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(
vec![
[b'1', b'2', b'3', b'4'],
[b'2', b'3', b'4', b'5'],
[b'3', b'4', b'5', b'6'],
[b'4', b'5', b'6', b'7'],
[b'5', b'6', b'7', b'8'],
[b'6', b'7', b'8', b'1'],
[b'7', b'8', b'1', b'2'],
[b'8', b'1', b'2', b'3'],
[b'1', b'2', b'3', b'4'],
],
collected
);
}
#[test]
fn less_than_n_rev() {
let iter = b"".iter().copied();
let windows = CircularWindowsReversed::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[0, 0, 0, 0],], collected);
let iter = b"1".iter().copied();
let windows = CircularWindowsReversed::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', 0, 0, 0],], collected);
let iter = b"12".iter().copied();
let windows = CircularWindowsReversed::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', b'2', 0, 0],], collected);
let iter = b"123".iter().copied();
let windows = CircularWindowsReversed::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', b'2', b'3', 0],], collected);
}
#[test]
fn equals_n_rev() {
let iter = b"1234".iter().copied();
let windows = CircularWindowsReversed::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(vec![[b'1', b'2', b'3', b'4']], collected);
}
#[test]
fn greater_than_n_rev() {
let iter = b"12345678".iter().copied();
let windows = CircularWindowsReversed::<4, _>::new(iter);
let collected = windows.collect::<Vec<_>>();
assert_eq!(
vec![
[b'1', b'2', b'3', b'4'],
[b'8', b'1', b'2', b'3'],
[b'7', b'8', b'1', b'2'],
[b'6', b'7', b'8', b'1'],
[b'5', b'6', b'7', b'8'],
[b'4', b'5', b'6', b'7'],
[b'3', b'4', b'5', b'6'],
[b'2', b'3', b'4', b'5'],
[b'1', b'2', b'3', b'4'],
],
collected
);
}
}