compressed_intvec/variable/
iter.rs

1//! Iterators for [`IntVec`].
2//!
3//! This module provides the iterators for [`IntVec`]. Due to the nature of
4//! variable-length encoding, an [`IntVec`] is immutable once created, as
5//! modifying an element would require re-encoding the rest of the data stream.
6//!
7//! [`IntVec`]: crate::variable::IntVec
8
9use super::{
10    reader::CodecReader, // Import the robust hybrid dispatcher
11    traits::Storable,
12    IntVec, IntVecBitReader,
13};
14use dsi_bitstream::{
15    dispatch::{CodesRead, StaticCodeRead},
16    prelude::{BitRead, BitSeek, Endianness},
17};
18use std::marker::PhantomData;
19
20/// A borrowing iterator over the values of an [`IntVec`].
21///
22/// This struct is created by the [`iter`](IntVec::iter) method on [`IntVec`].
23/// It provides a sequential, forward-only scan over the compressed data,
24/// decompressing values on the fly.
25///
26/// # Examples
27///
28/// ```
29/// use compressed_intvec::variable::{IntVec, UIntVec};
30///
31/// let data: &[u32] = &[10, 20, 30, 40, 50];
32/// let vec: UIntVec<u32> = IntVec::from_slice(data).unwrap();
33///
34/// let mut sum = 0;
35/// for value in vec.iter() {
36///     sum += value;
37/// }
38///
39/// assert_eq!(sum, 150);
40/// ```
41pub struct IntVecIter<'a, T: Storable, E: Endianness, B: AsRef<[u64]>>
42where
43    for<'b> IntVecBitReader<'b, E>: BitRead<E, Error = core::convert::Infallible>
44        + CodesRead<E>
45        + BitSeek<Error = core::convert::Infallible>,
46{
47    len: usize,
48    reader: IntVecBitReader<'a, E>,
49    /// The hybrid dispatcher that handles codec reading robustly.
50    code_reader: CodecReader<'a, T, E, B>,
51    current_index: usize,
52    _markers: PhantomData<(&'a B, T)>,
53}
54
55impl<'a, T: Storable, E: Endianness, B: AsRef<[u64]>> IntVecIter<'a, T, E, B>
56where
57    for<'b> IntVecBitReader<'b, E>: BitRead<E, Error = core::convert::Infallible>
58        + CodesRead<E>
59        + BitSeek<Error = core::convert::Infallible>,
60{
61    /// Creates a new iterator.
62    pub(super) fn new(intvec: &'a IntVec<T, E, B>) -> Self {
63        let reader = IntVecBitReader::<E>::new(dsi_bitstream::impls::MemWordReader::new(
64            intvec.data.as_ref(),
65        ));
66        // Instantiate the robust hybrid dispatcher. This will not panic.
67        let code_reader = CodecReader::new(intvec.encoding);
68
69        Self {
70            len: intvec.len,
71            reader,
72            code_reader,
73            current_index: 0,
74            _markers: PhantomData,
75        }
76    }
77}
78
79impl<T: Storable, E: Endianness, B: AsRef<[u64]>> Iterator for IntVecIter<'_, T, E, B>
80where
81    for<'b> IntVecBitReader<'b, E>: BitRead<E, Error = core::convert::Infallible>
82        + CodesRead<E>
83        + BitSeek<Error = core::convert::Infallible>,
84{
85    type Item = T;
86
87    #[inline]
88    fn next(&mut self) -> Option<Self::Item> {
89        if self.current_index >= self.len {
90            return None;
91        }
92        // The read operation is infallible due to the robust dispatcher.
93        let value = self.code_reader.read(&mut self.reader).unwrap();
94        self.current_index += 1;
95        Some(Storable::from_word(value))
96    }
97
98    fn size_hint(&self) -> (usize, Option<usize>) {
99        let remaining = self.len.saturating_sub(self.current_index);
100        (remaining, Some(remaining))
101    }
102}
103
104impl<T: Storable, E: Endianness, B: AsRef<[u64]>> ExactSizeIterator for IntVecIter<'_, T, E, B>
105where
106    for<'b> IntVecBitReader<'b, E>: BitRead<E, Error = core::convert::Infallible>
107        + CodesRead<E>
108        + BitSeek<Error = core::convert::Infallible>,
109{
110    fn len(&self) -> usize {
111        self.len.saturating_sub(self.current_index)
112    }
113}
114
115/// An owning iterator over the values of an [`IntVec`].
116///
117/// This struct is created by the [`into_iter`](IntVec::into_iter) method on
118/// [`IntVec`] (or by using a `for` loop on an owned [`IntVec`]). It takes ownership
119/// of the vector and decodes its values on the fly.
120///
121/// # Examples
122///
123/// ```
124/// use compressed_intvec::variable::{IntVec, SIntVec};
125///
126/// let data: &[i16] = &[-1, -2, -3, -4];
127/// let vec: SIntVec<i16> = IntVec::from_slice(data).unwrap();
128///
129/// // The `into_iter` call is implicit in the for loop.
130/// // This loop consumes `vec`.
131/// let collected: Vec<i16> = vec.into_iter().map(|v| v * 2).collect();
132///
133/// assert_eq!(collected, &[-2, -4, -6, -8]);
134/// ```
135pub struct IntVecIntoIter<T, E>
136where
137    T: Storable + 'static,
138    E: Endianness + 'static,
139    for<'a> IntVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
140        + CodesRead<E>
141        + BitSeek<Error = core::convert::Infallible>,
142{
143    /// The number of elements remaining in the iterator.
144    len: usize,
145    /// The current position in the sequence.
146    current_index: usize,
147    /// A stateful reader that borrows from `_data_owner`.
148    reader: IntVecBitReader<'static, E>,
149    /// The hybrid dispatcher for decoding.
150    code_reader: CodecReader<'static, T, E, Vec<u64>>,
151    /// This field owns the data buffer, ensuring it lives as long as the iterator.
152    _data_owner: Vec<u64>,
153    /// Phantom data to hold the generic type `T`.
154    _markers: PhantomData<T>,
155}
156
157impl<T, E> IntVecIntoIter<T, E>
158where
159    T: Storable + 'static,
160    E: Endianness + 'static,
161    for<'a> IntVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
162        + CodesRead<E>
163        + BitSeek<Error = core::convert::Infallible>,
164{
165    /// Creates a new, efficient owning iterator from an `IntVec`.
166    pub(super) fn new(vec: IntVec<T, E, Vec<u64>>) -> Self {
167        // This is a self-referential struct. We move the owned data buffer into `_data_owner`.
168        // Then, we create a 'static reference to that data to initialize the reader.
169        // This is safe because `_data_owner` is part of the same struct as `reader`,
170        // guaranteeing that the data outlives the reference.
171        let data_ref: &'static [u64] = unsafe { std::mem::transmute(vec.data.as_slice()) };
172
173        let reader = IntVecBitReader::<E>::new(dsi_bitstream::impls::MemWordReader::new(data_ref));
174        let code_reader = CodecReader::new(vec.encoding);
175
176        Self {
177            len: vec.len,
178            current_index: 0,
179            reader,
180            code_reader,
181            _data_owner: vec.data,
182            _markers: PhantomData,
183        }
184    }
185}
186
187impl<T, E> Iterator for IntVecIntoIter<T, E>
188where
189    T: Storable + 'static,
190    E: Endianness + 'static,
191    for<'a> IntVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
192        + CodesRead<E>
193        + BitSeek<Error = core::convert::Infallible>,
194{
195    type Item = T;
196
197    #[inline]
198    fn next(&mut self) -> Option<Self::Item> {
199        if self.current_index >= self.len {
200            return None;
201        }
202        let value = self.code_reader.read(&mut self.reader).unwrap();
203        self.current_index += 1;
204        Some(Storable::from_word(value))
205    }
206
207    fn size_hint(&self) -> (usize, Option<usize>) {
208        let remaining = self.len.saturating_sub(self.current_index);
209        (remaining, Some(remaining))
210    }
211}
212
213impl<T, E> ExactSizeIterator for IntVecIntoIter<T, E>
214where
215    T: Storable + 'static,
216    E: Endianness + 'static,
217    for<'a> IntVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
218        + CodesRead<E>
219        + BitSeek<Error = core::convert::Infallible>,
220{
221    fn len(&self) -> usize {
222        self.len.saturating_sub(self.current_index)
223    }
224}