compressed_intvec/fixed/
slice.rs

1//! # Zero-Copy Slices
2//!
3//! This module provides [`FixedVecSlice`], a zero-copy view into a portion of a
4//! [`FixedVec`]. Slices can be created from both immutable and mutable vectors
5//! and provide a way to operate on a sub-region of the data without copying.
6//!
7//! # Examples
8//!
9//! ## Creating and using an immutable slice
10//!
11//! ```rust
12//! use compressed_intvec::fixed::{FixedVec, UFixedVec};
13//!
14//! let data: Vec<u32> = (0..10).collect();
15//! let vec: UFixedVec<u32> = FixedVec::builder().build(&data).unwrap();
16//!
17//! // Create a slice of the elements from index 2 to 6.
18//! let slice = vec.slice(2, 5).unwrap();
19//!
20//! assert_eq!(slice.len(), 5);
21//! assert_eq!(slice.get(0), Some(2));
22//! assert_eq!(slice.get(4), Some(6));
23//!
24//! // The slice can be iterated over.
25//! let sum: u32 = slice.iter().sum();
26//! assert_eq!(sum, 2 + 3 + 4 + 5 + 6);
27//! ```
28//!
29//! ## Creating and using a mutable slice
30//!
31//! ```rust
32//! use compressed_intvec::fixed::{FixedVec, UFixedVec, BitWidth};
33//!
34//! let data: Vec<u32> = (0..10).collect();
35//! let mut vec: UFixedVec<u32> = FixedVec::builder().bit_width(BitWidth::Explicit(7)).build(&data).unwrap();
36//!
37//! // `split_at_mut` is one way to get mutable slices.
38//! let (_, mut slice2) = vec.split_at_mut(5);
39//!
40//! // Mutate an element within the second slice.
41//! if let Some(mut proxy) = slice2.at_mut(0) { // index 0 of slice2 is index 5 of vec
42//!     *proxy = 99;
43//! }
44//!
45//! assert_eq!(vec.get(5), Some(99));
46//! ```
47
48use crate::fixed::{
49    iter::FixedVecSliceIter,
50    proxy::MutProxy,
51    traits::{Storable, Word},
52    FixedVec,
53};
54use dsi_bitstream::prelude::Endianness;
55use std::ops::{Deref, DerefMut, Range};
56
57/// A zero-copy view into a contiguous portion of a [`FixedVec`].
58///
59/// A slice is a view that allows for operations on a sub-region of a [`FixedVec`]
60/// without copying the underlying data. It can be created from both immutable
61/// and mutable vectors.
62///
63/// This struct is generic over `V`, the type of reference to the parent vector,
64/// which can be `&FixedVec` (for an immutable slice) or `&mut FixedVec` (for a
65/// mutable slice).
66#[derive(Debug)]
67pub struct FixedVecSlice<V> {
68    pub(super) parent: V,
69    pub(super) range: Range<usize>,
70}
71
72// Common implementation for both immutable and mutable slices.
73impl<T, W, E, B, V> FixedVecSlice<V>
74where
75    T: Storable<W>,
76    W: Word,
77    E: Endianness,
78    B: AsRef<[W]>,
79    V: Deref<Target = FixedVec<T, W, E, B>>,
80{
81    /// Creates a new `FixedVecSlice`.
82    pub(super) fn new(parent: V, range: Range<usize>) -> Self {
83        // The range is asserted to be within the parent's bounds upon creation.
84        debug_assert!(range.end <= parent.len());
85        Self { parent, range }
86    }
87
88    /// Returns the number of elements in the slice.
89    #[inline]
90    pub fn len(&self) -> usize {
91        self.range.len()
92    }
93
94    /// Returns `true` if the slice is empty.
95    #[inline]
96    pub fn is_empty(&self) -> bool {
97        self.range.is_empty()
98    }
99
100    /// Returns the element at `index` relative to the start of the slice.
101    ///
102    /// Returns `None` if `index` is out of bounds of the slice.
103    #[inline]
104    pub fn get(&self, index: usize) -> Option<T> {
105        if index >= self.len() {
106            return None;
107        }
108        // SAFETY: The bounds check above ensures `index` is valid.
109        Some(unsafe { self.get_unchecked(index) })
110    }
111
112    /// Returns the element at `index` without bounds checking.
113    ///
114    /// The index is relative to the start of the slice.
115    ///
116    /// # Safety
117    ///
118    /// Calling this method with an out-of-bounds `index` is undefined behavior.
119    #[inline(always)]
120    pub unsafe fn get_unchecked(&self, index: usize) -> T {
121        debug_assert!(index < self.len());
122        // The index is relative to the slice, so we add the slice's start offset
123        // to get the correct index in the parent vector.
124        self.parent.get_unchecked(self.range.start + index)
125    }
126
127    /// Returns an iterator over the elements in the slice.
128    pub fn iter(&self) -> FixedVecSliceIter<'_, T, W, E, B, V> {
129        FixedVecSliceIter::new(self)
130    }
131
132    /// Binary searches this slice for a given element.
133    ///
134    /// If the value is found, returns `Ok(usize)` with the index of the
135    /// matching element within the slice. If the value is not found, returns
136    /// `Err(usize)` with the index where the value could be inserted to
137    /// maintain order.
138    pub fn binary_search(&self, value: &T) -> Result<usize, usize>
139    where
140        T: Ord,
141    {
142        let mut low = 0;
143        let mut high = self.len();
144
145        while low < high {
146            let mid = low + (high - low) / 2;
147            // SAFETY: The loop invariants ensure `mid` is always in bounds.
148            let mid_val = unsafe { self.get_unchecked(mid) };
149
150            match mid_val.cmp(value) {
151                std::cmp::Ordering::Less => low = mid + 1,
152                std::cmp::Ordering::Equal => return Ok(mid),
153                std::cmp::Ordering::Greater => high = mid,
154            }
155        }
156        Err(low)
157    }
158}
159
160// Mutable-only implementation.
161impl<T, W, E, B, V> FixedVecSlice<V>
162where
163    T: Storable<W>,
164    W: Word,
165    E: Endianness,
166    B: AsRef<[W]> + AsMut<[W]>,
167    V: Deref<Target = FixedVec<T, W, E, B>> + DerefMut,
168{
169    /// Returns a mutable proxy for an element at `index` within the slice.
170    ///
171    /// This allows for syntax like `*slice.at_mut(i).unwrap() = new_value;`.
172    ///
173    /// Returns `None` if the index is out of bounds of the slice.
174    pub fn at_mut(&mut self, index: usize) -> Option<MutProxy<'_, T, W, E, B>> {
175        if index >= self.len() {
176            return None;
177        }
178        // The index is translated to the parent vector's coordinate space.
179        Some(MutProxy::new(&mut self.parent, self.range.start + index))
180    }
181}
182
183// --- PartialEq Implementations ---
184
185impl<T, W, E, B, V1, V2> PartialEq<FixedVecSlice<V2>> for FixedVecSlice<V1>
186where
187    T: Storable<W> + PartialEq,
188    W: Word,
189    E: Endianness,
190    B: AsRef<[W]>,
191    V1: Deref<Target = FixedVec<T, W, E, B>>,
192    V2: Deref<Target = FixedVec<T, W, E, B>>,
193{
194    fn eq(&self, other: &FixedVecSlice<V2>) -> bool {
195        if self.len() != other.len() {
196            return false;
197        }
198        self.iter().eq(other.iter())
199    }
200}
201
202impl<T, W, E, B, V> Eq for FixedVecSlice<V>
203where
204    T: Storable<W> + Eq,
205    W: Word,
206    E: Endianness,
207    B: AsRef<[W]>,
208    V: Deref<Target = FixedVec<T, W, E, B>>,
209{
210}
211
212impl<T, W, E, B, B2, V> PartialEq<FixedVec<T, W, E, B2>> for FixedVecSlice<V>
213where
214    T: Storable<W> + PartialEq,
215    W: Word,
216    E: Endianness,
217    B: AsRef<[W]>,
218    B2: AsRef<[W]>,
219    V: Deref<Target = FixedVec<T, W, E, B>>,
220{
221    fn eq(&self, other: &FixedVec<T, W, E, B2>) -> bool {
222        if self.len() != other.len() {
223            return false;
224        }
225        self.iter().eq(other.iter())
226    }
227}
228
229impl<T, W, E, B, B2, V> PartialEq<FixedVecSlice<V>> for FixedVec<T, W, E, B>
230where
231    T: Storable<W> + PartialEq,
232    W: Word,
233    E: Endianness,
234    B: AsRef<[W]>,
235    B2: AsRef<[W]>,
236    V: Deref<Target = FixedVec<T, W, E, B2>>,
237{
238    fn eq(&self, other: &FixedVecSlice<V>) -> bool {
239        if self.len() != other.len() {
240            return false;
241        }
242        self.iter().eq(other.iter())
243    }
244}
245
246impl<T, W, E, B, T2, V> PartialEq<&[T2]> for FixedVecSlice<V>
247where
248    T: Storable<W> + PartialEq<T2>,
249    W: Word,
250    E: Endianness,
251    B: AsRef<[W]>,
252    T2: Clone,
253    V: Deref<Target = FixedVec<T, W, E, B>>,
254{
255    fn eq(&self, other: &&[T2]) -> bool {
256        if self.len() != other.len() {
257            return false;
258        }
259        self.iter().zip(other.iter()).all(|(a, b)| a == *b)
260    }
261}
262
263impl<T, W, E, B, B2, V> PartialEq<&FixedVec<T, W, E, B2>> for FixedVecSlice<V>
264where
265    T: Storable<W> + PartialEq,
266    W: Word,
267    E: Endianness,
268    B: AsRef<[W]>,
269    B2: AsRef<[W]>,
270    V: Deref<Target = FixedVec<T, W, E, B>>,
271{
272    fn eq(&self, other: &&FixedVec<T, W, E, B2>) -> bool {
273        self.eq(*other)
274    }
275}