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