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