itermore/adaptors/
circular_array_windows.rs

1use core::fmt;
2use core::fmt::Debug;
3use core::iter::{Cycle, FusedIterator};
4
5use crate::{ArrayWindows, IterArrayWindows};
6
7pub trait IterCircularArrayWindows: Iterator {
8    /// Returns an iterator over all contiguous windows of length `N` wrapping
9    /// back to the first elements when the window would otherwise exceed the
10    /// length of the iterator.
11    ///
12    /// This adaptor clones the iterator elements so that they can be part of
13    /// successive windows, this makes this it most suited for iterators of
14    /// references and other values that are cheap to clone or copy.
15    ///
16    /// # Panics
17    ///
18    /// If called with `N = 0`.
19    ///
20    /// # Examples
21    ///
22    /// Basic usage:
23    ///
24    /// ```
25    /// use itermore::IterCircularArrayWindows;
26    ///
27    /// let mut iter = (1..5).into_iter().circular_array_windows();
28    /// assert_eq!(iter.next(), Some([1, 2]));
29    /// assert_eq!(iter.next(), Some([2, 3]));
30    /// assert_eq!(iter.next(), Some([3, 4]));
31    /// assert_eq!(iter.next(), Some([4, 1]));
32    /// assert_eq!(iter.next(), None);
33    /// ```
34    ///
35    /// If the window is smaller than the iterator length, then the iterator
36    /// will wrap around multiple times.
37    ///
38    /// ```
39    /// use itermore::IterCircularArrayWindows;
40    ///
41    /// let mut iter = (1..2).into_iter().circular_array_windows::<3>();
42    /// assert_eq!(iter.next(), Some([1, 1, 1]));
43    /// ```
44    #[inline]
45    fn circular_array_windows<const N: usize>(self) -> CircularArrayWindows<Self, N>
46    where
47        Self: Sized + Clone + ExactSizeIterator,
48        Self::Item: Clone,
49    {
50        CircularArrayWindows::new(self)
51    }
52}
53
54impl<I: ?Sized> IterCircularArrayWindows for I where I: Iterator {}
55
56/// An iterator over all contiguous windows of length `N` wrapping back to the
57/// first elements when the window would otherwise exceed the length of the
58/// iterator.
59///
60/// This struct is created by the [`circular_array_windows`] method on
61/// iterators. See its documentation for more.
62///
63/// [`circular_array_windows`]: IterCircularArrayWindows::circular_array_windows
64#[must_use = "iterators are lazy and do nothing unless consumed"]
65pub struct CircularArrayWindows<I, const N: usize>
66where
67    I: Iterator + Clone,
68{
69    iter: ArrayWindows<Cycle<I>, N>,
70    len: usize,
71}
72
73impl<I, const N: usize> CircularArrayWindows<I, N>
74where
75    I: ExactSizeIterator + Clone,
76    I::Item: Clone,
77{
78    fn new(iter: I) -> Self {
79        let len = iter.len();
80        let iter = iter.cycle().array_windows();
81        Self { iter, len }
82    }
83}
84
85impl<I, const N: usize> Debug for CircularArrayWindows<I, N>
86where
87    I: Iterator + Clone + Debug,
88    I::Item: Clone + Debug,
89{
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        f.debug_struct("CircularArrayWindows")
92            .field("iter", &self.iter)
93            .field("len", &self.len)
94            .finish()
95    }
96}
97
98impl<I, const N: usize> Clone for CircularArrayWindows<I, N>
99where
100    I: Iterator + Clone,
101    I::Item: Clone,
102{
103    fn clone(&self) -> Self {
104        Self {
105            iter: self.iter.clone(),
106            len: self.len,
107        }
108    }
109}
110
111impl<I, const N: usize> Iterator for CircularArrayWindows<I, N>
112where
113    I: Iterator + Clone,
114    I::Item: Clone,
115{
116    type Item = [I::Item; N];
117
118    #[inline]
119    fn next(&mut self) -> Option<Self::Item> {
120        if self.len != 0 {
121            self.len -= 1;
122            self.iter.next()
123        } else {
124            None
125        }
126    }
127
128    #[inline]
129    fn size_hint(&self) -> (usize, Option<usize>) {
130        (self.len, Some(self.len))
131    }
132
133    #[inline]
134    fn count(self) -> usize {
135        self.len
136    }
137}
138
139impl<I, const N: usize> ExactSizeIterator for CircularArrayWindows<I, N>
140where
141    I: ExactSizeIterator + Clone,
142    I::Item: Clone,
143{
144}
145
146impl<I, const N: usize> FusedIterator for CircularArrayWindows<I, N>
147where
148    I: ExactSizeIterator + Clone,
149    I::Item: Clone,
150{
151}