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::{marker::PhantomData, ops::RangeBounds};
8
9use mapped_range_bounds::MappedRangeBounds;
10
11mod mapped_range_bounds;
12mod trait_impls;
13
14/// A [`Vec`] wrapper that allows indexing only via the given `Index` type.
15///
16/// For actual operation, `Index` must implement [`From<usize>`] and [`Into<usize>`].
17pub struct TaggedVec<Index, Value> {
18    index_type: PhantomData<Index>,
19    vec: Vec<Value>,
20}
21
22impl<Index, Value> TaggedVec<Index, Value> {
23    /// Creates a new empty `TaggedVec`.
24    pub fn new() -> Self {
25        Self::default()
26    }
27
28    /// Creates a new empty `TaggedVec` with at least the specified capacity.
29    pub fn with_capacity(capacity: usize) -> Self {
30        Self {
31            index_type: PhantomData,
32            vec: Vec::with_capacity(capacity),
33        }
34    }
35
36    /// Returns the number of elements in the `TaggedVec`.
37    pub fn len(&self) -> usize {
38        self.vec.len()
39    }
40
41    /// Returns `true` if the `TaggedVec` contains no elements.
42    pub fn is_empty(&self) -> bool {
43        self.vec.is_empty()
44    }
45
46    /// Returns the total number of elements the `TaggedVec` can hold without reallocating.
47    pub fn capacity(&self) -> usize {
48        self.vec.capacity()
49    }
50
51    /// Returns the untagged slice underlying this `TaggedVec`.
52    pub fn as_untagged_slice(&self) -> &[Value] {
53        &self.vec
54    }
55
56    /// Inserts the given value at the back of the `TaggedVec`, returning its index.
57    pub fn push(&mut self, value: Value) -> Index
58    where
59        Index: From<usize>,
60    {
61        let index = self.vec.len().into();
62        self.vec.push(value);
63        index
64    }
65
66    /// Insert a single value into the `TaggedVec` by constructing it in place.
67    ///
68    /// This method allows to create the value while already knowing its index.
69    /// Returns the index.
70    pub fn push_in_place(&mut self, value: impl FnOnce(Index) -> Value) -> Index
71    where
72        Index: From<usize>,
73    {
74        let index = self.vec.len();
75        self.vec.push(value(index.into()));
76        index.into()
77    }
78
79    /// Removes the value at the back of the `TaggedVec` and returns it with its index.
80    pub fn pop(&mut self) -> Option<(Index, Value)>
81    where
82        Index: From<usize>,
83    {
84        if let Some(value) = self.vec.pop() {
85            Some((self.vec.len().into(), value))
86        } else {
87            None
88        }
89    }
90
91    /// Inserts the given `value` at position `index`, shifting all existing values in range `index..` one position to the right.
92    pub fn insert(&mut self, index: Index, value: Value)
93    where
94        Index: Into<usize>,
95    {
96        self.vec.insert(index.into(), value);
97    }
98
99    /// See [`Vec::splice`].
100    pub fn splice<I: IntoIterator<Item = Value>>(
101        &mut self,
102        range: impl RangeBounds<Index>,
103        replace_with: I,
104    ) -> std::vec::Splice<'_, I::IntoIter>
105    where
106        usize: for<'a> From<&'a Index>,
107    {
108        self.vec.splice(MappedRangeBounds::new(range), replace_with)
109    }
110
111    /// Retains only the values specified by the predicate.
112    ///
113    /// In other words, remove all values `v` for which `f(&v)` returns `false`.
114    /// This method operates in place, visiting each value exactly once in the original order, and preserves the order of the retained values.
115    pub fn retain(&mut self, f: impl FnMut(&Value) -> bool) {
116        self.vec.retain(f);
117    }
118
119    /// Removes the elements at the specified indices, shifting other elements to the left to fill gaps as required.
120    ///
121    /// The provided indices must be sorted.
122    pub fn remove_multi(&mut self, indices: impl IntoIterator<Item = Index>)
123    where
124        Index: Into<usize> + Clone,
125    {
126        let mut indices = indices.into_iter().peekable();
127        let mut current_index = 0;
128        self.vec.retain(|_| {
129            if let Some(next_delete_index) = indices.peek() {
130                let next_delete_index = next_delete_index.clone().into();
131                let result = if next_delete_index == current_index {
132                    indices.next();
133
134                    if let Some(next_next_delete_index) = indices.peek() {
135                        let next_next_delete_index: usize = next_next_delete_index.clone().into();
136                        assert!(next_next_delete_index > next_delete_index);
137                    }
138
139                    false
140                } else {
141                    true
142                };
143                current_index += 1;
144                result
145            } else {
146                true
147            }
148        });
149
150        assert!(indices.next().is_none());
151    }
152
153    /// Returns an iterator over references to the entries of the `TaggedVec`.
154    pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Index, &Value)> + ExactSizeIterator
155    where
156        Index: From<usize>,
157    {
158        self.vec
159            .iter()
160            .enumerate()
161            .map(|(index, value)| (index.into(), value))
162    }
163
164    /// Returns an iterator over mutable references to the entries of the `TaggedVec`.
165    pub fn iter_mut(
166        &mut self,
167    ) -> impl DoubleEndedIterator<Item = (Index, &mut Value)> + ExactSizeIterator
168    where
169        Index: From<usize>,
170    {
171        self.vec
172            .iter_mut()
173            .enumerate()
174            .map(|(index, value)| (index.into(), value))
175    }
176
177    /// Returns an iterator over references to the values of the `TaggedVec`.
178    pub fn iter_values(&self) -> std::slice::Iter<'_, Value> {
179        self.vec.iter()
180    }
181
182    /// Returns an iterator over mutable references to the values of the `TaggedVec`.
183    pub fn iter_values_mut(&mut self) -> std::slice::IterMut<'_, Value> {
184        self.vec.iter_mut()
185    }
186
187    /// Returns an iterator over the indices of the `TaggedVec`.
188    pub fn iter_indices(&self) -> impl DoubleEndedIterator<Item = Index> + ExactSizeIterator
189    where
190        Index: From<usize>,
191    {
192        (0..self.vec.len()).map(Into::into)
193    }
194
195    /// Consumes the `TaggedVec`, returning an iterator over the values.
196    pub fn into_values_iter(self) -> std::vec::IntoIter<Value> {
197        self.vec.into_iter()
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use crate::TaggedVec;
204
205    #[test]
206    fn delete_multi() {
207        let mut v = TaggedVec::<usize, _>::from_iter([0, 1, 2, 3, 4]);
208        v.remove_multi([0, 4]);
209        assert_eq!(v, vec![1, 2, 3].into());
210
211        let mut v = TaggedVec::<usize, _>::from_iter([0, 1, 2, 3, 4]);
212        v.remove_multi([0, 2, 4]);
213        assert_eq!(v, vec![1, 3].into());
214
215        let mut v = TaggedVec::<usize, _>::from_iter([0, 1, 2, 3, 4]);
216        v.remove_multi([1, 3]);
217        assert_eq!(v, vec![0, 2, 4].into());
218    }
219}