safe_http_parser 0.1.0-beta.4

HTTP head parser for the safe_http crate
Documentation
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.iter is a Fuse, so we can ignore the result
            // because this.next() will continue to return None,
            // so we will never return a window, that still has defaults.
            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]]);
    }
}