chunky_vec/
lib.rs

1//! This crate provides a pin-safe, append-only vector which guarantees never
2//! to move the storage for an element once it has been allocated.
3
4use std::{
5    ops::{Index, IndexMut},
6    slice,
7};
8
9struct Chunk<T> {
10    /// The elements of this chunk.
11    elements: Vec<T>,
12}
13
14impl<T> Chunk<T> {
15    fn with_capacity(capacity: usize) -> Self {
16        let elements = Vec::with_capacity(capacity);
17        assert_eq!(elements.capacity(), capacity);
18        Self { elements }
19    }
20
21    fn len(&self) -> usize {
22        self.elements.len()
23    }
24
25    /// Returns the number of available empty elements.
26    fn available(&self) -> usize {
27        self.elements.capacity() - self.elements.len()
28    }
29
30    /// Returns a shared reference to the element at the given index.
31    ///
32    /// # Panics
33    ///
34    /// Panics if the index is out of bounds.
35    pub fn get(&self, index: usize) -> Option<&T> {
36        self.elements.get(index)
37    }
38
39    /// Returns an exclusive reference to the element at the given index.
40    ///
41    /// # Panics
42    ///
43    /// Panics if the index is out of bounds.
44    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
45        self.elements.get_mut(index)
46    }
47
48    /// Pushes a new value into the fixed capacity entry.
49    ///
50    /// # Panics
51    ///
52    /// If the entry is already at its capacity.
53    /// Note that this panic should never happen since the entry is only ever
54    /// accessed by its outer chunk vector that checks before pushing.
55    pub fn push(&mut self, new_value: T) {
56        if self.available() == 0 {
57            panic!("No available elements.")
58        }
59        self.elements.push(new_value);
60    }
61
62    pub fn push_get(&mut self, new_value: T) -> &mut T {
63        self.push(new_value);
64        unsafe {
65            let last = self.elements.len() - 1;
66            self.elements.get_unchecked_mut(last)
67        }
68    }
69
70    /// Returns an iterator over the elements of the chunk.
71    pub fn iter(&self) -> slice::Iter<T> {
72        self.elements.iter()
73    }
74
75    /// Returns an iterator over the elements of the chunk.
76    pub fn iter_mut(&mut self) -> slice::IterMut<T> {
77        self.elements.iter_mut()
78    }
79}
80
81impl<T> Index<usize> for Chunk<T> {
82    type Output = T;
83
84    fn index(&self, index: usize) -> &Self::Output {
85        self.get(index).expect("index out of bounds")
86    }
87}
88
89impl<T> IndexMut<usize> for Chunk<T> {
90    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
91        self.get_mut(index).expect("index out of bounds")
92    }
93}
94
95/// Pin safe vector
96///
97/// An append only vector that never moves the backing store for each element.
98pub struct ChunkyVec<T> {
99    /// The chunks holding elements
100    chunks: Vec<Chunk<T>>,
101}
102
103impl<T> Default for ChunkyVec<T> {
104    fn default() -> Self {
105        Self {
106            chunks: Vec::default(),
107        }
108    }
109}
110
111impl<T> Unpin for ChunkyVec<T> {}
112
113impl<T> ChunkyVec<T> {
114    const DEFAULT_CAPACITY: usize = 32;
115
116    pub fn len(&self) -> usize {
117        if self.chunks.is_empty() {
118            0
119        } else {
120            // # Safety - There is at least one chunk here.
121            (self.chunks.len() - 1) * Self::DEFAULT_CAPACITY + self.chunks.last().unwrap().len()
122        }
123    }
124
125    pub fn is_empty(&self) -> bool {
126        // # Safety - Since it's impossible to pop, at least one chunk means we're not empty.
127        self.chunks.is_empty()
128    }
129
130    /// Returns an iterator that yields shared references to the elements of the bucket vector.
131    pub fn iter(&self) -> Iter<T> {
132        Iter::new(self)
133    }
134
135    /// Returns an iterator that yields exclusive reference to the elements of the bucket vector.
136    pub fn iter_mut(&mut self) -> IterMut<T> {
137        IterMut::new(self)
138    }
139
140    /// Returns a shared reference to the element at the given index if any.
141    pub fn get(&self, index: usize) -> Option<&T> {
142        let (x, y) = (
143            index / Self::DEFAULT_CAPACITY,
144            index % Self::DEFAULT_CAPACITY,
145        );
146        self.chunks.get(x).and_then(|chunk| chunk.get(y))
147    }
148
149    /// Returns an exclusive reference to the element at the given index if any.
150    pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
151        let (x, y) = (
152            index / Self::DEFAULT_CAPACITY,
153            index % Self::DEFAULT_CAPACITY,
154        );
155        self.chunks.get_mut(x).and_then(|chunk| chunk.get_mut(y))
156    }
157
158    /// Pushes a new element onto the bucket vector.
159    ///
160    /// # Note
161    ///
162    /// This operation will never move other elements, reallocates or otherwise
163    /// invalidate pointers of elements contained by the bucket vector.
164    pub fn push(&mut self, new_value: T) {
165        self.push_get(new_value);
166    }
167
168    pub fn push_get(&mut self, new_value: T) -> &mut T {
169        if self.chunks.last().map(Chunk::available).unwrap_or_default() == 0 {
170            self.chunks.push(Chunk::with_capacity(Self::DEFAULT_CAPACITY));
171        }
172        // Safety: Guaranteed to have a chunk with available elements
173        unsafe {
174            let last = self.chunks.len() - 1;
175            self.chunks.get_unchecked_mut(last).push_get(new_value)
176        }
177    }
178}
179
180impl<T> Index<usize> for ChunkyVec<T> {
181    type Output = T;
182
183    fn index(&self, index: usize) -> &Self::Output {
184        self.get(index).expect("index out of bounds")
185    }
186}
187
188impl<T> IndexMut<usize> for ChunkyVec<T> {
189    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
190        self.get_mut(index).expect("index out of bounds")
191    }
192}
193
194/// An iterator yielding shared references to the elements of a ChunkyVec.
195#[derive(Clone)]
196pub struct Iter<'a, T> {
197    /// Chunks iterator.
198    chunks: slice::Iter<'a, Chunk<T>>,
199    /// Forward iterator for `next`.
200    iter: Option<slice::Iter<'a, T>>,
201    /// Number of elements that are to be yielded by the iterator.
202    len: usize,
203}
204
205impl<'a, T> Iter<'a, T> {
206    /// Creates a new iterator over the ChunkyVec
207    pub(crate) fn new(vec: &'a ChunkyVec<T>) -> Self {
208        let len = vec.len();
209        Self {
210            chunks: vec.chunks.iter(),
211            iter: None,
212            len,
213        }
214    }
215}
216
217impl<'a, T> Iterator for Iter<'a, T> {
218    type Item = &'a T;
219
220    fn next(&mut self) -> Option<Self::Item> {
221        loop {
222            if let Some(ref mut iter) = self.iter {
223                if let front @ Some(_) = iter.next() {
224                    self.len -= 1;
225                    return front;
226                }
227            }
228            self.iter = Some(self.chunks.next()?.iter());
229        }
230    }
231
232    fn size_hint(&self) -> (usize, Option<usize>) {
233        (self.len(), Some(self.len()))
234    }
235}
236
237impl<'a, T> ExactSizeIterator for Iter<'a, T> {
238    fn len(&self) -> usize {
239        self.len
240    }
241}
242
243/// An iterator yielding exclusive references to the elements of a ChunkVec.
244pub struct IterMut<'a, T> {
245    /// Chunks iterator.
246    chunks: slice::IterMut<'a, Chunk<T>>,
247    /// Forward iterator for `next`.
248    iter: Option<slice::IterMut<'a, T>>,
249    /// Number of elements that are to be yielded by the iterator.
250    len: usize,
251}
252
253impl<'a, T> IterMut<'a, T> {
254    /// Creates a new iterator over the bucket vector.
255    pub(crate) fn new(vec: &'a mut ChunkyVec<T>) -> Self {
256        let len = vec.len();
257        Self {
258            chunks: vec.chunks.iter_mut(),
259            iter: None,
260            len,
261        }
262    }
263}
264
265impl<'a, T> Iterator for IterMut<'a, T> {
266    type Item = &'a mut T;
267
268    fn next(&mut self) -> Option<Self::Item> {
269        loop {
270            if let Some(ref mut iter) = self.iter {
271                if let front @ Some(_) = iter.next() {
272                    self.len -= 1;
273                    return front;
274                }
275            }
276            self.iter = Some(self.chunks.next()?.iter_mut());
277        }
278    }
279
280    fn size_hint(&self) -> (usize, Option<usize>) {
281        (self.len(), Some(self.len()))
282    }
283}
284
285impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
286    fn len(&self) -> usize {
287        self.len
288    }
289}
290impl<'a, T> IntoIterator for &'a ChunkyVec<T> {
291    type Item = &'a T;
292    type IntoIter = Iter<'a, T>;
293
294    fn into_iter(self) -> Iter<'a, T> {
295        self.iter()
296    }
297}
298
299impl<'a, T> IntoIterator for &'a mut ChunkyVec<T> {
300    type Item = &'a mut T;
301    type IntoIter = IterMut<'a, T>;
302
303    fn into_iter(self) -> IterMut<'a, T> {
304        self.iter_mut()
305    }
306}
307
308#[cfg(test)]
309mod tests {
310    use super::*;
311
312    #[test]
313    fn iterate_empty() {
314        let v = ChunkyVec::<usize>::default();
315        for i in &v {
316            println!("{:?}", i);
317        }
318    }
319
320    #[test]
321    fn iterate_multiple_chunks() {
322        let mut v = ChunkyVec::<usize>::default();
323        for i in 0..33 {
324            v.push(i);
325        }
326        let mut iter = v.iter();
327        for _ in 0..32 {
328            iter.next();
329        }
330        assert_eq!(iter.next(), Some(&32));
331        assert_eq!(iter.next(), None);
332    }
333
334    #[test]
335    fn index_multiple_chunks() {
336        let mut v = ChunkyVec::<usize>::default();
337        for i in 0..33 {
338            v.push(i);
339        }
340        assert_eq!(v.get(32), Some(&32));
341        assert_eq!(v[32], 32);
342    }
343}