1#![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
14pub struct TaggedVec<Index, Value> {
18 index_type: PhantomData<Index>,
19 vec: Vec<Value>,
20}
21
22impl<Index, Value> TaggedVec<Index, Value> {
23 pub fn new() -> Self {
25 Self::default()
26 }
27
28 pub fn with_capacity(capacity: usize) -> Self {
30 Self {
31 index_type: PhantomData,
32 vec: Vec::with_capacity(capacity),
33 }
34 }
35
36 pub fn len(&self) -> usize {
38 self.vec.len()
39 }
40
41 pub fn is_empty(&self) -> bool {
43 self.vec.is_empty()
44 }
45
46 pub fn capacity(&self) -> usize {
48 self.vec.capacity()
49 }
50
51 pub fn push(&mut self, value: Value) -> Index
53 where
54 Index: From<usize>,
55 {
56 let index = self.vec.len().into();
57 self.vec.push(value);
58 index
59 }
60
61 pub fn push_in_place(&mut self, value: impl FnOnce(Index) -> Value) -> Index
66 where
67 Index: From<usize>,
68 {
69 let index = self.vec.len();
70 self.vec.push(value(index.into()));
71 index.into()
72 }
73
74 pub fn pop(&mut self) -> Option<(Index, Value)>
76 where
77 Index: From<usize>,
78 {
79 if let Some(value) = self.vec.pop() {
80 Some((self.vec.len().into(), value))
81 } else {
82 None
83 }
84 }
85
86 pub fn insert(&mut self, index: Index, value: Value)
88 where
89 Index: Into<usize>,
90 {
91 self.vec.insert(index.into(), value);
92 }
93
94 pub fn splice<I: IntoIterator<Item = Value>>(
96 &mut self,
97 range: impl RangeBounds<Index>,
98 replace_with: I,
99 ) -> std::vec::Splice<'_, I::IntoIter>
100 where
101 usize: for<'a> From<&'a Index>,
102 {
103 self.vec.splice(MappedRangeBounds::new(range), replace_with)
104 }
105
106 pub fn retain(&mut self, f: impl FnMut(&Value) -> bool) {
111 self.vec.retain(f);
112 }
113
114 pub fn remove_multi(&mut self, indices: impl IntoIterator<Item = Index>)
118 where
119 Index: Into<usize> + Clone,
120 {
121 let mut indices = indices.into_iter().peekable();
122 let mut current_index = 0;
123 self.vec.retain(|_| {
124 if let Some(next_delete_index) = indices.peek() {
125 let next_delete_index = next_delete_index.clone().into();
126 let result = if next_delete_index == current_index {
127 indices.next();
128
129 if let Some(next_next_delete_index) = indices.peek() {
130 let next_next_delete_index: usize = next_next_delete_index.clone().into();
131 assert!(next_next_delete_index > next_delete_index);
132 }
133
134 false
135 } else {
136 true
137 };
138 current_index += 1;
139 result
140 } else {
141 true
142 }
143 });
144
145 assert!(indices.next().is_none());
146 }
147
148 pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Index, &Value)> + ExactSizeIterator
150 where
151 Index: From<usize>,
152 {
153 self.vec
154 .iter()
155 .enumerate()
156 .map(|(index, value)| (index.into(), value))
157 }
158
159 pub fn iter_mut(
161 &mut self,
162 ) -> impl DoubleEndedIterator<Item = (Index, &mut Value)> + ExactSizeIterator
163 where
164 Index: From<usize>,
165 {
166 self.vec
167 .iter_mut()
168 .enumerate()
169 .map(|(index, value)| (index.into(), value))
170 }
171
172 pub fn iter_values(&self) -> std::slice::Iter<'_, Value> {
174 self.vec.iter()
175 }
176
177 pub fn iter_values_mut(&mut self) -> std::slice::IterMut<'_, Value> {
179 self.vec.iter_mut()
180 }
181
182 pub fn iter_indices(&self) -> impl DoubleEndedIterator<Item = Index> + ExactSizeIterator
184 where
185 Index: From<usize>,
186 {
187 (0..self.vec.len()).map(Into::into)
188 }
189
190 pub fn into_values_iter(self) -> std::vec::IntoIter<Value> {
192 self.vec.into_iter()
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use crate::TaggedVec;
199
200 #[test]
201 fn delete_multi() {
202 let mut v = TaggedVec::<usize, _>::from_iter([0, 1, 2, 3, 4]);
203 v.remove_multi([0, 4]);
204 assert_eq!(v, vec![1, 2, 3].into());
205
206 let mut v = TaggedVec::<usize, _>::from_iter([0, 1, 2, 3, 4]);
207 v.remove_multi([0, 2, 4]);
208 assert_eq!(v, vec![1, 3].into());
209
210 let mut v = TaggedVec::<usize, _>::from_iter([0, 1, 2, 3, 4]);
211 v.remove_multi([1, 3]);
212 assert_eq!(v, vec![0, 2, 4].into());
213 }
214}