const_vec/
lib.rs

1//! This library provides a `Vec`-like data structure called `ConstVec` where
2//! elements can be pushed to the array in an immutable way as long as the
3//! capacity of the vector is large enough).
4//!
5//! # Example
6//!
7//! ```rust
8//! use const_vec::ConstVec;
9//!
10//! // Create a new empty `ConstVec` with a capacity of 10 items.
11//! // Note that it is NOT mutable.
12//! let vec = ConstVec::new(10);
13//!
14//! // Add a new element in `vec`, without mutating it.
15//! vec.push(42);
16//! ```
17use std::{
18	alloc,
19	alloc::Layout,
20	borrow::{Borrow, BorrowMut},
21	cell::Cell,
22	fmt,
23	mem::{self, ManuallyDrop},
24	ops::{Deref, DerefMut},
25	ptr,
26	ptr::NonNull,
27};
28
29/// Fixed capacity array with immutable `push` method.
30pub struct ConstVec<T> {
31	ptr: NonNull<T>,
32	capacity: usize,
33	len: Cell<usize>,
34}
35
36impl<T> ConstVec<T> {
37	/// Creates a new array with the given fixed capacity.
38	pub fn new(capacity: usize) -> ConstVec<T> {
39		let ptr = if capacity == 0 {
40			NonNull::dangling()
41		} else {
42			let layout = Layout::array::<T>(capacity).unwrap();
43			let ptr = unsafe { alloc::alloc(layout) };
44			match NonNull::new(ptr as *mut T) {
45				Some(ptr) => ptr,
46				None => alloc::handle_alloc_error(layout),
47			}
48		};
49
50		ConstVec {
51			ptr,
52			capacity,
53			len: Cell::new(0),
54		}
55	}
56
57	/// Creates a `ConstVec<T>` directly from a pointer, a capacity, and a
58	/// length.
59	///
60	/// # Safety
61	///
62	/// This is highly unsafe, due to the number of invariants that aren't
63	/// checked:
64	///
65	/// * `T` needs to have the same alignment as what `ptr` was allocated with.
66	///   (`T` having a less strict alignment is not sufficient, the alignment really
67	///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
68	///   allocated and deallocated with the same layout.)
69	/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
70	///   to be the same size as the pointer was allocated with. (Because similar to
71	///   alignment, [`dealloc`] must be called with the same layout `size`.)
72	/// * `len` needs to be less than or equal to `capacity`.
73	/// * The first `len` values must be properly initialized values of type `T`.
74	/// * `capacity` needs to be the capacity that the pointer was allocated with.
75	/// * The allocated size in bytes must be no larger than `isize::MAX`.
76	///   See the safety documentation of `pointer::offset`.
77	///
78	/// These requirements are always upheld by any `ptr` that has been allocated
79	/// via `Vec<T>`. Other allocation sources are allowed if the invariants are
80	/// upheld.
81	///
82	/// The ownership of `ptr` is effectively transferred to the
83	/// `ConstVec<T>` which may then deallocate, reallocate or change the
84	/// contents of memory pointed to by the pointer at will. Ensure
85	/// that nothing else uses the pointer after calling this
86	/// function.
87	///
88	/// [`dealloc`]: alloc::dealloc
89	#[inline]
90	pub unsafe fn from_raw_parts(ptr: *mut T, len: usize, capacity: usize) -> Self {
91		Self {
92			ptr: NonNull::new_unchecked(ptr),
93			len: Cell::new(len),
94			capacity,
95		}
96	}
97
98	/// Decomposes a `ConstVec<T>` into its raw components.
99	///
100	/// Returns the raw pointer to the underlying data, the length of
101	/// the vector (in elements), and the allocated capacity of the
102	/// data (in elements). These are the same arguments in the same
103	/// order as the arguments to [`from_raw_parts`].
104	///
105	/// After calling this function, the caller is responsible for the
106	/// memory previously managed by the `Vec`. The only way to do
107	/// this is to convert the raw pointer, length, and capacity back
108	/// into a `ConstVec` with the [`from_raw_parts`] function, allowing
109	/// the destructor to perform the cleanup.
110	///
111	/// [`from_raw_parts`]: ConstVec::from_raw_parts
112	///
113	/// # Examples
114	///
115	/// ```
116	/// # use const_vec::ConstVec;
117	/// let v: ConstVec<i32> = ConstVec::new(3);
118	/// v.push(-1);
119	/// v.push(0);
120	/// v.push(1);
121	///
122	/// let (ptr, len, cap) = v.into_raw_parts();
123	///
124	/// let rebuilt = unsafe {
125	///     // We can now make changes to the components, such as
126	///     // transmuting the raw pointer to a compatible type.
127	///     let ptr = ptr as *mut u32;
128	///
129	///     ConstVec::from_raw_parts(ptr, len, cap)
130	/// };
131	///
132	/// assert_eq!(rebuilt, [4294967295, 0, 1]);
133	/// ```
134	pub fn into_raw_parts(self) -> (*mut T, usize, usize) {
135		let mut me = ManuallyDrop::new(self);
136		(me.as_mut_ptr(), me.len(), me.capacity())
137	}
138
139	#[inline]
140	pub fn capacity(&self) -> usize {
141		self.capacity
142	}
143
144	#[inline]
145	pub fn len(&self) -> usize {
146		self.len.get()
147	}
148
149	#[inline]
150	pub fn is_empty(&self) -> bool {
151		self.len() == 0
152	}
153
154	#[inline]
155	pub fn as_ptr(&self) -> *const T {
156		self.ptr.as_ptr()
157	}
158
159	#[inline]
160	pub fn as_mut_ptr(&mut self) -> *mut T {
161		self.ptr.as_ptr()
162	}
163
164	#[inline]
165	pub fn as_slice(&self) -> &[T] {
166		unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
167	}
168
169	#[inline]
170	pub fn as_mut_slice(&mut self) -> &mut [T] {
171		unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
172	}
173
174	#[inline]
175	pub fn push(&self, value: T) {
176		if self.len() < self.capacity() {
177			unsafe {
178				let len = self.len.get();
179				let end = self.ptr.as_ptr().add(len);
180				std::ptr::write(end, value);
181				self.len.set(len + 1);
182			}
183		} else {
184			panic!("not enough capacity")
185		}
186	}
187
188	/// Removes the last element from a vector and returns it, or [`None`] if it
189	/// is empty.
190	///
191	/// # Examples
192	///
193	/// ```
194	/// # use const_vec::ConstVec;
195	/// let mut vec = ConstVec::new(3);
196	/// vec.push(1);
197	/// vec.push(2);
198	/// vec.push(3);
199	///
200	/// assert_eq!(vec.pop(), Some(3));
201	/// assert_eq!(vec, [1, 2]);
202	/// ```
203	#[inline]
204	pub fn pop(&mut self) -> Option<T> {
205		if self.len.get() == 0 {
206			None
207		} else {
208			unsafe {
209				self.len.set(self.len.get() - 1);
210				Some(ptr::read(self.as_ptr().add(self.len())))
211			}
212		}
213	}
214
215	/// Moves all the elements of `other` into `self`, leaving `other` empty.
216	///
217	/// # Panics
218	///
219	/// Panics if the current length and `other` length exceed the capacity.
220	///
221	/// # Examples
222	///
223	/// ```
224	/// # use const_vec::ConstVec;
225	/// let vec = ConstVec::new(6);
226	/// vec.push(1);
227	/// vec.push(2);
228	/// vec.push(3);
229	///
230	/// let mut vec2 = vec![4, 5, 6];
231	/// vec.append(&mut vec2);
232	///
233	/// assert_eq!(vec, [1, 2, 3, 4, 5, 6]);
234	/// assert_eq!(vec2, []);
235	/// ```
236	pub fn append(&self, other: &mut Vec<T>) {
237		if self.len() + other.len() <= self.capacity() {
238			unsafe {
239				self.append_elements(other.as_slice() as _);
240				other.set_len(0)
241			}
242		} else {
243			panic!("not enough capacity")
244		}
245	}
246
247	/// Appends elements to `self` from other buffer.
248	///
249	/// The sum of the current length and length of `other` must not exceed
250	/// the capacity.
251	#[cfg(not(no_global_oom_handling))]
252	#[inline]
253	unsafe fn append_elements(&self, other: *const [T]) {
254		let count = unsafe { (*other).len() };
255		let len = self.len();
256		unsafe { ptr::copy_nonoverlapping(other as *const T, self.ptr.as_ptr().add(len), count) };
257		self.len.set(len + count);
258	}
259
260	/// Clears the vector, removing all values.
261	///
262	/// Note that this method has no effect on the allocated capacity
263	/// of the vector.
264	///
265	/// # Examples
266	///
267	/// ```
268	/// # use const_vec::ConstVec;
269	/// let mut vec = ConstVec::new(3);
270	/// vec.push(1);
271	/// vec.push(2);
272	/// vec.push(3);
273	///
274	/// vec.clear();
275	///
276	/// assert!(vec.is_empty());
277	/// ```
278	#[inline]
279	pub fn clear(&mut self) {
280		let elems: *mut [T] = self.as_mut_slice();
281
282		// SAFETY:
283		// - `elems` comes directly from `as_mut_slice` and is therefore valid.
284		// - Setting `self.len` before calling `drop_in_place` means that,
285		//   if an element's `Drop` impl panics, the vector's `Drop` impl will
286		//   do nothing (leaking the rest of the elements) instead of dropping
287		//   some twice.
288		unsafe {
289			self.len.set(0);
290			ptr::drop_in_place(elems);
291		}
292	}
293}
294
295impl<T> IntoIterator for ConstVec<T> {
296	type IntoIter = IntoIter<T>;
297	type Item = T;
298
299	fn into_iter(self) -> Self::IntoIter {
300		let iter = IntoIter {
301			ptr: self.ptr,
302			capacity: self.capacity,
303			start: self.ptr.as_ptr(),
304			end: unsafe { self.ptr.as_ptr().add(self.len()) },
305		};
306
307		mem::forget(self);
308		iter
309	}
310}
311
312impl<'a, T> IntoIterator for &'a ConstVec<T> {
313	type IntoIter = std::slice::Iter<'a, T>;
314	type Item = &'a T;
315
316	fn into_iter(self) -> Self::IntoIter {
317		self.iter()
318	}
319}
320
321impl<T: Clone> Clone for ConstVec<T> {
322	fn clone(&self) -> Self {
323		let result = Self::new(self.capacity);
324
325		for item in self {
326			result.push(item.clone())
327		}
328
329		result
330	}
331}
332
333impl<T> AsRef<[T]> for ConstVec<T> {
334	fn as_ref(&self) -> &[T] {
335		self.as_slice()
336	}
337}
338
339impl<T> AsMut<[T]> for ConstVec<T> {
340	fn as_mut(&mut self) -> &mut [T] {
341		self.as_mut_slice()
342	}
343}
344
345impl<T> Borrow<[T]> for ConstVec<T> {
346	fn borrow(&self) -> &[T] {
347		self.as_slice()
348	}
349}
350
351impl<T> BorrowMut<[T]> for ConstVec<T> {
352	fn borrow_mut(&mut self) -> &mut [T] {
353		self.as_mut_slice()
354	}
355}
356
357impl<T> Deref for ConstVec<T> {
358	type Target = [T];
359
360	#[inline]
361	fn deref(&self) -> &[T] {
362		self.as_slice()
363	}
364}
365
366impl<T> DerefMut for ConstVec<T> {
367	#[inline]
368	fn deref_mut(&mut self) -> &mut [T] {
369		self.as_mut_slice()
370	}
371}
372
373impl<T> Drop for ConstVec<T> {
374	fn drop(&mut self) {
375		if self.capacity != 0 {
376			unsafe {
377				// use drop for [T]
378				// use a raw slice to refer to the elements of the vector as weakest necessary type;
379				// could avoid questions of validity in certain cases
380				ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len()));
381
382				let layout = Layout::array::<T>(self.capacity).unwrap();
383				alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout);
384			}
385		}
386	}
387}
388
389impl<T: fmt::Debug> fmt::Debug for ConstVec<T> {
390	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391		fmt::Debug::fmt(&**self, f)
392	}
393}
394
395impl<T: PartialEq<U>, U> PartialEq<[U]> for ConstVec<T> {
396	#[inline]
397	fn eq(&self, other: &[U]) -> bool {
398		*self.as_slice() == *other
399	}
400}
401
402impl<'a, T: PartialEq<U>, U> PartialEq<&'a [U]> for ConstVec<T> {
403	#[inline]
404	fn eq(&self, other: &&'a [U]) -> bool {
405		*self.as_slice() == **other
406	}
407}
408
409impl<T: PartialEq<U>, U, const N: usize> PartialEq<[U; N]> for ConstVec<T> {
410	#[inline]
411	fn eq(&self, other: &[U; N]) -> bool {
412		*self.as_slice() == *other
413	}
414}
415
416impl<'a, T: PartialEq<U>, U, const N: usize> PartialEq<&'a [U; N]> for ConstVec<T> {
417	#[inline]
418	fn eq(&self, other: &&'a [U; N]) -> bool {
419		*self.as_slice() == **other
420	}
421}
422
423impl<T: PartialEq<U>, U> PartialEq<ConstVec<U>> for ConstVec<T> {
424	#[inline]
425	fn eq(&self, other: &ConstVec<U>) -> bool {
426		*self.as_slice() == *other.as_slice()
427	}
428}
429
430impl<T> From<Vec<T>> for ConstVec<T> {
431	fn from(value: Vec<T>) -> Self {
432		let mut value = ManuallyDrop::new(value);
433		let ptr = value.as_mut_ptr();
434		let len = value.len();
435		let capacity = value.capacity();
436		unsafe { Self::from_raw_parts(ptr, len, capacity) }
437	}
438}
439
440impl<T> From<ConstVec<T>> for Vec<T> {
441	fn from(value: ConstVec<T>) -> Self {
442		let (ptr, len, capacity) = value.into_raw_parts();
443		unsafe { Vec::from_raw_parts(ptr, len, capacity) }
444	}
445}
446
447pub struct IntoIter<T> {
448	ptr: NonNull<T>,
449	capacity: usize,
450	start: *mut T,
451	end: *mut T,
452}
453
454impl<T> IntoIter<T> {
455	#[inline]
456	pub fn len(&self) -> usize {
457		(self.end as usize - self.start as usize) / mem::size_of::<T>()
458	}
459
460	#[inline]
461	pub fn is_empty(&self) -> bool {
462		self.start == self.end
463	}
464
465	#[inline]
466	pub fn as_ptr(&self) -> *const T {
467		self.start
468	}
469
470	#[inline]
471	pub fn as_mut_ptr(&mut self) -> *mut T {
472		self.start
473	}
474
475	#[inline]
476	pub fn as_slice(&self) -> &[T] {
477		unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
478	}
479
480	#[inline]
481	pub fn as_mut_slice(&mut self) -> &mut [T] {
482		unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len()) }
483	}
484}
485
486impl<T> Iterator for IntoIter<T> {
487	type Item = T;
488
489	fn size_hint(&self) -> (usize, Option<usize>) {
490		let len = self.len();
491		(len, Some(len))
492	}
493
494	fn next(&mut self) -> Option<Self::Item> {
495		if self.start == self.end {
496			None
497		} else {
498			unsafe {
499				let result = ptr::read(self.start);
500				self.start = self.start.offset(1);
501				Some(result)
502			}
503		}
504	}
505}
506
507impl<T> ExactSizeIterator for IntoIter<T> {}
508
509impl<T> DoubleEndedIterator for IntoIter<T> {
510	fn next_back(&mut self) -> Option<Self::Item> {
511		if self.start == self.end {
512			None
513		} else {
514			unsafe {
515				self.end = self.end.offset(-1);
516				Some(ptr::read(self.end))
517			}
518		}
519	}
520}
521
522impl<T> Drop for IntoIter<T> {
523	fn drop(&mut self) {
524		if self.capacity != 0 {
525			unsafe {
526				// use drop for [T]
527				// use a raw slice to refer to the elements of the vector as weakest necessary type;
528				// could avoid questions of validity in certain cases
529				ptr::drop_in_place(ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), self.len()));
530
531				let layout = Layout::array::<T>(self.capacity).unwrap();
532				alloc::dealloc(self.ptr.as_ptr() as *mut u8, layout);
533			}
534		}
535	}
536}