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