ahtml/
stillvec.rs

1//! A vector-like region allocator building block that guarantees that
2//! its slots never move, and are available unchanged until
3//! exclusive_clear is called, and hence allows shared references to
4//! existing slots while allowing to push new items at the same
5//! time. Uses internal mutability.
6
7use std::cell::UnsafeCell;
8
9use crate::more_vec::MoreVec;
10
11pub struct StillVec<T>(UnsafeCell<Vec<T>>);
12
13impl<T> StillVec<T> {
14    pub fn with_capacity(cap: usize) -> Self {
15        Self(UnsafeCell::new(Vec::with_capacity(cap)))
16    }
17
18    // This is used to get the new id value for allocations.
19    pub fn len(&self) -> usize {
20        let p = self.0.get();
21        // Safe because StillVec is not Sync, hence the vector cannot
22        // be mutated from under us.
23        unsafe { &*p }.len()
24    }
25
26    pub fn capacity(&self) -> usize {
27        let p = self.0.get();
28        // Safe because StillVec since there is no API for mutating
29        // the capacity.
30        unsafe { &*p }.capacity()
31    }
32
33    pub fn push_within_capacity(&self, value: T) -> Result<(), T> {
34        let p = self.0.get();
35        // Safe because pushing within capacity will not cause
36        // reallocations, hence will not invalidate references
37        // returned by `get`, and StillVec is not Sync.
38        unsafe { &mut *p }.push_within_capacity_(value)
39    }
40
41    pub fn get(&self, i: usize) -> Option<&T> {
42        let p = self.0.get();
43        // Safe because we never give mutable access to slots, and any
44        // stored value remains in the region for the duration of its
45        // lifetime or until `exclusive_clear` is called, and we
46        // pre-allocate all storage via `Vec::with_capacity`, so the
47        // storage will never be moved.
48        unsafe { &*p }.get(i)
49    }
50
51    // This must take `&mut self`, to ensure that no references from
52    // `get` still exist!
53    pub fn exclusive_clear(&mut self) {
54        self.0.get_mut().clear()
55    }
56}