circular_buffer/
iter.rs

1// Copyright © 2023-2025 Andrea Corbellini and contributors
2// SPDX-License-Identifier: BSD-3-Clause
3
4use crate::CircularBuffer;
5use core::fmt;
6use core::iter::FusedIterator;
7use core::ops::Bound;
8use core::ops::RangeBounds;
9
10/// An owning [iterator](core::iter::Iterator) over the elements of a [`CircularBuffer`].
11///
12/// This yields the elements of a `CircularBuffer` from front to back.
13///
14/// This struct is created when iterating over a `CircularBuffer`. See the documentation for
15/// [`IntoIterator`] for more details.
16#[derive(Clone)]
17pub struct IntoIter<const N: usize, T> {
18    inner: CircularBuffer<N, T>,
19}
20
21impl<const N: usize, T> IntoIter<N, T> {
22    pub(crate) const fn new(inner: CircularBuffer<N, T>) -> Self {
23        Self { inner }
24    }
25}
26
27impl<const N: usize, T> Iterator for IntoIter<N, T> {
28    type Item = T;
29
30    fn next(&mut self) -> Option<Self::Item> {
31        self.inner.pop_front()
32    }
33
34    #[inline]
35    fn size_hint(&self) -> (usize, Option<usize>) {
36        let len = self.inner.len();
37        (len, Some(len))
38    }
39}
40
41impl<const N: usize, T> ExactSizeIterator for IntoIter<N, T> {
42    #[inline]
43    fn len(&self) -> usize {
44        self.inner.len()
45    }
46}
47
48impl<const N: usize, T> FusedIterator for IntoIter<N, T> {}
49
50impl<const N: usize, T> DoubleEndedIterator for IntoIter<N, T> {
51    fn next_back(&mut self) -> Option<Self::Item> {
52        self.inner.pop_back()
53    }
54}
55
56impl<const N: usize, T> fmt::Debug for IntoIter<N, T>
57where
58    T: fmt::Debug,
59{
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        self.inner.fmt(f)
62    }
63}
64
65pub(crate) fn translate_range_bounds<const N: usize, T, R>(
66    buf: &CircularBuffer<N, T>,
67    range: R,
68) -> (usize, usize)
69where
70    R: RangeBounds<usize>,
71{
72    let start = match range.start_bound() {
73        Bound::Included(x) => *x,
74        Bound::Excluded(x) => x
75            .checked_add(1)
76            .expect("range start index exceeds maximum usize"),
77        Bound::Unbounded => 0,
78    };
79
80    let end = match range.end_bound() {
81        Bound::Included(x) => x
82            .checked_add(1)
83            .expect("range end index exceeds maximum usize"),
84        Bound::Excluded(x) => *x,
85        Bound::Unbounded => buf.len(),
86    };
87
88    assert!(
89        end <= buf.len(),
90        "range end index {} out of range for buffer of length {}",
91        end,
92        buf.len()
93    );
94    assert!(
95        start <= end,
96        "range starts at index {start} but ends at index {end}"
97    );
98
99    (start, end)
100}
101
102/// An [iterator](core::iter::Iterator) over the elements of a `CircularBuffer`.
103///
104/// This struct is created by [`CircularBuffer::iter()`] and [`CircularBuffer::range()`]. See
105/// their documentation for more details.
106pub struct Iter<'a, T> {
107    pub(crate) right: &'a [T],
108    pub(crate) left: &'a [T],
109}
110
111impl<'a, T> Iter<'a, T> {
112    pub(crate) const fn empty() -> Self {
113        Self {
114            right: &[],
115            left: &[],
116        }
117    }
118
119    pub(crate) fn new<const N: usize>(buf: &'a CircularBuffer<N, T>) -> Self {
120        let (right, left) = buf.as_slices();
121        Self { right, left }
122    }
123
124    pub(crate) fn over_range<const N: usize, R>(buf: &'a CircularBuffer<N, T>, range: R) -> Self
125    where
126        R: RangeBounds<usize>,
127    {
128        let (start, end) = translate_range_bounds(buf, range);
129        if start >= end {
130            Self::empty()
131        } else {
132            let len = buf.len();
133            let mut it = Self::new(buf);
134            it.advance_front_by(start);
135            it.advance_back_by(len - end);
136            it
137        }
138    }
139
140    fn advance_front_by(&mut self, count: usize) {
141        if self.right.len() > count {
142            let _ = self.right.split_off(..count);
143        } else {
144            let take_left = count - self.right.len();
145            debug_assert!(
146                take_left <= self.left.len(),
147                "attempted to advance past the back of the buffer"
148            );
149            let _ = self.left.split_off(..take_left);
150            self.right = &[];
151        }
152    }
153
154    fn advance_back_by(&mut self, count: usize) {
155        if self.left.len() > count {
156            let take_left = self.left.len() - count;
157            let _ = self.left.split_off(take_left..);
158        } else {
159            let take_right = self.right.len() - (count - self.left.len());
160            debug_assert!(
161                take_right <= self.right.len(),
162                "attempted to advance past the front of the buffer"
163            );
164            let _ = self.right.split_off(take_right..);
165            self.left = &[];
166        }
167    }
168}
169
170impl<T> Default for Iter<'_, T> {
171    #[inline]
172    fn default() -> Self {
173        Self::empty()
174    }
175}
176
177impl<'a, T> Iterator for Iter<'a, T> {
178    type Item = &'a T;
179
180    fn next(&mut self) -> Option<Self::Item> {
181        if let Some(item) = self.right.split_off_first() {
182            Some(item)
183        } else if let Some(item) = self.left.split_off_first() {
184            Some(item)
185        } else {
186            None
187        }
188    }
189
190    #[inline]
191    fn size_hint(&self) -> (usize, Option<usize>) {
192        let len = self.len();
193        (len, Some(len))
194    }
195}
196
197impl<T> ExactSizeIterator for Iter<'_, T> {
198    #[inline]
199    fn len(&self) -> usize {
200        self.right.len() + self.left.len()
201    }
202}
203
204impl<T> FusedIterator for Iter<'_, T> {}
205
206impl<T> DoubleEndedIterator for Iter<'_, T> {
207    fn next_back(&mut self) -> Option<Self::Item> {
208        if let Some(item) = self.left.split_off_last() {
209            Some(item)
210        } else if let Some(item) = self.right.split_off_last() {
211            Some(item)
212        } else {
213            None
214        }
215    }
216}
217
218impl<T> Clone for Iter<'_, T> {
219    fn clone(&self) -> Self {
220        Self {
221            right: self.right,
222            left: self.left,
223        }
224    }
225}
226
227impl<T> fmt::Debug for Iter<'_, T>
228where
229    T: fmt::Debug,
230{
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        f.debug_list().entries(self.clone()).finish()
233    }
234}
235
236/// A mutable [iterator](core::iter::Iterator) over the elements of a `CircularBuffer`.
237///
238/// This struct is created by [`CircularBuffer::iter_mut()`] and [`CircularBuffer::range_mut()`].
239/// See their documentation for more details.
240pub struct IterMut<'a, T> {
241    right: &'a mut [T],
242    left: &'a mut [T],
243}
244
245impl<'a, T> IterMut<'a, T> {
246    pub(crate) fn empty() -> Self {
247        Self {
248            right: &mut [],
249            left: &mut [],
250        }
251    }
252
253    pub(crate) fn new<const N: usize>(buf: &'a mut CircularBuffer<N, T>) -> Self {
254        let (right, left) = buf.as_mut_slices();
255        Self { right, left }
256    }
257
258    pub(crate) fn over_range<const N: usize, R>(buf: &'a mut CircularBuffer<N, T>, range: R) -> Self
259    where
260        R: RangeBounds<usize>,
261    {
262        let (start, end) = translate_range_bounds(buf, range);
263        if start >= end {
264            Self::empty()
265        } else {
266            let len = buf.len();
267            let mut it = Self::new(buf);
268            it.advance_front_by(start);
269            it.advance_back_by(len - end);
270            it
271        }
272    }
273
274    fn advance_front_by(&mut self, count: usize) {
275        if self.right.len() > count {
276            let _ = self.right.split_off_mut(..count);
277        } else {
278            let take_left = count - self.right.len();
279            debug_assert!(
280                take_left <= self.left.len(),
281                "attempted to advance past the back of the buffer"
282            );
283            let _ = self.left.split_off_mut(..take_left);
284            self.right = &mut [];
285        }
286    }
287
288    fn advance_back_by(&mut self, count: usize) {
289        if self.left.len() > count {
290            let take_left = self.left.len() - count;
291            let _ = self.left.split_off_mut(take_left..);
292        } else {
293            let take_right = self.right.len() - (count - self.left.len());
294            debug_assert!(
295                take_right <= self.right.len(),
296                "attempted to advance past the front of the buffer"
297            );
298            let _ = self.right.split_off_mut(take_right..);
299            self.left = &mut [];
300        }
301    }
302}
303
304impl<T> Default for IterMut<'_, T> {
305    #[inline]
306    fn default() -> Self {
307        Self::empty()
308    }
309}
310
311impl<'a, T> Iterator for IterMut<'a, T> {
312    type Item = &'a mut T;
313
314    fn next(&mut self) -> Option<Self::Item> {
315        if let Some(item) = self.right.split_off_first_mut() {
316            Some(item)
317        } else if let Some(item) = self.left.split_off_first_mut() {
318            Some(item)
319        } else {
320            None
321        }
322    }
323
324    #[inline]
325    fn size_hint(&self) -> (usize, Option<usize>) {
326        let len = self.len();
327        (len, Some(len))
328    }
329}
330
331impl<T> ExactSizeIterator for IterMut<'_, T> {
332    #[inline]
333    fn len(&self) -> usize {
334        self.right.len() + self.left.len()
335    }
336}
337
338impl<T> FusedIterator for IterMut<'_, T> {}
339
340impl<T> DoubleEndedIterator for IterMut<'_, T> {
341    fn next_back(&mut self) -> Option<Self::Item> {
342        if let Some(item) = self.left.split_off_last_mut() {
343            Some(item)
344        } else if let Some(item) = self.right.split_off_last_mut() {
345            Some(item)
346        } else {
347            None
348        }
349    }
350}
351
352impl<T> fmt::Debug for IterMut<'_, T>
353where
354    T: fmt::Debug,
355{
356    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
357        let it = Iter {
358            right: self.right,
359            left: self.left,
360        };
361        it.fmt(f)
362    }
363}