Skip to main content

circular_buffer/
iter.rs

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