stack_vector/lib.rs
1//! A vector-like object allocated on the stack
2//!
3//! # Example
4//! ```
5//! use stack_vector::StackVec;
6//!
7//! let mut sv = StackVec::<i32, 10>::new();
8//!
9//! sv.push(1);
10//!
11//! if false {
12//! sv.push(2);
13//! }
14//!
15//! sv.push(3);
16//!
17//! if true {
18//! sv.push(4);
19//! }
20//!
21//! assert_eq!(sv.as_slice(), &[1, 3, 4]);
22//! ```
23
24use std::iter::Peekable;
25use std::mem::{self, ManuallyDrop, MaybeUninit};
26use std::ops::{Deref, DerefMut};
27use std::ptr;
28
29/// A [Vec]-like wrapper for an array.
30///
31/// This struct allows to push and pop to an array,
32/// treating it like a vector, but with no heap allocations.
33pub struct StackVec<T, const CAP: usize> {
34 inner: [MaybeUninit<T>; CAP],
35 length: usize,
36}
37
38impl<T, const CAP: usize> StackVec<T, CAP> {
39
40 #[inline]
41 pub const fn new() -> Self {
42 Self {
43 inner: [const { MaybeUninit::uninit() }; CAP ],
44 length: 0
45 }
46 }
47
48 pub const fn from_array(arr: [T; CAP]) -> Self {
49 /* We can't transmute the array due to rust's limitations.
50 * We need to wrap the array into a ManuallyDrop, to avoid
51 * T's Drop to be called twice. */
52 let arr = ManuallyDrop::new(arr);
53 let inner = unsafe {
54 /* SAFETY: T and ManualyDrop<T> have the same size and alignment */
55 mem::transmute_copy(&arr)
56 };
57 Self { inner, length: CAP }
58 }
59
60 /// Pushes an element in the StackVec without checking bounds.
61 ///
62 /// # Safety
63 /// Caller must ensure that the StackVec has room for the element
64 #[inline]
65 pub unsafe fn push_unchecked(&mut self, val: T) {
66 unsafe {
67 self.inner.get_unchecked_mut(self.length).write(val);
68 }
69 self.length += 1;
70 }
71
72 /// Pushes an element into this StackVec, panicking if there is no space left.
73 ///
74 /// # Panics
75 /// - If the StackVec is full
76 #[inline]
77 pub fn push(&mut self, val: T) {
78 if self.try_push(val).is_err() {
79 panic!("Attemp to push beyond the capacity of the array")
80 }
81 }
82
83 /// Attempts to push an element into this StackVec.
84 ///
85 /// # Errors
86 /// - If the StackVec if full, returns back the element
87 /// inside an Err variant.
88 pub fn try_push(&mut self, val: T) -> Result<(),T> {
89 if self.length >= CAP {
90 Err(val)
91 } else {
92 /* SAFETY: We've just checked that the buffer can
93 * hold the element */
94 unsafe { self.push_unchecked(val) };
95 Ok(())
96 }
97 }
98
99 pub fn extend_from_iter<I>(&mut self, it: I)
100 where
101 I: IntoIterator<Item = T>
102 {
103 for elem in it.into_iter() {
104 self.push(elem)
105 }
106 }
107
108 /// Attempts to push all elements from the iterator into this StackVec.
109 ///
110 /// # Errors
111 /// If the iterator yields more elements that we can push, returns the
112 /// iterator (turned into a [Peekable]) as an Err variant
113 pub fn try_extend_from_iter<I>(&mut self, it: I) -> Result<(), Peekable<<I as IntoIterator>::IntoIter>>
114 where
115 I: IntoIterator<Item = T>
116 {
117 let mut it = it.into_iter().peekable();
118 while it.peek().is_some() {
119 if self.length >= CAP {
120 return Err(it)
121 }
122 unsafe {
123 /* SAFETY:
124 * 1) In the while condition, we've checked that the
125 * iterator has a next element.
126 *
127 * 2) In the condition above, we check that there's room
128 * for this element
129 * */
130 let elem = it.next().unwrap_unchecked();
131 self.push_unchecked(elem)
132 }
133 }
134 Ok(())
135 }
136
137 /// Removes the ith element of the StackVec, and returns it.
138 ///
139 /// # Safety
140 /// - i must be within bounds [0, [Self::len])
141 pub unsafe fn remove_unchecked(&mut self, i: usize) -> T {
142 /* SAFETY: self.inner[i] is initialized, thus reading
143 * from this pointer is safe */
144 let ret = unsafe { self.inner[i].assume_init_read() };
145
146 let ptr = self.inner.as_mut_ptr();
147
148 unsafe {
149 /* SAFETY: Elements [i + 1, len) are within bounds
150 * for the buffer, and can be copied over */
151 ptr::copy(
152 ptr.add(i + 1),
153 ptr.add(i),
154 self.length - i - 1
155 );
156 }
157 self.length -= 1;
158 ret
159 }
160
161 /// Removes the last element of the StackVec, and returns it.
162 /// If empty, returns None
163 pub fn pop(&mut self) -> Option<T> {
164 self.remove(self.length)
165 }
166
167 /// Removes the ith element of the StackVec, and returns it.
168 /// If the index is out of bounds, returns None
169 pub fn remove(&mut self, i: usize) -> Option<T> {
170 if i <= self.length {
171 unsafe { Some(self.remove_unchecked(i)) }
172 } else {
173 None
174 }
175 }
176
177 /// Returns an slice of T's from this StackVec, with all
178 /// the currently allocated elements.
179 pub const fn as_slice(&self) -> &[T] {
180 let (slice, _) = self.inner.split_at(self.length);
181 /* SAFETY: The items in range 0..self.len will allways be
182 * initialized, so it's safe to reinterpret the slice of
183 * MaybeUninit to an slice of T */
184 unsafe {
185 mem::transmute::<&[MaybeUninit<T>], &[T]>(slice)
186 }
187 }
188
189 /// Returns a mutable slice of T's from this StackVec, with
190 /// all the currently allocated elements.
191 pub const fn as_slice_mut(&mut self) -> &mut [T] {
192 let (slice, _) = self.inner.split_at_mut(self.length);
193 /* SAFETY: Same as as_slice */
194 unsafe {
195 mem::transmute::<&mut [MaybeUninit<T>], &mut [T]>(slice)
196 }
197 }
198
199 /// Returns the capacity of this StackVec.
200 /// This is just a convenience function, since the
201 /// capacity is a const generic argument.
202 #[inline(always)]
203 pub const fn capacity(&self) -> usize { CAP }
204
205 /// Returns the remaining capacity of this StackVec.
206 /// This is, how many more elements can we store in it.
207 #[inline(always)]
208 pub const fn remaining_capacity(&self) -> usize { CAP - self.length }
209
210 /// Returns the length of this StackVec, this is, the
211 /// number of elements "pushed" into it.
212 #[inline(always)]
213 pub const fn len(&self) -> usize { self.length }
214
215 /// Returns true if the length is 0
216 #[inline(always)]
217 pub const fn is_empty(&self) -> bool { self.length == 0 }
218
219 /// Returns true if no more elements can be pushed into this StackVec
220 #[inline(always)]
221 pub const fn is_full(&self) -> bool { self.length == CAP }
222}
223
224impl<T, const CAP: usize> Deref for StackVec<T, CAP> {
225 type Target = [T];
226
227 fn deref(&self) -> &Self::Target {
228 self.as_slice()
229 }
230}
231
232impl<T, const CAP: usize> DerefMut for StackVec<T, CAP> {
233 fn deref_mut(&mut self) -> &mut [T] {
234 self.as_slice_mut()
235 }
236}
237
238impl<T, const CAP: usize> Default for StackVec<T, CAP> {
239 fn default() -> Self {
240 Self::new()
241 }
242}
243
244impl<T, const CAP: usize> From<[T; CAP]> for StackVec<T, CAP> {
245 #[inline(always)]
246 fn from(value: [T; CAP]) -> Self {
247 StackVec::from_array(value)
248 }
249}
250
251impl<T, const CAP: usize> Drop for StackVec<T, CAP> {
252 fn drop(&mut self) {
253 if mem::needs_drop::<T>() {
254 for elem in &mut self.inner[0..self.length] {
255 unsafe {
256 /* SAFETY: Elements [0, len) are initialized, and
257 * must be dropped */
258 elem.assume_init_drop();
259 }
260 }
261 }
262 }
263}