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    /// Removes the value at the back of the `TaggedVec` and returns it with its index.
49    pub fn pop(&mut self) -> Option<(Index, Value)>
50    where
51        Index: From<usize>,
52    {
53        if let Some(value) = self.vec.pop() {
54            Some((self.vec.len().into(), value))
55        } else {
56            None
57        }
58    }
59
60    /// Inserts the given `value` at position `index`, shifting all existing values in range `index..` one position to the right.
61    pub fn insert(&mut self, index: Index, value: Value)
62    where
63        Index: Into<usize>,
64    {
65        self.vec.insert(index.into(), value);
66    }
67
68    /// See [`Vec::splice`].
69    pub fn splice<I: IntoIterator<Item = Value>>(
70        &mut self,
71        range: impl RangeBounds<Index>,
72        replace_with: I,
73    ) -> std::vec::Splice<'_, I::IntoIter>
74    where
75        usize: for<'a> From<&'a Index>,
76    {
77        self.vec.splice(MappedRangeBounds::new(range), replace_with)
78    }
79
80    /// Retains only the values specified by the predicate.
81    ///
82    /// In other words, remove all values `v` for which `f(&v)` returns `false`.
83    /// This method operates in place, visiting each value exactly once in the original order, and preserves the order of the retained values.
84    pub fn retain(&mut self, f: impl FnMut(&Value) -> bool) {
85        self.vec.retain(f);
86    }
87
88    /// Returns an iterator over references to the entries of the `TaggedVec`.
89    pub fn iter(&self) -> impl Iterator<Item = (Index, &Value)>
90    where
91        Index: From<usize>,
92    {
93        self.vec
94            .iter()
95            .enumerate()
96            .map(|(index, value)| (index.into(), value))
97    }
98
99    /// Returns an iterator over mutable references to the entries of the `TaggedVec`.
100    pub fn iter_mut(&mut self) -> impl Iterator<Item = (Index, &mut Value)>
101    where
102        Index: From<usize>,
103    {
104        self.vec
105            .iter_mut()
106            .enumerate()
107            .map(|(index, value)| (index.into(), value))
108    }
109
110    /// Returns an iterator over references to the values of the `TaggedVec`.
111    pub fn iter_values(&self) -> std::slice::Iter<'_, Value> {
112        self.vec.iter()
113    }
114
115    /// Returns an iterator over mutable references to the values of the `TaggedVec`.
116    pub fn iter_values_mut(&mut self) -> std::slice::IterMut<'_, Value> {
117        self.vec.iter_mut()
118    }
119
120    /// Returns an iterator over the indices of the `TaggedVec`.
121    pub fn iter_indices(&self) -> impl Iterator<Item = Index>
122    where
123        Index: From<usize>,
124    {
125        (0..self.vec.len()).map(Into::into)
126    }
127}