Skip to main content

compressed_intvec/fixed/
iter.rs

1//! # [`FixedVec`] Iterators
2//!
3//! This module provides iterators for sequential access to the elements of a
4//! [`FixedVec`]. The iterators decode values on the fly without allocating an
5//! intermediate buffer, making them efficient for processing large datasets.
6//!
7//! The core iterators ([`FixedVecIter`], [`FixedVecSliceIter`]) are stateful and
8//! employ a bit-windowing technique. They decode values on the fly without
9//! allocating an intermediate buffer. They support both forward and reverse
10//! iteration.
11//!
12//! # Provided Iterators
13//!
14//! - [`FixedVecIter`]: A stateful, bidirectional iterator over the elements of a borrowed [`FixedVec`].
15//! - [`FixedVecIntoIter`]: A consuming, bidirectional iterator that takes ownership of a [`FixedVec`].
16//! - [`FixedVecSliceIter`]: A stateful, bidirectional iterator over the elements of a [`FixedVecSlice`].
17//! - [`Chunks`]: An iterator that yields non-overlapping, immutable slices ([`FixedVecSlice`]).
18//! - [`Windows`]: An iterator that yields overlapping, immutable slices ([`FixedVecSlice`]).
19//! - [`FixedVecUncheckedIter`]: An `unsafe` bidirectional iterator that omits bounds checks for maximum performance.
20//!
21//! # Examples
22//!
23//! ## Iterating over elements
24//!
25//! ```rust
26//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
27//! use compressed_intvec::fixed::{FixedVec, SFixedVec};
28//!
29//! let data: &[i16] = &[-100, 0, 100, 200];
30//! let vec: SFixedVec<i16> = FixedVec::builder().build(data)?;
31//!
32//! let mut sum = 0;
33//! for value in vec.iter() {
34//!     sum += value;
35//! }
36//!
37//! assert_eq!(sum, 200);
38//! # Ok(())
39//! # }
40//! ```
41//!
42//! ## Bidirectional Iteration
43//!
44//! The main iterators implement [`DoubleEndedIterator`], allowing for
45//! traversal from both ends of the sequence.
46//!
47//! ```rust
48//! use compressed_intvec::fixed::{FixedVec, UFixedVec};
49//!
50//! let vec: UFixedVec<u8> = (0..=5u8).collect();
51//! let mut iter = vec.iter();
52//!
53//! assert_eq!(iter.next(), Some(0));
54//! assert_eq!(iter.next_back(), Some(5));
55//! assert_eq!(iter.next(), Some(1));
56//! assert_eq!(iter.next_back(), Some(4));
57//!
58//! // The iterator correctly tracks its remaining length.
59//! assert_eq!(iter.len(), 2);
60//!
61//! assert_eq!(iter.next(), Some(2));
62//! assert_eq!(iter.next(), Some(3));
63//! assert_eq!(iter.next(), None);
64//! ```
65//!
66//! ## Iterating over a Slice
67//!
68//! You can also create an iterator over a zero-copy slice of a vector.
69//!
70//! ```rust
71//! use compressed_intvec::fixed::{FixedVec, UFixedVec};
72//!
73//! let vec: UFixedVec<u32> = (0..100u32).collect();
74//!
75//! // Create a slice containing elements from index 20 to 29.
76//! let slice = vec.slice(20, 10).expect("slice failed");
77//! assert_eq!(slice.len(), 10);
78//!
79//! // The slice iterator will yield the elements from the slice.
80//! let collected: Vec<u32> = slice.iter().collect();
81//! let expected: Vec<u32> = (20..30).collect();
82//!
83//! assert_eq!(collected, expected);
84//! ```
85
86use crate::fixed::{
87    FixedVec,
88    slice::FixedVecSlice,
89    traits::{Storable, Word},
90};
91use dsi_bitstream::prelude::Endianness;
92use std::{marker::PhantomData, ops::Deref};
93
94use std::cmp::min;
95
96/// An iterator over the elements of a borrowed [`FixedVec`].
97///
98/// This struct is created by the [`iter`](FixedVec::iter) method. It is a
99/// stateful bitstream reader that decodes values on the fly for both forward
100/// and reverse iteration.
101///
102/// # Examples
103///
104/// ## Forward iteration
105///
106/// ```rust
107/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
108/// use compressed_intvec::fixed::{FixedVec, UFixedVec};
109///
110/// let data: &[u8] = &[1, 2, 3, 4, 5];
111/// let vec: UFixedVec<u8> = FixedVec::builder().build(data)?;
112/// let mut iter = vec.iter();
113///
114/// assert_eq!(iter.next(), Some(1));
115/// assert_eq!(iter.next(), Some(2));
116/// # Ok(())
117/// # }
118/// ```
119///
120/// ## Reverse iteration
121///
122/// ```rust
123/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
124/// use compressed_intvec::fixed::{FixedVec, UFixedVec};
125///
126/// let data: &[u8] = &[1, 2, 3, 4, 5];
127/// let vec: UFixedVec<u8> = FixedVec::builder().build(data)?;
128/// let mut iter = vec.iter();
129///
130/// assert_eq!(iter.next_back(), Some(5));
131/// assert_eq!(iter.next_back(), Some(4));
132/// # Ok(())
133/// # }
134/// ```
135#[derive(Debug)]
136pub struct FixedVecIter<'a, T, W, E, B>
137where
138    T: Storable<W>,
139    W: Word,
140    E: Endianness,
141    B: AsRef<[W]>,
142{
143    vec: &'a FixedVec<T, W, E, B>,
144    front_index: usize,
145    back_index: usize,
146
147    // State for forward iteration.
148    front_window: W,
149    front_bits_in_window: usize,
150    front_word_index: usize,
151
152    // State for backward iteration.
153    back_window: W,
154    back_bits_in_window: usize,
155    back_word_index: usize,
156    _phantom: PhantomData<T>,
157}
158
159/// An iterator over non-overlapping, immutable chunks of a [`FixedVec`].
160///
161/// This struct is created by the [`chunks`](super::FixedVec::chunks) method.
162#[derive(Debug)]
163pub struct Chunks<'a, T, W, E, B>
164where
165    T: Storable<W>,
166    W: Word,
167    E: Endianness,
168    B: AsRef<[W]>,
169{
170    vec: &'a FixedVec<T, W, E, B>,
171    chunk_size: usize,
172    current_pos: usize,
173}
174
175impl<'a, T, W, E, B> FixedVecIter<'a, T, W, E, B>
176where
177    T: Storable<W>,
178    W: Word,
179    E: Endianness,
180    B: AsRef<[W]>,
181{
182    /// Creates a new stateful, bidirectional iterator for a given [`FixedVec`].
183    pub(super) fn new(vec: &'a FixedVec<T, W, E, B>) -> Self {
184        if vec.is_empty() {
185            return Self {
186                vec,
187                front_index: 0,
188                back_index: 0,
189                front_window: W::ZERO,
190                front_bits_in_window: 0,
191                front_word_index: 0,
192                back_window: W::ZERO,
193                back_bits_in_window: 0,
194                back_word_index: 0,
195                _phantom: PhantomData,
196            };
197        }
198
199        let limbs = vec.as_limbs();
200        let bits_per_word: usize = <W as Word>::BITS;
201
202        // --- Setup forward state ---
203        let front_word_index = 1;
204        // Pre-load the first word into the forward window.
205        let front_window = unsafe { *limbs.get_unchecked(0) };
206        let front_bits_in_window = bits_per_word;
207
208        // --- Setup backward state ---
209        let total_bits = vec.len() * vec.bit_width();
210        let back_word_index = (total_bits.saturating_sub(1)) / bits_per_word;
211        // Pre-load the last word into the backward window.
212        let back_window = unsafe { *limbs.get_unchecked(back_word_index) };
213        // Calculate how many bits in the last word are valid data.
214        let back_bits_in_window = total_bits % bits_per_word;
215        let back_bits_in_window = if back_bits_in_window == 0 {
216            bits_per_word
217        } else {
218            back_bits_in_window
219        };
220
221        Self {
222            vec,
223            front_index: 0,
224            back_index: vec.len(),
225            front_window,
226            front_bits_in_window,
227            front_word_index,
228            back_window,
229            back_bits_in_window,
230            back_word_index,
231            _phantom: PhantomData,
232        }
233    }
234}
235
236impl<T, W, E, B> Iterator for FixedVecIter<'_, T, W, E, B>
237where
238    T: Storable<W>,
239    W: Word,
240    E: Endianness,
241    B: AsRef<[W]>,
242{
243    type Item = T;
244
245    #[inline]
246    fn next(&mut self) -> Option<Self::Item> {
247        if self.front_index >= self.back_index {
248            return None;
249        }
250        let index = self.front_index;
251        self.front_index += 1;
252
253        let bit_width = self.vec.bit_width();
254        // Path for word-sized elements.
255        if bit_width == <W as Word>::BITS {
256            let val = unsafe { *self.vec.as_limbs().get_unchecked(index) };
257            let final_val = if E::IS_BIG { W::from_be(val) } else { val };
258            return Some(<T as Storable<W>>::from_word(final_val));
259        }
260
261        // Fallback to the standard `get_unchecked` for Big-Endian.
262        if E::IS_BIG {
263            return Some(unsafe { self.vec.get_unchecked(index) });
264        }
265
266        let mask = self.vec.mask;
267        // If the current window has enough bits for the next element.
268        if self.front_bits_in_window >= bit_width {
269            let value = self.front_window & mask;
270            self.front_window >>= bit_width;
271            self.front_bits_in_window -= bit_width;
272            return Some(<T as Storable<W>>::from_word(value));
273        }
274
275        // Otherwise, load the next word to replenish the window.
276        unsafe {
277            let limbs = self.vec.as_limbs();
278            let bits_from_old = self.front_bits_in_window;
279            let mut result = self.front_window;
280
281            self.front_window = *limbs.get_unchecked(self.front_word_index);
282            self.front_word_index += 1;
283            result |= self.front_window << bits_from_old;
284            let value = result & mask;
285
286            let bits_from_new = bit_width - bits_from_old;
287            self.front_window >>= bits_from_new;
288            self.front_bits_in_window = <W as Word>::BITS - bits_from_new;
289
290            Some(<T as Storable<W>>::from_word(value))
291        }
292    }
293
294    fn size_hint(&self) -> (usize, Option<usize>) {
295        let remaining = self.back_index.saturating_sub(self.front_index);
296        (remaining, Some(remaining))
297    }
298}
299
300impl<T, W, E, B> DoubleEndedIterator for FixedVecIter<'_, T, W, E, B>
301where
302    T: Storable<W>,
303    W: Word,
304    E: Endianness,
305    B: AsRef<[W]>,
306{
307    #[inline]
308    fn next_back(&mut self) -> Option<Self::Item> {
309        if self.front_index >= self.back_index {
310            return None;
311        }
312        self.back_index -= 1;
313        let index = self.back_index;
314
315        if E::IS_BIG || self.vec.bit_width() == <W as Word>::BITS {
316            return Some(unsafe { self.vec.get_unchecked(index) });
317        }
318
319        let bit_width = self.vec.bit_width();
320        let bits_per_word: usize = <W as Word>::BITS;
321
322        if self.back_bits_in_window >= bit_width {
323            self.back_bits_in_window -= bit_width;
324            let value = (self.back_window >> self.back_bits_in_window) & self.vec.mask;
325            return Some(<T as Storable<W>>::from_word(value));
326        }
327
328        unsafe {
329            let limbs = self.vec.as_limbs();
330            let bits_from_old = self.back_bits_in_window;
331            let mut result = self.back_window;
332
333            self.back_word_index -= 1;
334            self.back_window = *limbs.get_unchecked(self.back_word_index);
335
336            result &= (W::ONE << bits_from_old).wrapping_sub(W::ONE);
337            let bits_from_new = bit_width - bits_from_old;
338            result <<= bits_from_new;
339            result |= self.back_window >> (bits_per_word - bits_from_new);
340
341            self.back_bits_in_window = bits_per_word - bits_from_new;
342            Some(<T as Storable<W>>::from_word(result))
343        }
344    }
345}
346
347impl<T, W, E, B> ExactSizeIterator for FixedVecIter<'_, T, W, E, B>
348where
349    T: Storable<W>,
350    W: Word,
351    E: Endianness,
352    B: AsRef<[W]>,
353{
354    fn len(&self) -> usize {
355        self.back_index.saturating_sub(self.front_index)
356    }
357}
358
359/// An iterator that consumes an owned [`FixedVec`] and yields its elements.
360///
361/// This struct is created by the `into_iter` method on `FixedVec`.
362///
363/// # Implementation
364///
365/// This is a self-referential struct: the [`FixedVecIter`] borrows from the
366/// heap-allocated [`FixedVec`] stored in `_vec_owner`. The `Box` ensures a
367/// stable address that won't move, making the `'static` transmute sound.
368/// The `iter` field is declared before `_vec_owner` so it is dropped first,
369/// though neither type has a custom `Drop` that accesses borrowed data.
370pub struct FixedVecIntoIter<T, W, E>
371where
372    T: Storable<W> + 'static,
373    W: Word,
374    E: Endianness,
375{
376    iter: FixedVecIter<'static, T, W, E, Vec<W>>,
377    /// Owns the `FixedVec` on the heap. Must outlive `iter`.
378    _vec_owner: Box<FixedVec<T, W, E, Vec<W>>>,
379}
380
381impl<T, W, E> FixedVecIntoIter<T, W, E>
382where
383    T: Storable<W> + 'static,
384    W: Word,
385    E: Endianness,
386{
387    /// Creates a new consuming iterator from an owned `FixedVec`.
388    pub(super) fn new(vec: FixedVec<T, W, E, Vec<W>>) -> Self {
389        // Move the FixedVec to the heap so it has a stable address.
390        let boxed = Box::new(vec);
391        // SAFETY: `boxed` is heap-allocated and will not move. The reference
392        // is valid for the lifetime of this struct because `_vec_owner` holds
393        // the Box. We transmute to 'static to express this self-referential
394        // borrow, which cannot be expressed with Rust lifetimes.
395        let iter = unsafe {
396            let vec_ref: &'static FixedVec<T, W, E, Vec<W>> =
397                std::mem::transmute(&*boxed as &FixedVec<T, W, E, Vec<W>>);
398            FixedVecIter::new(vec_ref)
399        };
400        Self {
401            iter,
402            _vec_owner: boxed,
403        }
404    }
405}
406
407impl<T, W, E> Iterator for FixedVecIntoIter<T, W, E>
408where
409    T: Storable<W> + 'static,
410    W: Word,
411    E: Endianness,
412{
413    type Item = T;
414
415    #[inline]
416    fn next(&mut self) -> Option<Self::Item> {
417        self.iter.next()
418    }
419
420    fn size_hint(&self) -> (usize, Option<usize>) {
421        self.iter.size_hint()
422    }
423}
424
425impl<T, W, E> DoubleEndedIterator for FixedVecIntoIter<T, W, E>
426where
427    T: Storable<W> + 'static,
428    W: Word,
429    E: Endianness,
430{
431    #[inline]
432    fn next_back(&mut self) -> Option<Self::Item> {
433        self.iter.next_back()
434    }
435}
436
437impl<T, W, E> ExactSizeIterator for FixedVecIntoIter<T, W, E>
438where
439    T: Storable<W> + 'static,
440    W: Word,
441    E: Endianness,
442{
443    fn len(&self) -> usize {
444        self.iter.len()
445    }
446}
447
448/// An iterator over the elements of a [`FixedVecSlice`].
449///
450/// This struct is created by the [`iter`](super::slice::FixedVecSlice::iter)
451/// method on [`FixedVecSlice`]. It is a stateful bitstream reader that decodes
452/// values on the fly for both forward and reverse iteration.
453pub struct FixedVecSliceIter<'s, T, W, E, B, V>
454where
455    T: Storable<W>,
456    W: Word,
457    E: Endianness,
458    B: AsRef<[W]>,
459    V: Deref<Target = FixedVec<T, W, E, B>>,
460{
461    slice: &'s FixedVecSlice<V>,
462    front_index: usize, // index relative to slice start
463    back_index: usize,  // index relative to slice start
464
465    // State for forward iteration.
466    front_window: W,
467    front_bits_in_window: usize,
468    front_word_index: usize,
469
470    // State for backward iteration.
471    back_window: W,
472    back_bits_in_window: usize,
473    back_word_index: usize,
474
475    _phantom: PhantomData<(T, W, E, B)>,
476}
477
478impl<'s, T, W, E, B, V> FixedVecSliceIter<'s, T, W, E, B, V>
479where
480    T: Storable<W>,
481    W: Word,
482    E: Endianness,
483    B: AsRef<[W]>,
484    V: Deref<Target = FixedVec<T, W, E, B>>,
485{
486    /// Creates a new stateful, bidirectional iterator for a given `FixedVecSlice`.
487    pub(super) fn new(slice: &'s FixedVecSlice<V>) -> Self {
488        let parent_vec = &slice.parent;
489        if slice.is_empty() {
490            return Self {
491                slice,
492                front_index: 0,
493                back_index: 0,
494                front_window: W::ZERO,
495                front_bits_in_window: 0,
496                front_word_index: 0,
497                back_window: W::ZERO,
498                back_bits_in_window: 0,
499                back_word_index: 0,
500                _phantom: PhantomData,
501            };
502        }
503
504        let bits_per_word: usize = <W as Word>::BITS;
505        let bit_width: usize = parent_vec.bit_width();
506        let limbs: &[W] = parent_vec.as_limbs();
507        let slice_start_abs: usize = slice.range.start;
508        let slice_end_abs: usize = slice.range.end;
509
510        // --- Setup forward state ---
511        let start_bit_pos: usize = slice_start_abs * bit_width;
512        let start_word_index: usize = start_bit_pos / bits_per_word;
513        let start_bit_offset: usize = start_bit_pos % bits_per_word;
514
515        let front_window_raw: W = unsafe { *limbs.get_unchecked(start_word_index) };
516        let front_window: W = front_window_raw >> start_bit_offset;
517        let front_bits_in_window: usize = bits_per_word - start_bit_offset;
518        let front_word_index: usize = start_word_index + 1;
519
520        // --- Setup backward state ---
521        let end_bit_pos: usize = slice_end_abs * bit_width;
522        let back_word_index: usize = (end_bit_pos.saturating_sub(1)) / bits_per_word;
523        let back_window: W = unsafe { *limbs.get_unchecked(back_word_index) };
524
525        let back_bits_in_window = end_bit_pos % bits_per_word;
526        let back_bits_in_window = if back_bits_in_window == 0 && end_bit_pos > 0 {
527            bits_per_word
528        } else {
529            back_bits_in_window
530        };
531
532        Self {
533            slice,
534            front_index: 0,
535            back_index: slice.len(),
536            front_window,
537            front_bits_in_window,
538            front_word_index,
539            back_window,
540            back_bits_in_window,
541            back_word_index,
542            _phantom: PhantomData,
543        }
544    }
545}
546
547impl<T, W, E, B, V> Iterator for FixedVecSliceIter<'_, T, W, E, B, V>
548where
549    T: Storable<W>,
550    W: Word,
551    E: Endianness,
552    B: AsRef<[W]>,
553    V: Deref<Target = FixedVec<T, W, E, B>>,
554{
555    type Item = T;
556
557    #[inline]
558    fn next(&mut self) -> Option<Self::Item> {
559        if self.front_index >= self.back_index {
560            return None;
561        }
562
563        let parent_vec = &self.slice.parent;
564        let bit_width = parent_vec.bit_width();
565        let mask = parent_vec.mask;
566
567        let abs_index = self.slice.range.start + self.front_index;
568        self.front_index += 1;
569
570        if bit_width == <W as Word>::BITS {
571            let val = unsafe { *parent_vec.as_limbs().get_unchecked(abs_index) };
572            let final_val = if E::IS_BIG { W::from_be(val) } else { val };
573            return Some(<T as Storable<W>>::from_word(final_val));
574        }
575
576        if E::IS_BIG {
577            return Some(unsafe { parent_vec.get_unchecked(abs_index) });
578        }
579
580        if self.front_bits_in_window >= bit_width {
581            let value = self.front_window & mask;
582            self.front_window >>= bit_width;
583            self.front_bits_in_window -= bit_width;
584            return Some(<T as Storable<W>>::from_word(value));
585        }
586
587        unsafe {
588            let limbs = parent_vec.as_limbs();
589            let bits_from_old = self.front_bits_in_window;
590            let mut result = self.front_window;
591
592            self.front_window = *limbs.get_unchecked(self.front_word_index);
593            self.front_word_index += 1;
594            result |= self.front_window << bits_from_old;
595            let value = result & mask;
596
597            let bits_from_new = bit_width - bits_from_old;
598            self.front_window >>= bits_from_new;
599            self.front_bits_in_window = <W as Word>::BITS - bits_from_new;
600
601            Some(<T as Storable<W>>::from_word(value))
602        }
603    }
604
605    fn size_hint(&self) -> (usize, Option<usize>) {
606        let remaining = self.back_index.saturating_sub(self.front_index);
607        (remaining, Some(remaining))
608    }
609}
610
611impl<T, W, E, B, V> DoubleEndedIterator for FixedVecSliceIter<'_, T, W, E, B, V>
612where
613    T: Storable<W>,
614    W: Word,
615    E: Endianness,
616    B: AsRef<[W]>,
617    V: Deref<Target = FixedVec<T, W, E, B>>,
618{
619    #[inline]
620    fn next_back(&mut self) -> Option<Self::Item> {
621        if self.front_index >= self.back_index {
622            return None;
623        }
624        self.back_index -= 1;
625        let abs_index = self.slice.range.start + self.back_index;
626        let parent_vec = &self.slice.parent;
627
628        if E::IS_BIG || parent_vec.bit_width() == <W as Word>::BITS {
629            return Some(unsafe { parent_vec.get_unchecked(abs_index) });
630        }
631
632        let bit_width = parent_vec.bit_width();
633        let bits_per_word: usize = <W as Word>::BITS;
634
635        if self.back_bits_in_window >= bit_width {
636            self.back_bits_in_window -= bit_width;
637            let value = (self.back_window >> self.back_bits_in_window) & parent_vec.mask;
638            return Some(<T as Storable<W>>::from_word(value));
639        }
640
641        unsafe {
642            let limbs = parent_vec.as_limbs();
643            let bits_from_old = self.back_bits_in_window;
644            let mut result = self.back_window;
645
646            self.back_word_index -= 1;
647            self.back_window = *limbs.get_unchecked(self.back_word_index);
648
649            result &= (W::ONE << bits_from_old).wrapping_sub(W::ONE);
650            let bits_from_new = bit_width - bits_from_old;
651            result <<= bits_from_new;
652            result |= self.back_window >> (bits_per_word - bits_from_new);
653
654            self.back_bits_in_window = bits_per_word - bits_from_new;
655            Some(<T as Storable<W>>::from_word(result))
656        }
657    }
658}
659
660impl<T, W, E, B, V> ExactSizeIterator for FixedVecSliceIter<'_, T, W, E, B, V>
661where
662    T: Storable<W>,
663    W: Word,
664    E: Endianness,
665    B: AsRef<[W]>,
666    V: Deref<Target = FixedVec<T, W, E, B>>,
667{
668    fn len(&self) -> usize {
669        self.back_index.saturating_sub(self.front_index)
670    }
671}
672
673impl<'a, T, W, E, B> Chunks<'a, T, W, E, B>
674where
675    T: Storable<W>,
676    W: Word,
677    E: Endianness,
678    B: AsRef<[W]>,
679{
680    /// Creates a new `Chunks` iterator.
681    pub(super) fn new(vec: &'a FixedVec<T, W, E, B>, chunk_size: usize) -> Self {
682        assert!(chunk_size != 0, "chunk_size cannot be zero");
683        Self {
684            vec,
685            chunk_size,
686            current_pos: 0,
687        }
688    }
689}
690
691impl<'a, T, W, E, B> Iterator for Chunks<'a, T, W, E, B>
692where
693    T: Storable<W>,
694    W: Word,
695    E: Endianness,
696    B: AsRef<[W]>,
697{
698    type Item = FixedVecSlice<&'a FixedVec<T, W, E, B>>;
699
700    fn next(&mut self) -> Option<Self::Item> {
701        if self.current_pos >= self.vec.len() {
702            return None;
703        }
704
705        let len = min(self.chunk_size, self.vec.len() - self.current_pos);
706        let slice = FixedVecSlice::new(self.vec, self.current_pos..self.current_pos + len);
707        self.current_pos += len;
708
709        Some(slice)
710    }
711}
712
713/// An iterator over overlapping sub-slices of a [`FixedVec`].
714///
715/// This struct is created by the [`windows`](super::FixedVec::windows) method.
716pub struct Windows<'a, T, W, E, B>
717where
718    T: Storable<W>,
719    W: Word,
720    E: Endianness,
721    B: AsRef<[W]>,
722{
723    vec: &'a FixedVec<T, W, E, B>,
724    size: usize,
725    current_pos: usize,
726}
727
728impl<'a, T, W, E, B> Windows<'a, T, W, E, B>
729where
730    T: Storable<W>,
731    W: Word,
732    E: Endianness,
733    B: AsRef<[W]>,
734{
735    /// Creates a new `Windows` iterator.
736    pub(super) fn new(vec: &'a FixedVec<T, W, E, B>, size: usize) -> Self {
737        Self {
738            vec,
739            size,
740            current_pos: 0,
741        }
742    }
743}
744
745impl<'a, T, W, E, B> Iterator for Windows<'a, T, W, E, B>
746where
747    T: Storable<W>,
748    W: Word,
749    E: Endianness,
750    B: AsRef<[W]>,
751{
752    type Item = FixedVecSlice<&'a FixedVec<T, W, E, B>>;
753
754    fn next(&mut self) -> Option<Self::Item> {
755        if self.current_pos + self.size > self.vec.len() {
756            return None;
757        }
758
759        let slice = FixedVecSlice::new(self.vec, self.current_pos..self.current_pos + self.size);
760        self.current_pos += 1;
761
762        Some(slice)
763    }
764}
765
766/// An unchecked iterator over the elements of a [`FixedVec`].
767///
768/// This struct is created by the [`iter_unchecked`](super::FixedVec::iter_unchecked)
769/// method. It does not perform any bounds checking.
770///
771/// # Safety
772///
773/// The iterator is safe to use only if it is guaranteed that it will not
774/// be advanced beyond the end of the vector.
775pub struct FixedVecUncheckedIter<'a, T, W, E, B>
776where
777    T: Storable<W>,
778    W: Word,
779    E: Endianness,
780    B: AsRef<[W]>,
781{
782    iter: FixedVecIter<'a, T, W, E, B>,
783}
784
785impl<'a, T, W, E, B> FixedVecUncheckedIter<'a, T, W, E, B>
786where
787    T: Storable<W>,
788    W: Word,
789    E: Endianness,
790    B: AsRef<[W]>,
791{
792    /// Creates a new `FixedVecUncheckedIter`.
793    pub(super) fn new(vec: &'a FixedVec<T, W, E, B>) -> Self {
794        Self {
795            iter: FixedVecIter::new(vec),
796        }
797    }
798
799    /// Returns the next element without bounds checking.
800    ///
801    /// # Safety
802    ///
803    /// Calling this method when the iterator is exhausted is undefined behavior.
804    #[inline]
805    pub unsafe fn next_unchecked(&mut self) -> T {
806        // The underlying FixedVecIter is already highly optimized.
807        // The primary gain here is removing the check in `next()`.
808        unsafe { self.iter.next().unwrap_unchecked() }
809    }
810
811    /// Returns the next element from the back without bounds checking.
812    ///
813    /// # Safety
814    ///
815    /// Calling this method when the iterator is exhausted is undefined behavior.
816    #[inline]
817    pub unsafe fn next_back_unchecked(&mut self) -> T {
818        unsafe { self.iter.next_back().unwrap_unchecked() }
819    }
820}