Skip to main content

compressed_intvec/variable/
mod.rs

1//! A compressed integer vector using variable-length encoding with fast random access.
2//!
3//! This module provides [`VarVec`], a data structure for storing sequences of
4//! integers in a compressed format while retaining efficient random access. It is
5//! well-suited for datasets where integer values are non-uniformly distributed,
6//! as it uses instantaneous variable-length codes to represent smaller numbers with fewer bits.
7//!
8//! # Core Concepts
9//!
10//! ## Variable-Length Encoding
11//!
12//! Unlike [`FixedVec`], which uses a fixed number of
13//! bits for every integer, [`VarVec`] employs **instantaneous codes** (such as
14//! Gamma, Delta, or Rice codes) provided by the [`dsi-bitstream`] crate. This
15//! approach allows each integer to be encoded with a variable number of bits,
16//! typically using shorter codes for smaller or more frequent values. This can
17//! lead to significant space savings, especially for data with many small numbers.
18//!
19//! Signed integers (e.g., `i8`, `i32`) are supported transparently through
20//! zig-zag encoding, which maps small negative and positive integers to small
21//! unsigned integers.
22//!
23//! ## Random Access and Sampling
24//!
25//! A key challenge with variable-length codes is that the location of the *i*-th
26//! element cannot be calculated directly. To solve this, [`VarVec`] implements a
27//! **sampling mechanism**. It stores the bit position of every *k*-th element in
28//! a separate, auxiliary [`FixedVec`]. This parameter, `k`, is the **sampling rate**.
29//!
30//! To access an element at `index`, [`VarVec`]:
31//! 1.  Finds the nearest sample by calculating `index / k`.
32//! 2.  Retrieves the bit offset of the start of that sampled block.
33//! 3.  Jumps to that offset in the compressed data stream.
34//! 4.  Sequentially decodes the remaining `index % k` elements to reach the target.
35//!
36//! This strategy provides amortized O(1) random access, as the number of
37//! sequential decoding steps is bounded by `k`.
38//!
39//! ### The `k` Trade-off
40//!
41//! The choice of the sampling rate `k` involves a trade-off:
42//! -   **Smaller `k`**: Faster random access (fewer elements to decode per access)
43//!     but higher memory usage due to a larger samples table.
44//! -   **Larger `k`**: Slower random access but better compression, as the
45//!     samples table is smaller.
46//!
47//! The optimal `k` depends on the specific access patterns of an application.
48//!
49//! # Design and Immutability
50//!
51//! [`VarVec`] is **immutable** after creation.
52//! Unlike [`FixedVec`], it does not provide methods for
53//! in-place modification (e.g., `set`, `push`).
54//!
55//! If a value in the middle of the compressed bitstream were changed, its new
56//! encoded length might be different. For example, changing `5` (which might be
57//! 4 bits) to `5000` (which might be 16 bits) would require shifting all
58//! subsequent data, invalidating every sample point that follows. The cost of
59//! such an operation would be prohibitive, scaling with the length of the vector.
60//!
61//! For this reason, [`VarVec`] is designed as a write-once, read-many data structure.
62//!
63//! # Access Strategies and Readers
64//!
65//! [`VarVec`] provides multiple interfaces for accessing data, each optimized for a
66//! different pattern of use.
67//!
68//! - **[`get()`](VarVec::get)**: For single, infrequent lookups. Each call creates and discards
69//!   an internal reader, which incurs overhead if used in a loop.
70//!
71//! - **[`get_many()`](VarVec::get_many)**: The most efficient method for retrieving a batch of elements
72//!   when all indices are known beforehand. It sorts the indices to perform a
73//!   single, monotonic scan over the data, minimizing redundant decoding and seek
74//!   operations.
75//!
76//! - **[`VarVecReader`] (Reusable Stateless Reader)**: This reader is created via
77//!   [`VarVec::reader()`]. It maintains an internal, reusable bitstream reader,
78//!   amortizing its setup cost over multiple calls. Each [`get()`](VarVec::get) call is
79//!   **stateless** with respect to position: it performs a full seek to the nearest
80//!   sample and decodes forward from there, independently of previous calls. It is
81//!   best suited for true random access patterns where indices are sparse and
82//!   unpredictable.
83//!
84//! - **[`VarVecSeqReader`] (Stateful Sequential Reader)**: This reader, created via
85//!   [`VarVec::seq_reader()`], is a stateful object optimized for access patterns with
86//!   high locality. It maintains an internal cursor of the current decoding position.
87//!   - **Fast Path**: If a requested `index` is at or after the cursor's current
88//!     position and within the same sample block, the reader simply decodes
89//!     forward from its last position, avoiding a costly seek operation.
90//!   - **Fallback Path**: If the requested `index` is before the cursor or in a
91//!     different sample block, the reader falls back to the standard behavior of
92//!     seeking to the nearest sample and decoding from there. This makes it very
93//!     efficient for iterating through sorted or clustered indices.
94//!
95//! # Migration Notice
96//!
97//! As of version 0.6.0, all `IntVec*` types have been renamed to `VarVec*` for
98//! consistency with the module naming convention (`fixed` → `FixedVec`, `seq` → `SeqVec`,
99//! `variable` → `VarVec`). The old names remain available as deprecated type aliases
100//! and will continue to work, but using the new names is recommended.
101//!
102//! # Main Components
103//!
104//! - [`VarVec`]: The core compressed vector.
105//! - [`VarVecBuilder`]: The primary tool for constructing an [`VarVec`] with
106//!   custom compression codecs and sampling rates.
107//! - [`Codec`]: An enum to specify the compression codec.
108//! - [`VarVecReader`]: A reusable, stateless reader for efficient random access.
109//! - [`VarVecSeqReader`]: A stateful reader optimized for sequential or localized access patterns.
110//! - [`VarVecSlice`]: An immutable, zero-copy view over a portion of the vector.
111//!
112//! # Examples
113//!
114//! ## Basic Usage with Unsigned Integers
115//!
116//! Create a [`UVarVec`] (an alias for `VarVec<u32, LE>`) from a slice of `u32`. The builder will automatically
117//! select a suitable codec and use a default sampling rate.
118//!
119//! ```
120//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
121//! use compressed_intvec::variable::{VarVec, UVarVec};
122//!
123//! let data: Vec<u32> = vec![100, 200, 300, 1024];
124//! let vec: UVarVec<u32> = VarVec::from_slice(&data)?;
125//!
126//! assert_eq!(vec.len(), 4);
127//! // Accessing an element
128//! assert_eq!(vec.get(1), Some(200));
129//! # Ok(())
130//! # }
131//! ```
132//!
133//! ## Storing Signed Integers
134//!
135//! [`VarVec`] handles signed integers, such as [`i16`], by mapping them to unsigned
136//! values using zig-zag encoding.
137//!
138//! ```
139//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
140//! use compressed_intvec::variable::{VarVec, SVarVec};
141//!
142//! let data: &[i16] = &[-5, 20, -100, 0, 8];
143//! let vec: SVarVec<i16> = VarVec::from_slice(data)?;
144//!
145//! assert_eq!(vec.len(), 5);
146//! assert_eq!(vec.get(0), Some(-5));
147//! assert_eq!(vec.get(2), Some(-100));
148//! # Ok(())
149//! # }
150//! ```
151//!
152//! ## Manual Codec and Sampling Rate
153//!
154//! For fine-grained control, use the [`VarVecBuilder`]. Here, we specify a
155//! sampling rate of `k=8` and use the `Zeta` code with `k=3`.
156//!
157//! ```
158//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
159//! use compressed_intvec::variable::{VarVec, UVarVec, Codec};
160//!
161//! let data: Vec<u64> = (0..100).map(|i| i * i).collect();
162//!
163//! let vec: UVarVec<u64> = VarVec::builder()
164//!     .k(8) // Set sampling rate
165//!     .codec(Codec::Zeta { k: Some(3) }) // Set compression codec
166//!     .build(&data)?;
167//!
168//! assert_eq!(vec.sampling_rate(), 8);
169//! assert_eq!(vec.get(10), Some(100));
170//! # Ok(())
171//! # }
172//! ```
173//!
174//! Best performance is achieved when the sampling rate `k` is a power of two. Usually a value of `32` or `16` is a good trade-off between speed and compression ratio.
175//!
176//! ## Codec Selection and Performance
177//!
178//! The choice of compression codec is critical for performance and space efficiency.
179//! [`VarVecBuilder`] offers automatic codec selection via
180//! [`Codec::Auto`]. When enabled, the builder analyzes the entire input
181//! dataset to find the codec that offers the best compression ratio.
182//!
183//! This analysis involves calculating the compressed size for the data with
184//! approximately 70 different codec configurations. This process introduces a
185//! significant, one-time **construction overhead**.
186//!
187//! Use [`Auto`](Codec::Auto) for read-heavy workloads where the [`VarVec`]
188//! is built once and then accessed many times. The initial cost is easily amortized by
189//! the long-term space savings.
190//!
191//! If your application creates many small [`VarVec`]s or accesses them frequently,
192//! the repeated cost of analysis can become a performance
193//! bottleneck. In such scenarios, it is better to explicitly specify a codec
194//! (e.g., [`Gamma`](Codec::Gamma) or [`Delta`](Codec::Delta)) that is known
195//! to be a good general-purpose choice for your data.
196//!
197//! ```
198//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
199//! use compressed_intvec::prelude::*;
200//!
201//! let data: Vec<u32> = (0..100).collect();
202//!
203//! // Create an VarVec with automatic codec selection
204//! let vec: UVarVec<u32> = VarVec::builder()
205//!     .build(&data)?;
206//! # Ok(())
207//! # }
208//! ```
209//!
210//! [`dsi-bitstream`]: https://docs.rs/dsi-bitstream/latest/dsi_bitstream/
211
212#[macro_use]
213mod macros;
214
215pub mod builder;
216pub mod codec;
217pub mod iter;
218#[cfg(feature = "parallel")]
219mod parallel;
220pub mod reader;
221pub mod seq_reader;
222#[cfg(feature = "serde")]
223pub mod serde;
224pub mod slice;
225pub mod traits;
226
227pub use self::{codec::Codec, traits::Storable};
228use crate::fixed::{Error as FixedVecError, FixedVec};
229use dsi_bitstream::{
230    codes::params::DefaultReadParams,
231    dispatch::StaticCodeRead,
232    prelude::{
233        BitRead, BitSeek, BufBitReader, BufBitWriter, Codes, CodesRead, CodesWrite, Endianness,
234        MemWordReader, MemWordWriterVec,
235    },
236    traits::{BE, BitWrite, LE},
237};
238use mem_dbg::{DbgFlags, FlatType, MemDbgImpl, MemSize, SizeFlags};
239use std::{
240    error::Error,
241    fmt::{self, Write},
242    marker::PhantomData,
243};
244
245pub use builder::{VarVecBuilder, VarVecFromIterBuilder};
246use iter::{VarVecIntoIter, VarVecIter};
247pub use reader::VarVecReader;
248pub use seq_reader::VarVecSeqReader;
249pub use slice::{VarVecSlice, VarVecSliceIter};
250
251/// Defines the set of errors that can occur in [`VarVec`] operations.
252#[derive(Debug)]
253pub enum VarVecError {
254    /// An error occurred during an I/O operation, typically from the underlying
255    /// bitstream reader or writer.
256    Io(std::io::Error),
257    /// A generic error from the [`dsi-bitstream`](https://crates.io/crates/dsi-bitstream) library, often related to decoding malformed data.
258    Bitstream(Box<dyn Error + Send + Sync>),
259    /// An error indicating that one or more parameters are invalid for the
260    /// requested operation.
261    InvalidParameters(String),
262    /// An error that occurs during the dynamic dispatch of codec functions.
263    CodecDispatch(String),
264    /// An error indicating that a provided index is outside the valid bounds
265    /// of the vector.
266    IndexOutOfBounds(usize),
267}
268
269impl fmt::Display for VarVecError {
270    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
271        match self {
272            VarVecError::Io(e) => write!(f, "I/O error: {}", e),
273            VarVecError::Bitstream(e) => write!(f, "Bitstream error: {}", e),
274            VarVecError::InvalidParameters(s) => write!(f, "Invalid parameters: {}", s),
275            VarVecError::CodecDispatch(s) => write!(f, "Codec dispatch error: {}", s),
276            VarVecError::IndexOutOfBounds(index) => write!(f, "Index out of bounds: {}", index),
277        }
278    }
279}
280
281impl Error for VarVecError {
282    fn source(&self) -> Option<&(dyn Error + 'static)> {
283        match self {
284            VarVecError::Io(e) => Some(e),
285            VarVecError::Bitstream(e) => Some(e.as_ref()),
286            _ => None,
287        }
288    }
289}
290
291impl From<std::io::Error> for VarVecError {
292    fn from(e: std::io::Error) -> Self {
293        VarVecError::Io(e)
294    }
295}
296
297impl From<core::convert::Infallible> for VarVecError {
298    fn from(_: core::convert::Infallible) -> Self {
299        unreachable!()
300    }
301}
302
303impl From<FixedVecError> for VarVecError {
304    fn from(e: FixedVecError) -> Self {
305        VarVecError::InvalidParameters(e.to_string())
306    }
307}
308
309/// A compressed, randomly accessible vector of integers using variable-length encoding.
310///
311/// [`VarVec`] achieves compression by using instantaneous codes and enables fast,
312/// amortized O(1) random access via a sampling mechanism. See the
313/// [module-level documentation](crate::variable) for a detailed explanation.
314///
315/// # Type Parameters
316///
317/// - `T`: The integer type for the elements (e.g., `u32`, `i16`). It must
318///   implement the [`Storable`] trait.
319/// - `E`: The [`Endianness`] of the underlying bitstream (e.g., [`LE`] or [`BE`]).
320/// - `B`: The backend storage buffer, such as `Vec<u64>` for an owned vector or
321///   `&[u64]` for a borrowed, zero-copy view.
322#[derive(Debug, Clone)]
323pub struct VarVec<T: Storable, E: Endianness, B: AsRef<[u64]> = Vec<u64>> {
324    /// The raw, bit-packed compressed data.
325    pub(super) data: B,
326    /// A `FixedVec` containing the bit offsets of sampled elements.
327    pub(super) samples: FixedVec<u64, u64, LE, B>,
328    /// The sampling rate `k`. Every `k`-th element's position is stored.
329    pub(super) k: usize,
330    /// The number of elements in the vector.
331    pub(super) len: usize,
332    /// The `dsi-bitstream` code used for compression.
333    pub(super) encoding: Codes,
334    /// Zero-sized markers for the generic type parameters.
335    pub(super) _markers: PhantomData<(T, E)>,
336}
337
338/// Type alias for the bit writer used internally by [`VarVec`] builders.
339pub(crate) type VarVecBitWriter<E> = BufBitWriter<E, MemWordWriterVec<u64, Vec<u64>>>;
340/// Type alias for the bit reader used internally by [`VarVec`] accessors.
341pub(crate) type VarVecBitReader<'a, E> =
342    BufBitReader<E, MemWordReader<u64, &'a [u64], true>, DefaultReadParams>;
343
344impl<T: Storable + 'static, E: Endianness> VarVec<T, E, Vec<u64>> {
345    /// Creates a builder for constructing an owned [`VarVec`] from a slice of data.
346    ///
347    /// This is the most flexible way to create an [`VarVec`], allowing customization
348    /// of the compression codec and sampling rate.
349    ///
350    /// # Examples
351    ///
352    /// ```
353    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
354    /// use compressed_intvec::variable::{VarVec, UVarVec, Codec};
355    ///
356    /// let data: &[u32] = &[5, 8, 13, 21, 34];
357    /// let vec: UVarVec<u32> = VarVec::builder()
358    ///     .k(2) // Sample every 2nd element
359    ///     .codec(Codec::Delta)
360    ///     .build(data)?;
361    ///
362    /// assert_eq!(vec.get(3), Some(21));
363    /// # Ok(())
364    /// # }
365    /// ```
366    pub fn builder() -> VarVecBuilder<T, E> {
367        VarVecBuilder::new()
368    }
369
370    /// Creates a builder for constructing an owned [`VarVec`] from an iterator.
371    ///
372    /// This is useful for large datasets that are generated on the fly.
373    pub fn from_iter_builder<I>(iter: I) -> VarVecFromIterBuilder<T, E, I>
374    where
375        I: IntoIterator<Item = T> + Clone,
376    {
377        VarVecFromIterBuilder::new(iter)
378    }
379
380    /// Consumes the [`VarVec`] and returns its decoded values as a standard `Vec<T>`.
381    ///
382    /// # Examples
383    ///
384    /// ```
385    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
386    /// use compressed_intvec::variable::{VarVec, SVarVec};
387    ///
388    /// let data: &[i32] = &[-10, 0, 10];
389    /// let vec: SVarVec<i32> = VarVec::from_slice(data)?;
390    /// let decoded_data = vec.into_vec();
391    ///
392    /// assert_eq!(decoded_data, &[-10, 0, 10]);
393    /// # Ok(())
394    /// # }
395    /// ```
396    pub fn into_vec(self) -> Vec<T>
397    where
398        for<'a> VarVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
399            + CodesRead<E>
400            + BitSeek<Error = core::convert::Infallible>,
401    {
402        self.into_iter().collect()
403    }
404
405    /// Creates an owned [`VarVec`] from a slice of data using default settings.
406    ///
407    /// This method uses [`Codec::Auto`] to select a codec and a
408    /// default sampling rate of `k=16`.
409    pub fn from_slice(slice: &[T]) -> Result<Self, VarVecError>
410    where
411        for<'a> crate::variable::VarVecBitWriter<E>:
412            BitWrite<E, Error = core::convert::Infallible> + CodesWrite<E>,
413    {
414        Self::builder().k(16).codec(Codec::Auto).build(slice)
415    }
416}
417
418impl<T: Storable, E: Endianness, B: AsRef<[u64]>> VarVec<T, E, B> {
419    /// Creates a new [`VarVec`] from its raw components, enabling zero-copy views.
420    ///
421    /// This constructor is intended for advanced use cases, such as memory-mapping
422    /// a pre-built [`VarVec`] from disk without copying the data.
423    ///
424    /// # Errors
425    ///
426    /// Returns an [`VarVecError::InvalidParameters`] if `k` is zero or if the
427    /// number of samples is inconsistent with `len` and `k`.
428    pub fn from_parts(
429        data: B,
430        samples_data: B,
431        samples_len: usize,
432        samples_num_bits: usize,
433        k: usize,
434        len: usize,
435        encoding: Codes,
436    ) -> Result<Self, VarVecError> {
437        let samples =
438            FixedVec::<u64, u64, LE, B>::from_parts(samples_data, samples_len, samples_num_bits)?;
439
440        if k == 0 {
441            return Err(VarVecError::InvalidParameters(
442                "Sampling rate k cannot be zero".to_string(),
443            ));
444        }
445        let expected_samples = if len == 0 { 0 } else { len.div_ceil(k) };
446        if samples.len() != expected_samples {
447            return Err(VarVecError::InvalidParameters(format!(
448                "Inconsistent number of samples. Expected {}, found {}",
449                expected_samples,
450                samples.len()
451            )));
452        }
453
454        Ok(unsafe { Self::new_unchecked(data, samples, k, len, encoding) })
455    }
456
457    /// Creates a new [`VarVec`] from its raw parts without performing safety checks.
458    ///
459    /// # Safety
460    ///
461    /// The caller must ensure that all parameters are consistent and valid. The
462    /// `samples` must contain the correct bit offsets for the `data` stream,
463    /// and `len`, `k`, and `encoding` must accurately describe the layout.
464    /// Mismatched parameters will lead to panics or incorrect data retrieval.
465    pub(crate) unsafe fn new_unchecked(
466        data: B,
467        samples: FixedVec<u64, u64, LE, B>,
468        k: usize,
469        len: usize,
470        encoding: Codes,
471    ) -> Self {
472        Self {
473            data,
474            samples,
475            k,
476            len,
477            encoding,
478            _markers: PhantomData,
479        }
480    }
481
482    /// Creates a zero-copy, immutable view (a _slice_) of this vector.
483    ///
484    /// Returns `None` if the specified range is out of bounds.
485    ///
486    /// # Examples
487    ///
488    /// ```
489    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
490    /// use compressed_intvec::variable::{VarVec, UVarVec};
491    ///
492    /// let data: Vec<u32> = (0..20).collect();
493    /// let vec: UVarVec<u32> = VarVec::from_slice(&data)?;
494    /// let slice = vec.slice(5, 10).expect("valid slice range");
495    ///
496    /// assert_eq!(slice.len(), 10);
497    /// assert_eq!(slice.get(0), Some(5)); // Corresponds to index 5 of the original vec
498    /// # Ok(())
499    /// # }
500    /// ```
501    pub fn slice(&'_ self, start: usize, len: usize) -> Option<VarVecSlice<'_, T, E, B>> {
502        if start.saturating_add(len) > self.len {
503            return None;
504        }
505        Some(VarVecSlice::new(self, start..start + len))
506    }
507
508    /// Splits the vector into two immutable slices at a given index.
509    ///
510    /// Returns `None` if `mid` is out of bounds.
511    #[allow(clippy::type_complexity)]
512    pub fn split_at(
513        &'_ self,
514        mid: usize,
515    ) -> Option<(VarVecSlice<'_, T, E, B>, VarVecSlice<'_, T, E, B>)> {
516        if mid > self.len {
517            return None;
518        }
519        let left = VarVecSlice::new(self, 0..mid);
520        let right = VarVecSlice::new(self, mid..self.len);
521        Some((left, right))
522    }
523
524    /// Returns the number of integers in the vector.
525    #[inline]
526    pub fn len(&self) -> usize {
527        self.len
528    }
529
530    /// Returns `true` if the vector contains no elements.
531    #[inline]
532    pub fn is_empty(&self) -> bool {
533        self.len == 0
534    }
535
536    /// Returns the sampling rate `k` used during encoding.
537    #[inline]
538    pub fn sampling_rate(&self) -> usize {
539        self.k
540    }
541
542    /// Returns the number of sample points stored in the vector.
543    #[inline]
544    pub fn num_samples(&self) -> usize {
545        self.samples.len()
546    }
547
548    /// Returns the sampling rate `k` used during encoding.
549    #[deprecated(since = "0.6.0", note = "renamed to `sampling_rate`; use `sampling_rate` instead")]
550    #[inline]
551    pub fn get_sampling_rate(&self) -> usize {
552        self.sampling_rate()
553    }
554
555    /// Returns the number of sample points stored in the vector.
556    #[deprecated(
557        since = "0.6.0",
558        note = "renamed to `num_samples`; use `num_samples` instead"
559    )]
560    #[inline]
561    pub fn get_num_samples(&self) -> usize {
562        self.num_samples()
563    }
564
565    /// Returns a reference to the inner `FixedVec` of samples.
566    #[inline]
567    pub fn samples_ref(&self) -> &FixedVec<u64, u64, LE, B> {
568        &self.samples
569    }
570
571    /// Returns a read-only slice of the underlying compressed data words (`&[u64]`).
572    #[inline]
573    pub fn as_limbs(&self) -> &[u64] {
574        self.data.as_ref()
575    }
576
577    /// Returns the concrete [`Codes`] variant that was used for compression.
578    #[inline]
579    pub fn encoding(&self) -> Codes {
580        self.encoding
581    }
582
583    /// Returns a clone of the underlying storage as a `Vec<u64>`.
584    pub fn limbs(&self) -> Vec<u64> {
585        self.data.as_ref().to_vec()
586    }
587
588    /// Returns an iterator over the decompressed values.
589    pub fn iter(&'_ self) -> impl Iterator<Item = T> + '_
590    where
591        for<'a> VarVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
592            + CodesRead<E>
593            + BitSeek<Error = core::convert::Infallible>,
594    {
595        VarVecIter::new(self)
596    }
597}
598
599impl<T: Storable, E: Endianness, B: AsRef<[u64]>> VarVec<T, E, B>
600where
601    for<'a> VarVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
602        + CodesRead<E>
603        + BitSeek<Error = core::convert::Infallible>,
604{
605    /// Creates a reusable, stateless reader for efficient random access.
606    ///
607    /// This method returns an [`VarVecReader`], a struct that maintains a persistent,
608    /// reusable bitstream reader. This amortizes the setup cost across multiple `get`
609    /// operations, making it more efficient than calling [`get`](VarVec::get) repeatedly in a loop.
610    ///
611    /// This reader is **stateless**: it performs a full seek from the nearest sample point for each call,
612    /// independently of any previous access.
613    ///
614    /// # When to use it
615    /// Use [`VarVecReader`] for true random access patterns where lookup indices are sparse,
616    /// unordered, or not known in advance (e.g., graph traversals, pointer chasing).
617    /// For accessing a known set of indices, [`get_many`](VarVec::get_many) is generally superior.
618    ///
619    /// # Examples
620    ///
621    /// ```
622    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
623    /// use compressed_intvec::prelude::*;
624    ///
625    /// let data: Vec<u32> = (0..100).rev().collect(); // Data is not sequential
626    /// let vec: UVarVec<u32> = VarVec::from_slice(&data)?;
627    ///
628    /// // Create a reusable reader for multiple random lookups
629    /// let mut reader = vec.reader();
630    ///
631    /// assert_eq!(reader.get(99)?, Some(0));
632    /// assert_eq!(reader.get(0)?, Some(99));
633    /// assert_eq!(reader.get(50)?, Some(49));
634    /// # Ok(())
635    /// # }
636    /// ```
637    pub fn reader(&'_ self) -> VarVecReader<'_, T, E, B> {
638        VarVecReader::new(self)
639    }
640
641    /// Creates a stateful, reusable reader optimized for sequential access.
642    ///
643    /// This method returns an [`VarVecSeqReader`], which is specifically designed
644    /// to take advantage of the vector's internal state, tracking the current decoding position (cursor).
645    ///
646    /// This statefulness enables a key optimization:
647    /// - **Fast Path**: If a requested index is at or after the cursor and within
648    ///   the same sample block, the reader decodes forward from its last known
649    ///   position. This avoids a costly seek operation.
650    /// - **Fallback Path**: If the requested index is before the cursor (requiring a
651    ///   backward move) or in a different sample block, the reader falls back to
652    ///   the standard behavior of seeking to the nearest sample point.
653    ///
654    /// # When to use it
655    /// Use [`VarVecSeqReader`] when your access pattern has high locality, meaning
656    /// indices are primarily increasing and often clustered together. It is ideal
657    /// for iterating through a sorted list of indices or for stream-like processing.
658    ///
659    /// # Examples
660    ///
661    /// ```
662    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
663    /// use compressed_intvec::prelude::*;
664    ///
665    /// let data: Vec<u32> = (0..100).collect();
666    /// let vec: UVarVec<u32> = VarVec::from_slice(&data)?;
667    ///
668    /// // Create a reader optimized for sequential access
669    /// let mut seq_reader = vec.seq_reader();
670    ///
671    /// // Accessing indices in increasing order is efficient
672    /// assert_eq!(seq_reader.get(10)?, Some(10));
673    /// // This next call is fast, as it decodes forward from index 10
674    /// assert_eq!(seq_reader.get(15)?, Some(15));
675    ///
676    /// // A large jump will trigger a seek to a new sample block
677    /// assert_eq!(seq_reader.get(90)?, Some(90));
678    ///
679    /// // A backward jump will also trigger a seek
680    /// assert_eq!(seq_reader.get(5)?, Some(5));
681    /// # Ok(())
682    /// # }
683    /// ```
684    pub fn seq_reader(&'_ self) -> VarVecSeqReader<'_, T, E, B> {
685        VarVecSeqReader::new(self)
686    }
687
688    /// Returns the element at the specified index, or `None` if the index is
689    /// out of bounds.
690    ///
691    /// This operation is amortized O(1).
692    ///
693    /// # Examples
694    ///
695    /// ```
696    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
697    /// use compressed_intvec::variable::{VarVec, UVarVec};
698    ///
699    /// let data: Vec<u32> = (0..100).collect();
700    /// let vec: UVarVec<u32> = VarVec::from_slice(&data)?;
701    ///
702    /// assert_eq!(vec.get(50), Some(50));
703    /// assert_eq!(vec.get(100), None);
704    /// # Ok(())
705    /// # }
706    /// ```
707    #[inline]
708    pub fn get(&self, index: usize) -> Option<T> {
709        if index >= self.len {
710            return None;
711        }
712        Some(unsafe { self.get_unchecked(index) })
713    }
714
715    /// Returns the element at the specified index without bounds checking.
716    ///
717    /// # Safety
718    ///
719    /// Calling this method with an out-of-bounds `index` is undefined behavior.
720    /// The `index` must be less than the vector's `len`.
721    #[inline]
722    pub unsafe fn get_unchecked(&self, index: usize) -> T {
723        let mut reader = self.reader();
724        unsafe { reader.get_unchecked(index) }
725    }
726
727    /// Retrieves multiple elements from the vector at the specified indices.
728    ///
729    /// This method is generally more efficient than calling [`get`](Self::get) in a loop, as
730    /// it sorts the indices and scans through the compressed data stream once.
731    ///
732    /// # Errors
733    ///
734    /// Returns [`VarVecError::IndexOutOfBounds`] if any index is out of bounds.
735    ///
736    /// # Examples
737    ///
738    /// ```
739    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
740    /// use compressed_intvec::variable::{VarVec, UVarVec};
741    ///
742    /// let data: Vec<u32> = (0..100).collect();
743    /// let vec: UVarVec<u32> = VarVec::from_slice(&data)?;
744    ///
745    /// let indices = [99, 0, 50];
746    /// let values = vec.get_many(&indices)?;
747    /// assert_eq!(values, vec![99, 0, 50]);
748    /// # Ok(())
749    /// # }
750    /// ```
751    pub fn get_many(&self, indices: &[usize]) -> Result<Vec<T>, VarVecError> {
752        if indices.is_empty() {
753            return Ok(Vec::new());
754        }
755
756        for &index in indices {
757            if index >= self.len {
758                return Err(VarVecError::IndexOutOfBounds(index));
759            }
760        }
761        // SAFETY: We have just performed the bounds checks.
762        Ok(unsafe { self.get_many_unchecked(indices) })
763    }
764
765    /// Retrieves multiple elements without bounds checking.
766    ///
767    /// # Safety
768    ///
769    /// Calling this method with any out-of-bounds index is undefined behavior.
770    #[allow(clippy::uninit_vec)]
771    pub unsafe fn get_many_unchecked(&self, indices: &[usize]) -> Vec<T> {
772        if indices.is_empty() {
773            return Vec::new();
774        }
775        let mut results = Vec::with_capacity(indices.len());
776        // SAFETY: The vector is immediately populated by the sorted access logic below.
777        unsafe { results.set_len(indices.len()) };
778
779        let mut indexed_indices: Vec<(usize, usize)> = indices
780            .iter()
781            .enumerate()
782            .map(|(i, &idx)| (idx, i))
783            .collect();
784        // Sort by the target index to enable efficient sequential scanning.
785        indexed_indices.sort_unstable_by_key(|&(idx, _)| idx);
786
787        if self.k.is_power_of_two() {
788            // Optimization: use bit-shift for division if k is a power of two.
789            let k_exp = self.k.trailing_zeros();
790            self.get_many_dsi_inner(
791                &indexed_indices,
792                &mut results,
793                |idx| idx >> k_exp,
794                |block| block << k_exp,
795            )
796            .unwrap();
797        } else {
798            self.get_many_dsi_inner(
799                &indexed_indices,
800                &mut results,
801                |idx| idx / self.k,
802                |block| block * self.k,
803            )
804            .unwrap();
805        }
806
807        results
808    }
809
810    /// Internal implementation for `get_many_unchecked`.
811    ///
812    /// This function takes closures to abstract away the division/multiplication
813    /// by `k`, allowing for a bit-shift optimization when `k` is a power of two.
814    fn get_many_dsi_inner<F1, F2>(
815        &self,
816        indexed_indices: &[(usize, usize)],
817        results: &mut [T],
818        block_of: F1,
819        start_of_block: F2,
820    ) -> Result<(), VarVecError>
821    where
822        F1: Fn(usize) -> usize,
823        F2: Fn(usize) -> usize,
824    {
825        let mut reader = self.reader();
826        let mut current_decoded_index: usize = 0;
827
828        for &(target_index, original_position) in indexed_indices {
829            // Check if we need to jump to a new sample block. This is true if the
830            // target index is before our current position, or if it's in a different
831            // sample block than the one we're currently in.
832            if target_index < current_decoded_index
833                || block_of(target_index) != block_of(current_decoded_index.saturating_sub(1))
834            {
835                let target_sample_block = block_of(target_index);
836                // SAFETY: The public-facing `get_many` performs bounds checks.
837                let start_bit = unsafe { self.samples.get_unchecked(target_sample_block) };
838                reader.reader.set_bit_pos(start_bit)?;
839                current_decoded_index = start_of_block(target_sample_block);
840            }
841
842            // Sequentially decode elements until we reach our target.
843            for _ in current_decoded_index..target_index {
844                reader.code_reader.read(&mut reader.reader)?;
845            }
846            let value = reader.code_reader.read(&mut reader.reader)?;
847            // Place the decoded value in its original requested position.
848            results[original_position] = Storable::from_word(value);
849            current_decoded_index = target_index + 1;
850        }
851        Ok(())
852    }
853
854    /// Retrieves multiple elements from an iterator of indices.
855    ///
856    /// This is a convenient alternative to [`get_many`](Self::get_many) when the indices are not
857    /// already in a slice. It may be less performant as it cannot pre-sort the
858    /// indices for optimal access.
859    pub fn get_many_from_iter<I>(&self, indices: I) -> Result<Vec<T>, VarVecError>
860    where
861        I: IntoIterator<Item = usize>,
862    {
863        let indices_iter = indices.into_iter();
864        let (lower_bound, _) = indices_iter.size_hint();
865        let mut results = Vec::with_capacity(lower_bound);
866        let mut seq_reader = self.seq_reader();
867
868        for index in indices_iter {
869            let value = seq_reader
870                .get(index)?
871                .ok_or(VarVecError::IndexOutOfBounds(index))?;
872            results.push(value);
873        }
874
875        Ok(results)
876    }
877}
878
879impl<T: Storable + Ord, E: Endianness, B: AsRef<[u64]>> VarVec<T, E, B>
880where
881    for<'a> VarVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
882        + CodesRead<E>
883        + BitSeek<Error = core::convert::Infallible>,
884{
885    /// Binary searches this vector for a given element.
886    ///
887    /// If the value is found, returns `Ok(usize)` with the index of the
888    /// matching element. If the value is not found, returns `Err(usize)` with
889    /// the index where the value could be inserted to maintain order.
890    ///
891    /// # Complexity
892    ///
893    /// The time complexity of this operation is O(k * log n), where `n` is the
894    /// number of elements in the vector and `k` is the sampling rate. This is
895    /// because each of the O(log n) probes during the search requires an
896    /// element access, which has a cost proportional to `k` in the worst case.
897    ///
898    /// # Examples
899    ///
900    /// ```
901    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
902    /// use compressed_intvec::variable::{VarVec, SVarVec};
903    ///
904    /// let data: &[i32] = &[-10, 0, 10, 20, 30];
905    /// let vec: SVarVec<i32> = VarVec::from_slice(data)?;
906    ///
907    /// assert_eq!(vec.binary_search(&10), Ok(2));
908    /// assert_eq!(vec.binary_search(&15), Err(3));
909    /// # Ok(())
910    /// # }
911    /// ```
912    pub fn binary_search(&self, value: &T) -> Result<usize, usize> {
913        self.binary_search_by(|probe| probe.cmp(value))
914    }
915
916    /// Binary searches this vector with a custom comparison function.
917    ///
918    /// # Complexity
919    ///
920    /// The time complexity of this operation is O(k * log n), where `n` is the
921    /// number of elements in the vector and `k` is the sampling rate.
922    #[inline]
923    pub fn binary_search_by<F>(&self, mut f: F) -> Result<usize, usize>
924    where
925        F: FnMut(T) -> std::cmp::Ordering,
926    {
927        let mut low = 0;
928        let mut high = self.len();
929        let mut reader = self.reader();
930
931        while low < high {
932            let mid = low + (high - low) / 2;
933            // SAFETY: The loop invariants ensure `mid` is always in bounds.
934            let cmp = f(unsafe { reader.get_unchecked(mid) });
935
936            match cmp {
937                std::cmp::Ordering::Less => low = mid + 1,
938                std::cmp::Ordering::Equal => return Ok(mid),
939                std::cmp::Ordering::Greater => high = mid,
940            }
941        }
942        Err(low)
943    }
944
945    /// Binary searches this vector with a key extraction function.
946    ///
947    /// # Complexity
948    ///
949    /// The time complexity of this operation is O(k * log n), where `n` is the
950    /// number of elements in the vector and `k` is the sampling rate.
951    #[inline]
952    pub fn binary_search_by_key<K: Ord, F>(&self, b: &K, mut f: F) -> Result<usize, usize>
953    where
954        F: FnMut(T) -> K,
955    {
956        self.binary_search_by(|k| f(k).cmp(b))
957    }
958}
959
960impl<T: Storable, E: Endianness, B: AsRef<[u64]> + MemSize + FlatType> MemSize for VarVec<T, E, B> {
961    fn mem_size_rec(&self, flags: SizeFlags, _refs: &mut mem_dbg::HashMap<usize, usize>) -> usize {
962        // Start with the stack size of the struct itself.
963        let mut total_size = core::mem::size_of::<Self>();
964        // Add the heap-allocated memory for the `data` field.
965        total_size += self.data.mem_size(flags) - core::mem::size_of::<B>();
966        // Add the heap-allocated memory for the `samples` field's internal buffer.
967        total_size +=
968            self.samples.mem_size(flags) - core::mem::size_of::<FixedVec<u64, u64, LE, B>>();
969        total_size
970    }
971}
972
973// A local wrapper for `dsi_bitstream::codes::Codes` to override its `MemDbgImpl`.
974// This is necessary because the derived implementation for `Codes` is incorrect
975// and cannot be fixed due to the orphan rule.
976struct CodeWrapper<'a>(&'a Codes);
977
978impl mem_dbg::MemSize for CodeWrapper<'_> {
979    fn mem_size_rec(&self, _flags: mem_dbg::SizeFlags, _refs: &mut mem_dbg::HashMap<usize, usize>) -> usize {
980        core::mem::size_of_val(self.0)
981    }
982}
983
984impl mem_dbg::MemDbgImpl for CodeWrapper<'_> {
985    // Override the top-level display function for this type.
986    fn _mem_dbg_depth_on(
987        &self,
988        writer: &mut impl core::fmt::Write,
989        total_size: usize,
990        max_depth: usize,
991        prefix: &mut String,
992        field_name: Option<&str>,
993        is_last: bool,
994        padded_size: usize,
995        flags: DbgFlags,
996        _dbg_refs: &mut mem_dbg::HashSet<usize>,
997    ) -> core::fmt::Result {
998        if prefix.len() > max_depth {
999            return Ok(());
1000        }
1001
1002        let real_size = self.mem_size(flags.to_size_flags());
1003        let mut buffer = String::new(); // Use a temp buffer to format the size part.
1004
1005        // Replicate the size and percentage formatting from the default `MemDbgImpl`.
1006        if flags.contains(DbgFlags::HUMANIZE) {
1007            let (value, uom) = mem_dbg::humanize_float(real_size);
1008            if uom == " B" {
1009                let _ = write!(&mut buffer, "{:>5}  B ", real_size);
1010            } else {
1011                let precision = if value.abs() >= 100.0 {
1012                    1
1013                } else if value.abs() >= 10.0 {
1014                    2
1015                } else {
1016                    3
1017                };
1018                let _ = write!(&mut buffer, "{0:>4.1$} {2} ", value, precision, uom);
1019            }
1020        } else {
1021            let align = mem_dbg::n_of_digits(total_size);
1022            let _ = write!(&mut buffer, "{:>align$} B ", real_size, align = align);
1023        }
1024
1025        if flags.contains(DbgFlags::PERCENTAGE) {
1026            let percentage = if total_size == 0 {
1027                100.0
1028            } else {
1029                100.0 * real_size as f64 / total_size as f64
1030            };
1031            let _ = write!(&mut buffer, "{:>6.2}% ", percentage);
1032        }
1033
1034        // Write the formatted size string with colors if enabled.
1035        if flags.contains(DbgFlags::COLOR) {
1036            writer.write_fmt(format_args!("{}", mem_dbg::color(real_size)))?;
1037        }
1038        writer.write_str(&buffer)?;
1039        if flags.contains(DbgFlags::COLOR) {
1040            writer.write_fmt(format_args!("{}", mem_dbg::reset_color()))?;
1041        }
1042
1043        // Write the tree structure part.
1044        if !prefix.is_empty() {
1045            writer.write_str(&prefix[2..])?;
1046            writer.write_char(if is_last { '╰' } else { '├' })?;
1047            writer.write_char('╴')?;
1048        }
1049
1050        if let Some(field_name) = field_name {
1051            writer.write_fmt(format_args!("{}", field_name))?;
1052        }
1053
1054        // This is the custom part: print the `Debug` format of the enum.
1055        if flags.contains(DbgFlags::TYPE_NAME) {
1056            if flags.contains(DbgFlags::COLOR) {
1057                writer.write_fmt(format_args!("{}", mem_dbg::type_color()))?;
1058            }
1059            writer.write_fmt(format_args!(": {:?}", self.0))?;
1060            if flags.contains(DbgFlags::COLOR) {
1061                writer.write_fmt(format_args!("{}", mem_dbg::reset_color()))?;
1062            }
1063        }
1064
1065        // Correctly calculate and print padding.
1066        let padding = padded_size - core::mem::size_of_val(self.0);
1067        if padding != 0 {
1068            writer.write_fmt(format_args!(" [{}B]", padding))?;
1069        }
1070
1071        writer.write_char('\n')?;
1072        Ok(())
1073    }
1074
1075    // It's a leaf node in the display tree, so no recursion is needed.
1076    fn _mem_dbg_rec_on(
1077        &self,
1078        _writer: &mut impl core::fmt::Write,
1079        _total_size: usize,
1080        _max_depth: usize,
1081        _prefix: &mut String,
1082        _is_last: bool,
1083        _flags: DbgFlags,
1084        _dbg_refs: &mut mem_dbg::HashSet<usize>,
1085    ) -> core::fmt::Result {
1086        Ok(())
1087    }
1088}
1089
1090impl<T: Storable, E: Endianness, B: AsRef<[u64]> + MemDbgImpl + FlatType> MemDbgImpl for VarVec<T, E, B> {
1091    fn _mem_dbg_rec_on(
1092        &self,
1093        writer: &mut impl core::fmt::Write,
1094        total_size: usize,
1095        max_depth: usize,
1096        prefix: &mut String,
1097        _is_last: bool,
1098        flags: DbgFlags,
1099        _dbg_refs: &mut mem_dbg::HashSet<usize>,
1100    ) -> core::fmt::Result {
1101        // Manually display each field, ensuring correct tree structure.
1102        self.data._mem_dbg_depth_on(
1103            writer,
1104            total_size,
1105            max_depth,
1106            prefix,
1107            Some("data"),
1108            false,
1109            core::mem::size_of_val(&self.data),
1110            flags,
1111            _dbg_refs,
1112        )?;
1113        self.samples._mem_dbg_depth_on(
1114            writer,
1115            total_size,
1116            max_depth,
1117            prefix,
1118            Some("samples"),
1119            false,
1120            core::mem::size_of_val(&self.samples),
1121            flags,
1122            _dbg_refs,
1123        )?;
1124        self.k._mem_dbg_depth_on(
1125            writer,
1126            total_size,
1127            max_depth,
1128            prefix,
1129            Some("k"),
1130            false,
1131            core::mem::size_of_val(&self.k),
1132            flags,
1133            _dbg_refs,
1134        )?;
1135        self.len._mem_dbg_depth_on(
1136            writer,
1137            total_size,
1138            max_depth,
1139            prefix,
1140            Some("len"),
1141            false,
1142            core::mem::size_of_val(&self.len),
1143            flags,
1144            _dbg_refs,
1145        )?;
1146
1147        // Use the custom wrapper to correctly display the `encoding` field.
1148        let code_wrapper = CodeWrapper(&self.encoding);
1149        code_wrapper._mem_dbg_depth_on(
1150            writer,
1151            total_size,
1152            max_depth,
1153            prefix,
1154            Some("encoding"),
1155            false, // Not the last field.
1156            core::mem::size_of_val(&self.encoding),
1157            flags,
1158            _dbg_refs,
1159        )?;
1160
1161        self._markers._mem_dbg_depth_on(
1162            writer,
1163            total_size,
1164            max_depth,
1165            prefix,
1166            Some("_markers"),
1167            true, // This is the last field.
1168            core::mem::size_of_val(&self._markers),
1169            flags,
1170            _dbg_refs,
1171        )?;
1172        Ok(())
1173    }
1174}
1175
1176impl<T: Storable + 'static, E: Endianness + 'static> IntoIterator for VarVec<T, E, Vec<u64>>
1177where
1178    for<'a> VarVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
1179        + CodesRead<E>
1180        + BitSeek<Error = core::convert::Infallible>,
1181{
1182    type Item = T;
1183    type IntoIter = VarVecIntoIter<T, E>;
1184
1185    fn into_iter(self) -> Self::IntoIter {
1186        VarVecIntoIter::new(self)
1187    }
1188}
1189
1190/// An [`VarVec`] for unsigned integers with Little-Endian bit layout.
1191pub type UVarVec<T> = VarVec<T, LE>;
1192/// An [`VarVec`] for signed integers with Little-Endian bit layout.
1193pub type SVarVec<T> = VarVec<T, LE>;
1194/// An [`VarVec`] for [`u64`] elements with Big-Endian bit layout.
1195pub type BEVarVec = VarVec<u64, BE>;
1196/// An [`VarVec`] for [`u64`] elements with Little-Endian bit layout.
1197pub type LEVarVec = VarVec<u64, LE>;
1198/// An [`VarVec`] for [`i64`] elements with Big-Endian bit layout.
1199pub type BESVarVec = VarVec<i64, BE>;
1200/// An [`VarVec`] for [`i64`] elements with Little-Endian bit layout.
1201pub type LESVarVec = VarVec<i64, LE>;
1202
1203// ============================================================================
1204// Deprecated Type Aliases for Backward Compatibility
1205// ============================================================================
1206// As of version 0.3.0, all `IntVec*` types have been renamed to `VarVec*`
1207// for consistency with the module naming convention. These deprecated aliases
1208// maintain backward compatibility and will be removed in a future major version.
1209
1210/// Deprecated alias for [`VarVec`]. Use [`VarVec`] instead.
1211///
1212/// # Deprecation Notice
1213///
1214/// This type has been renamed to [`VarVec`] for consistency with the module
1215/// naming convention (`variable` → `VarVec`). This alias will be removed in
1216/// a future major release.
1217#[deprecated(since = "0.6.0", note = "renamed to `VarVec`; use `VarVec` instead")]
1218pub type IntVec<T, E, B = Vec<u64>> = VarVec<T, E, B>;
1219
1220/// Deprecated alias for [`VarVecBuilder`]. Use [`VarVecBuilder`] instead.
1221#[deprecated(
1222    since = "0.6.0",
1223    note = "renamed to `VarVecBuilder`; use `VarVecBuilder` instead"
1224)]
1225pub type IntVecBuilder<T, E> = VarVecBuilder<T, E>;
1226
1227/// Deprecated alias for [`VarVecFromIterBuilder`]. Use [`VarVecFromIterBuilder`] instead.
1228#[deprecated(
1229    since = "0.6.0",
1230    note = "renamed to `VarVecFromIterBuilder`; use `VarVecFromIterBuilder` instead"
1231)]
1232pub type IntVecFromIterBuilder<T, E, I> = VarVecFromIterBuilder<T, E, I>;
1233
1234/// Deprecated alias for [`VarVecReader`]. Use [`VarVecReader`] instead.
1235#[deprecated(
1236    since = "0.6.0",
1237    note = "renamed to `VarVecReader`; use `VarVecReader` instead"
1238)]
1239pub type IntVecReader<'a, T, E, B> = VarVecReader<'a, T, E, B>;
1240
1241/// Deprecated alias for [`VarVecSeqReader`]. Use [`VarVecSeqReader`] instead.
1242#[deprecated(
1243    since = "0.6.0",
1244    note = "renamed to `VarVecSeqReader`; use `VarVecSeqReader` instead"
1245)]
1246pub type IntVecSeqReader<'a, T, E, B> = VarVecSeqReader<'a, T, E, B>;
1247
1248/// Deprecated alias for [`VarVecSlice`]. Use [`VarVecSlice`] instead.
1249#[deprecated(
1250    since = "0.6.0",
1251    note = "renamed to `VarVecSlice`; use `VarVecSlice` instead"
1252)]
1253pub type IntVecSlice<'a, T, E, B> = VarVecSlice<'a, T, E, B>;
1254
1255/// Deprecated alias for [`VarVecIter`]. Use [`VarVecIter`] instead.
1256#[deprecated(
1257    since = "0.6.0",
1258    note = "renamed to `VarVecIter`; use `VarVecIter` instead"
1259)]
1260pub type IntVecIter<'a, T, E, B> = VarVecIter<'a, T, E, B>;
1261
1262/// Deprecated alias for [`VarVecIntoIter`]. Use [`VarVecIntoIter`] instead.
1263#[deprecated(
1264    since = "0.6.0",
1265    note = "renamed to `VarVecIntoIter`; use `VarVecIntoIter` instead"
1266)]
1267pub type IntVecIntoIter<T, E> = VarVecIntoIter<T, E>;
1268
1269/// Deprecated alias for [`VarVecError`]. Use [`VarVecError`] instead.
1270#[deprecated(
1271    since = "0.6.0",
1272    note = "renamed to `VarVecError`; use `VarVecError` instead"
1273)]
1274pub type IntVecError = VarVecError;
1275
1276/// Deprecated alias for [`VarVecSliceIter`]. Use [`VarVecSliceIter`] instead.
1277#[deprecated(
1278    since = "0.6.0",
1279    note = "renamed to `VarVecSliceIter`; use `VarVecSliceIter` instead"
1280)]
1281pub type IntVecSliceIter<'a, T, E, B> = VarVecSliceIter<'a, T, E, B>;
1282
1283// Deprecated convenience aliases
1284/// Deprecated alias for [`UVarVec`]. Use [`UVarVec`] instead.
1285#[deprecated(since = "0.6.0", note = "renamed to `UVarVec`; use `UVarVec` instead")]
1286pub type UIntVec<T> = UVarVec<T>;
1287
1288/// Deprecated alias for [`SVarVec`]. Use [`SVarVec`] instead.
1289#[deprecated(since = "0.6.0", note = "renamed to `SVarVec`; use `SVarVec` instead")]
1290pub type SIntVec<T> = SVarVec<T>;
1291
1292/// Deprecated alias for [`BEVarVec`]. Use [`BEVarVec`] instead.
1293#[deprecated(
1294    since = "0.6.0",
1295    note = "renamed to `BEVarVec`; use `BEVarVec` instead"
1296)]
1297pub type BEIntVec = BEVarVec;
1298
1299/// Deprecated alias for [`LEVarVec`]. Use [`LEVarVec`] instead.
1300#[deprecated(
1301    since = "0.6.0",
1302    note = "renamed to `LEVarVec`; use `LEVarVec` instead"
1303)]
1304pub type LEIntVec = LEVarVec;
1305
1306/// Deprecated alias for [`BESVarVec`]. Use [`BESVarVec`] instead.
1307#[deprecated(
1308    since = "0.6.0",
1309    note = "renamed to `BESVarVec`; use `BESVarVec` instead"
1310)]
1311pub type BESIntVec = BESVarVec;
1312
1313/// Deprecated alias for [`LESVarVec`]. Use [`LESVarVec`] instead.
1314#[deprecated(
1315    since = "0.6.0",
1316    note = "renamed to `LESVarVec`; use `LESVarVec` instead"
1317)]
1318pub type LESIntVec = LESVarVec;
1319
1320/// Deprecated alias for [`Codec`]. Use [`Codec`] instead.
1321#[deprecated(since = "0.6.0", note = "renamed to `Codec`; use `Codec` instead")]
1322#[allow(deprecated)]
1323pub use self::codec::VariableCodecSpec;
1324
1325// Deprecated internal type aliases
1326/// Deprecated alias for [`VarVecBitReader`]. Use [`VarVecBitReader`] instead.
1327#[deprecated(
1328    since = "0.6.0",
1329    note = "renamed to `VarVecBitReader`; use `VarVecBitReader` instead"
1330)]
1331#[allow(dead_code)]
1332pub(crate) type IntVecBitReader<'a, E> = VarVecBitReader<'a, E>;
1333
1334/// Deprecated alias for [`VarVecBitWriter`]. Use [`VarVecBitWriter`] instead.
1335#[deprecated(
1336    since = "0.6.0",
1337    note = "renamed to `VarVecBitWriter`; use `VarVecBitWriter` instead"
1338)]
1339#[allow(dead_code)]
1340pub(crate) type IntVecBitWriter<E> = VarVecBitWriter<E>;
1341
1342impl<T, E, B, O> PartialEq<O> for VarVec<T, E, B>
1343where
1344    T: Storable + PartialEq,
1345    E: Endianness,
1346    B: AsRef<[u64]>,
1347    O: AsRef<[T]>,
1348    for<'a> VarVecBitReader<'a, E>: BitRead<E, Error = core::convert::Infallible>
1349        + CodesRead<E>
1350        + BitSeek<Error = core::convert::Infallible>,
1351{
1352    /// Checks for equality between an [`VarVec`] and a standard slice.
1353    ///
1354    /// The comparison is done by iterating over both and comparing elements
1355    /// one by one. The overall comparison is not a single atomic operation.
1356    fn eq(&self, other: &O) -> bool {
1357        let other_slice = other.as_ref();
1358        if self.len() != other_slice.len() {
1359            return false;
1360        }
1361        self.iter().zip(other_slice.iter()).all(|(a, b)| a == *b)
1362    }
1363}