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}