pinned_vec/
lib.rs

1//! # PinnedVec
2//! Vec-like structure whose elements never move.
3//!
4//! Normal Vec holds all its content in one contigious region, and moves when it needs to expand.
5//! PinnedVec holds several smaller sub-vector, each of which never moves.
6//! The first sub-vector is of capacity 1, the second 2, the third 4, the nth 2^(n-1).
7//!
8//! ## Example Usage
9//! ```rust
10//! use pinned_vec::PinnedVec;
11//! use std::pin::Pin;
12//! let mut v = PinnedVec::new();
13//! v.push(5);
14//! {
15//! 	let r: Pin<&i32> = v.get(0).unwrap();
16//! 	assert_eq!(*r, 5);
17//! }
18//! {
19//! 	let r: Pin<&mut i32> = v.get_mut(0).unwrap();
20//! 	assert_eq!(*r, 5);
21//! }
22//! assert_eq!(v.len(), 1);
23//! v.pop();
24//! v.push(7);
25//! v.push(8);
26//! v.replace(0, 6);
27//! assert_eq!(*v.get(0).unwrap(), 6);
28//! assert_eq!(*v.get(1).unwrap(), 8);
29//! ```
30
31use std::pin::Pin;
32
33// A block never grows, so it never moves, so Pinning is safe.
34struct Block<T> {
35	vec: Vec<T>,
36}
37
38impl<T> Block<T> {
39	fn new(capacity: usize) -> Self {
40		Self {
41			vec: Vec::with_capacity(capacity),
42		}
43	}
44	fn get(&self, index: usize) -> Option<Pin<&T>> {
45		// SAFETY: Since the sub-vector's allocation never move, all its contents are pinned.
46		self.vec
47			.get(index)
48			.map(|p| unsafe { Pin::new_unchecked(p) })
49	}
50	fn get_mut(&mut self, index: usize) -> Option<Pin<&mut T>> {
51		// SAFETY: Since the sub-vector's allocation never move, all its contents are pinned.
52		self.vec
53			.get_mut(index)
54			.map(|p| unsafe { Pin::new_unchecked(p) })
55	}
56	fn push(&mut self, item: T) {
57		assert!(self.vec.len() < self.vec.capacity());
58		self.vec.push(item);
59	}
60	fn pop(&mut self) {
61		self.vec.truncate(self.vec.len() - 1);
62	}
63	fn replace(&mut self, index: usize, item: T) {
64		*self.vec.get_mut(index).unwrap() = item;
65	}
66}
67
68/// Vec-like structure whose elements never move.
69pub struct PinnedVec<T> {
70	blocks: Vec<Block<T>>,
71	len: usize,
72}
73
74impl<T> PinnedVec<T> {
75	fn outter_idx(index: usize) -> usize {
76		(usize::BITS - (index + 1).leading_zeros() - 1) as usize
77	}
78	fn split_idx(index: usize) -> (usize, usize) {
79		let m = index + 1;
80		let outter_idx = (usize::BITS - m.leading_zeros() - 1) as usize;
81		let inner_idx: usize = m & (!(1 << outter_idx));
82		(outter_idx, inner_idx)
83	}
84	/// Create a new, empty PinnedVec.
85	/// This method does not allocate.
86	pub fn new() -> Self {
87		Self {
88			blocks: Vec::new(),
89			len: 0,
90		}
91	}
92	/// Get the length of the PinnedVec (the number of elements inside).
93	pub fn len(&self) -> usize {
94		self.len
95	}
96	/// Get the current capacity of the PinnedVec
97	/// Pushing within capacity means no extra allocation.
98	/// Pushing over capacity will cause allocation, increasing capacity.
99	pub fn capacity(&self) -> usize {
100		let outter_idx = Self::outter_idx(self.len);
101		(1 << outter_idx) - 1
102	}
103	/// Get a pinned reference to the element at the specified index, if it exists.
104	pub fn get(&self, index: usize) -> Option<Pin<&T>> {
105		if index >= self.len {
106			None
107		} else {
108			let (outter, inner) = Self::split_idx(index);
109			let block = self.blocks.get(outter).unwrap();
110			let item = block.get(inner).unwrap();
111			Some(item)
112		}
113	}
114	/// Get a pinned mutable reference to the element at the specified index, if it exists.
115	pub fn get_mut(&mut self, index: usize) -> Option<Pin<&mut T>> {
116		if index >= self.len {
117			None
118		} else {
119			let (outter, inner) = Self::split_idx(index);
120			let block = self.blocks.get_mut(outter).unwrap();
121			let item = block.get_mut(inner).unwrap();
122			Some(item)
123		}
124	}
125	/// Push an element to the end of the PinnedVec.
126	/// Might cause the PinnedVec to allocate a new sub-vector.
127	pub fn push(&mut self, item: T) {
128		let outter_idx = Self::outter_idx(self.len);
129		if self.blocks.len() <= outter_idx {
130			let new_block = Block::new(1 << outter_idx);
131			self.blocks.push(new_block);
132		}
133		self.blocks[outter_idx].push(item);
134		self.len += 1;
135	}
136	/// Remove the last element in the PinnedVec.
137	/// The element is not returned because that would violate Pin invariant.
138	/// ### Panics
139	/// Panics if the vec is empty.
140	pub fn pop(&mut self) {
141		assert!(self.len > 0);
142		self.len -= 1;
143		let outter_idx = Self::outter_idx(self.len);
144		self.blocks[outter_idx].pop();
145	}
146	/// Replace the element at the specified index with another one.
147	/// The element is not returned because that would violate Pin invariant.
148	/// ### Panics
149	/// Panics if index is not in the vec (i.e. len >= index).
150	pub fn replace(&mut self, index: usize, item: T) {
151		let (outter, inner) = Self::split_idx(index);
152		self.blocks[outter].replace(inner, item);
153	}
154}
155
156#[cfg(test)]
157mod tests {
158	use std::fmt::Debug;
159
160	use super::*;
161
162	struct Both<T> {
163		normal: Vec<T>,
164		pinned: PinnedVec<T>,
165	}
166
167	impl<T> Both<T> {
168		fn new() -> Self {
169			Self {
170				normal: Vec::new(),
171				pinned: PinnedVec::new(),
172			}
173		}
174	}
175
176	impl<T: PartialEq + Debug> Both<T> {
177		fn check(&self) {
178			let len = self.normal.len();
179			assert_eq!(len, self.pinned.len());
180			for i in 0..len {
181				assert_eq!(self.normal.get(i), self.pinned.get(i).as_deref());
182			}
183			assert_eq!(self.pinned.get(len), None);
184		}
185	}
186	impl<T: Clone> Both<T> {
187		fn push(&mut self, item: T) {
188			self.normal.push(item.clone());
189			self.pinned.push(item);
190		}
191		fn pop(&mut self) {
192			self.normal.pop();
193			self.pinned.pop();
194		}
195		fn replace(&mut self, index: usize, item: T) {
196			self.normal[index] = item.clone();
197			self.pinned.replace(index, item);
198		}
199	}
200
201	#[test]
202	fn one() {
203		let mut b: Both<i32> = Both::new();
204		for i in 0..200 {
205			for j in 0..i {
206				b.push(j);
207			}
208			b.check();
209			for _ in 0..(i - 2) {
210				b.pop();
211			}
212			b.check();
213			for j in (0..(i / 5)).map(|x| x * 3) {
214				b.replace(j as usize, -j);
215			}
216			b.check();
217		}
218	}
219
220	#[test]
221	fn two() {
222		let mut b: Both<i32> = Both::new();
223		b.push(1);
224		b.push(2);
225		b.push(3);
226		b.push(4);
227		b.check();
228		b.push(5);
229		b.push(6);
230		b.push(7);
231		b.check();
232		b.pop();
233		b.check();
234		b.pop();
235		b.check();
236		b.pop();
237		b.check();
238		b.pop();
239		b.check();
240		b.push(5);
241		b.check()
242	}
243}