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}