Skip to main content

tagged_vec/
lib.rs

1//! An alternative to the standard libraries' [`Vec`] which is indexed with a custom type instead of [`usize`].
2//!
3//! This is useful to catch errors like using the wrong variable to index the vector.
4
5#![warn(missing_docs)]
6
7use std::{
8    marker::PhantomData,
9    ops::{Bound, RangeBounds},
10};
11
12use mapped_range_bounds::MappedRangeBounds;
13
14pub use crate::index_iterator::IndexIterator;
15
16#[cfg(feature = "binary-io")]
17mod binary_io;
18mod index_iterator;
19mod mapped_range_bounds;
20#[cfg(test)]
21mod tests;
22mod trait_impls;
23
24/// A [`Vec`] wrapper that allows indexing only via the given `Index` type.
25///
26/// For actual operation, `Index` must implement [`From<usize>`] and [`Into<usize>`].
27pub struct TaggedVec<Index, Value> {
28    index_type: PhantomData<Index>,
29    vec: Vec<Value>,
30}
31
32impl<Index, Value> TaggedVec<Index, Value> {
33    /// Creates a new empty `TaggedVec`.
34    pub fn new() -> Self {
35        Self::default()
36    }
37
38    /// Creates a new empty `TaggedVec` with at least the specified capacity.
39    pub fn with_capacity(capacity: usize) -> Self {
40        Self {
41            index_type: PhantomData,
42            vec: Vec::with_capacity(capacity),
43        }
44    }
45
46    /// Returns the number of elements in the `TaggedVec`.
47    pub fn len(&self) -> usize {
48        self.vec.len()
49    }
50
51    /// Returns `true` if the `TaggedVec` contains no elements.
52    pub fn is_empty(&self) -> bool {
53        self.vec.is_empty()
54    }
55
56    /// Returns the total number of elements the `TaggedVec` can hold without reallocating.
57    pub fn capacity(&self) -> usize {
58        self.vec.capacity()
59    }
60
61    /// Returns the untagged slice of the `Vec` underlying this `TaggedVec`.
62    pub fn as_untagged_slice(&self) -> &[Value] {
63        &self.vec
64    }
65
66    /// Returns the untagged mutable slice of the `Vec` underlying this `TaggedVec`.
67    pub fn as_untagged_mut_slice(&mut self) -> &mut [Value] {
68        &mut self.vec
69    }
70
71    /// Inserts the given value at the back of the `TaggedVec`, returning its index.
72    pub fn push(&mut self, value: Value) -> Index
73    where
74        Index: From<usize>,
75    {
76        let index = self.vec.len().into();
77        self.vec.push(value);
78        index
79    }
80
81    /// Insert a single value into the `TaggedVec` by constructing it in place.
82    ///
83    /// This method allows to create the value while already knowing its index.
84    /// Returns the index.
85    pub fn push_in_place(&mut self, value: impl FnOnce(Index) -> Value) -> Index
86    where
87        Index: From<usize>,
88    {
89        let index = self.vec.len();
90        self.vec.push(value(index.into()));
91        index.into()
92    }
93
94    /// Removes the value at the back of the `TaggedVec` and returns it with its index.
95    pub fn pop(&mut self) -> Option<(Index, Value)>
96    where
97        Index: From<usize>,
98    {
99        if let Some(value) = self.vec.pop() {
100            Some((self.vec.len().into(), value))
101        } else {
102            None
103        }
104    }
105
106    /// Inserts the given `value` at position `index`, shifting all existing values in range `index..` one position to the right.
107    pub fn insert(&mut self, index: Index, value: Value)
108    where
109        Index: Into<usize>,
110    {
111        self.vec.insert(index.into(), value);
112    }
113
114    /// See [`Vec::splice`].
115    pub fn splice<I: IntoIterator<Item = Value>>(
116        &mut self,
117        range: impl RangeBounds<Index>,
118        replace_with: I,
119    ) -> std::vec::Splice<'_, I::IntoIter>
120    where
121        usize: From<Index>,
122        Index: Copy,
123    {
124        self.vec.splice(MappedRangeBounds::new(range), replace_with)
125    }
126
127    /// Retains only the values specified by the predicate.
128    ///
129    /// In other words, remove all values `v` for which `f(&v)` returns `false`.
130    /// This method operates in place, visiting each value exactly once in the original order, and preserves the order of the retained values.
131    pub fn retain(&mut self, f: impl FnMut(&Value) -> bool) {
132        self.vec.retain(f);
133    }
134
135    /// Removes the elements at the specified indices, shifting other elements to the left to fill gaps as required.
136    ///
137    /// The provided indices must be sorted.
138    pub fn remove_multi(&mut self, indices: impl IntoIterator<Item = Index>)
139    where
140        Index: Into<usize> + Clone,
141    {
142        let mut indices = indices.into_iter().peekable();
143        let mut current_index = 0;
144        self.vec.retain(|_| {
145            if let Some(next_delete_index) = indices.peek() {
146                let next_delete_index = next_delete_index.clone().into();
147                let result = if next_delete_index == current_index {
148                    indices.next();
149
150                    if let Some(next_next_delete_index) = indices.peek() {
151                        let next_next_delete_index: usize = next_next_delete_index.clone().into();
152                        assert!(next_next_delete_index > next_delete_index);
153                    }
154
155                    false
156                } else {
157                    true
158                };
159                current_index += 1;
160                result
161            } else {
162                true
163            }
164        });
165
166        assert!(indices.next().is_none());
167    }
168
169    /// Returns a reference to the value at the given index, or `None` if the index is out of bounds.
170    pub fn get(&self, index: Index) -> Option<&Value>
171    where
172        Index: Into<usize>,
173    {
174        self.vec.get(index.into())
175    }
176
177    /// Returns an iterator over references to the entries of the `TaggedVec`.
178    ///
179    /// The `range` specifies which subset of the entries to iterate over.
180    /// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
181    pub fn iter(
182        &self,
183        range: impl RangeBounds<Index>,
184    ) -> impl DoubleEndedIterator<Item = (Index, &Value)> + ExactSizeIterator
185    where
186        Index: From<usize> + Copy,
187        usize: From<Index>,
188    {
189        let range = MappedRangeBounds::new(range);
190        let start_index_inclusive = match range.start_bound() {
191            Bound::Included(index) => *index,
192            Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
193            Bound::Unbounded => 0,
194        };
195        let end_index_exclusive = match range.end_bound() {
196            Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
197            Bound::Excluded(index) => *index,
198            Bound::Unbounded => self.vec.len(),
199        };
200
201        self.vec
202            .iter()
203            .enumerate()
204            .skip(start_index_inclusive)
205            .take(end_index_exclusive - start_index_inclusive)
206            .map(|(index, value)| (index.into(), value))
207    }
208
209    /// Returns an iterator over mutable references to the entries of the `TaggedVec`.
210    ///
211    /// The `range` specifies which subset of the entries to iterate over.
212    /// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
213    pub fn iter_mut(
214        &mut self,
215        range: impl RangeBounds<Index>,
216    ) -> impl DoubleEndedIterator<Item = (Index, &mut Value)> + ExactSizeIterator
217    where
218        Index: From<usize> + Copy,
219        usize: From<Index>,
220    {
221        let range = MappedRangeBounds::new(range);
222        let start_index_inclusive = match range.start_bound() {
223            Bound::Included(index) => *index,
224            Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
225            Bound::Unbounded => 0,
226        };
227        let end_index_exclusive = match range.end_bound() {
228            Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
229            Bound::Excluded(index) => *index,
230            Bound::Unbounded => self.vec.len(),
231        };
232
233        self.vec
234            .iter_mut()
235            .enumerate()
236            .skip(start_index_inclusive)
237            .take(end_index_exclusive - start_index_inclusive)
238            .map(|(index, value)| (index.into(), value))
239    }
240
241    /// Returns an iterator over references to the values of the `TaggedVec`.
242    pub fn iter_values(&self) -> std::slice::Iter<'_, Value> {
243        self.vec.iter()
244    }
245
246    /// Returns an iterator over mutable references to the values of the `TaggedVec`.
247    pub fn iter_values_mut(&mut self) -> std::slice::IterMut<'_, Value> {
248        self.vec.iter_mut()
249    }
250
251    /// Returns an iterator over the indices of the `TaggedVec`.
252    ///
253    /// The `range` specifies which subset of the entries to iterate over.
254    /// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
255    pub fn iter_indices(&self, range: impl RangeBounds<Index>) -> IndexIterator<Index>
256    where
257        Index: From<usize> + Copy,
258        usize: From<Index>,
259    {
260        let range = MappedRangeBounds::new(range);
261        let start_index_inclusive = match range.start_bound() {
262            Bound::Included(index) => *index,
263            Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
264            Bound::Unbounded => 0,
265        };
266        let end_index_exclusive = match range.end_bound() {
267            Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
268            Bound::Excluded(index) => *index,
269            Bound::Unbounded => self.vec.len(),
270        };
271
272        IndexIterator::new(start_index_inclusive, end_index_exclusive)
273    }
274
275    /// Consumes the `TaggedVec`, returning an iterator over the entries.
276    ///
277    /// The `range` specifies which subset of the entries to iterate over.
278    /// Iterating over a partial range with this argument is more efficient than iterating over the whole vector and skipping the unwanted entries, because the returned iterator does not support the skip optimisation.
279    pub fn into_iter(
280        self,
281        range: impl RangeBounds<Index>,
282    ) -> impl DoubleEndedIterator<Item = (Index, Value)> + ExactSizeIterator
283    where
284        Index: From<usize> + Copy,
285        usize: From<Index>,
286    {
287        let range = MappedRangeBounds::new(range);
288        let start_index_inclusive = match range.start_bound() {
289            Bound::Included(index) => *index,
290            Bound::Excluded(index) => (*index).checked_add(1).expect("start index overflow"),
291            Bound::Unbounded => 0,
292        };
293        let end_index_exclusive = match range.end_bound() {
294            Bound::Included(index) => (*index).checked_add(1).expect("end index overflow"),
295            Bound::Excluded(index) => *index,
296            Bound::Unbounded => self.vec.len(),
297        };
298
299        self.vec
300            .into_iter()
301            .enumerate()
302            .skip(start_index_inclusive)
303            .take(end_index_exclusive - start_index_inclusive)
304            .map(|(index, value)| (index.into(), value))
305    }
306
307    /// Consumes the `TaggedVec`, returning an iterator over the values.
308    pub fn into_values_iter(self) -> std::vec::IntoIter<Value> {
309        self.vec.into_iter()
310    }
311
312    /// Removes all values from the `TaggedVec`.
313    pub fn clear(&mut self) {
314        self.vec.clear()
315    }
316}