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}