Skip to main content

hadris_common/types/
no_alloc.rs

1use core::fmt;
2use core::ops::{Index, IndexMut};
3
4/// A fixed-capacity vector.
5#[derive(Debug)]
6pub struct ArrayVec<T, const N: usize> {
7    inner: heapless::Vec<T, N>,
8}
9
10/// An error returned when an [`ArrayVec`] has no remaining capacity.
11#[derive(Debug, Clone)]
12pub enum ArrayVecError {
13    /// The vector is full.
14    CapacityOverflow,
15}
16
17impl fmt::Display for ArrayVecError {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            Self::CapacityOverflow => f.write_str("capacity overflow"),
21        }
22    }
23}
24
25impl core::error::Error for ArrayVecError {}
26
27impl<T, const N: usize> ArrayVec<T, N> {
28    /// Creates an empty vector.
29    pub const fn new() -> Self {
30        Self {
31            inner: heapless::Vec::new(),
32        }
33    }
34
35    /// Appends a value, returning an error when the vector is full.
36    pub fn try_push(&mut self, value: T) -> Result<(), ArrayVecError> {
37        self.inner
38            .push(value)
39            .map_err(|_| ArrayVecError::CapacityOverflow)
40    }
41
42    /// Appends a value.
43    ///
44    /// # Panics
45    ///
46    /// Panics when the vector is full.
47    pub fn push(&mut self, value: T) {
48        self.try_push(value).expect("ArrayVec: ran out of capacity");
49    }
50
51    /// Returns the number of stored values.
52    pub fn len(&self) -> usize {
53        self.inner.len()
54    }
55
56    /// Returns whether the vector is empty.
57    pub fn is_empty(&self) -> bool {
58        self.inner.is_empty()
59    }
60
61    /// Returns the stored values as a slice.
62    pub fn as_slice(&self) -> &[T] {
63        self.inner.as_slice()
64    }
65
66    /// Returns the stored values as a mutable slice.
67    pub fn as_mut_slice(&mut self) -> &mut [T] {
68        self.inner.as_mut_slice()
69    }
70
71    /// Returns an iterator over the stored values.
72    pub fn iter(&self) -> core::slice::Iter<'_, T> {
73        self.inner.iter()
74    }
75
76    /// Returns a mutable iterator over the stored values.
77    pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> {
78        self.inner.iter_mut()
79    }
80
81    /// Reverses the stored values.
82    pub fn reverse(&mut self) {
83        self.inner.reverse();
84    }
85
86    /// Returns a pointer to the vector's storage.
87    pub fn as_ptr(&self) -> *const T {
88        self.inner.as_ptr()
89    }
90
91    /// Returns a mutable pointer to the vector's storage.
92    pub fn as_mut_ptr(&mut self) -> *mut T {
93        self.inner.as_mut_ptr()
94    }
95}
96
97impl<T, const N: usize> Default for ArrayVec<T, N> {
98    fn default() -> Self {
99        Self::new()
100    }
101}
102
103impl<T, const N: usize> ArrayVec<T, N>
104where
105    T: Copy + PartialEq,
106{
107    /// Returns whether the vector contains the given value.
108    pub fn contains(&self, value: &T) -> bool {
109        self.inner.contains(value)
110    }
111}
112
113impl<T, const N: usize> ArrayVec<T, N>
114where
115    T: Copy + Ord,
116{
117    /// Sorts the vector without preserving the order of equal values.
118    pub fn sort_unstable(&mut self) {
119        self.inner.sort_unstable();
120    }
121}
122
123impl<T, const N: usize> Index<usize> for ArrayVec<T, N>
124where
125    T: Copy,
126{
127    type Output = T;
128
129    fn index(&self, index: usize) -> &Self::Output {
130        &self.inner[index]
131    }
132}
133
134impl<T, const N: usize> IndexMut<usize> for ArrayVec<T, N>
135where
136    T: Copy,
137{
138    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
139        &mut self.inner[index]
140    }
141}
142
143/// A fixed-capacity FIFO ring buffer.
144///
145/// A buffer with storage size `N` can hold at most `N - 1` values.
146#[derive(Clone, Copy)]
147pub struct RingBuf<T: Copy, const N: usize> {
148    buf: [Option<T>; N],
149    head: usize,
150    tail: usize,
151}
152
153impl<T: Copy, const N: usize> RingBuf<T, N> {
154    /// The number of storage slots in the buffer.
155    pub const SIZE: usize = N;
156
157    /// Creates an empty ring buffer.
158    pub const fn new() -> Self {
159        Self {
160            buf: [None; N],
161            head: 0,
162            tail: 0,
163        }
164    }
165
166    /// Returns whether the buffer is empty.
167    pub const fn is_empty(&self) -> bool {
168        self.head == self.tail
169    }
170
171    /// Returns the number of stored values.
172    pub const fn len(&self) -> usize {
173        (self.head + Self::SIZE - self.tail) % Self::SIZE
174    }
175
176    /// Returns whether the buffer is full.
177    pub const fn is_full(&self) -> bool {
178        (self.head + 1) % N == self.tail
179    }
180
181    /// Returns the maximum number of values the buffer can hold.
182    pub const fn max_capacity(&self) -> usize {
183        Self::SIZE - 1
184    }
185
186    /// Appends a value, returning it when the buffer is full.
187    pub fn try_push(&mut self, value: T) -> Result<(), T> {
188        if self.is_full() {
189            return Err(value);
190        }
191
192        // SAFETY: The buffer was checked for remaining capacity.
193        unsafe { self.push_unchecked(value) };
194        Ok(())
195    }
196
197    /// Appends a value.
198    ///
199    /// # Panics
200    ///
201    /// Panics when the buffer is full.
202    pub fn push(&mut self, value: T) {
203        if self.try_push(value).is_err() {
204            panic!("ringbuf is full");
205        }
206    }
207
208    /// Appends a value without checking whether the buffer is full.
209    ///
210    /// # Safety
211    ///
212    /// The caller must ensure the buffer is not full.
213    pub unsafe fn push_unchecked(&mut self, value: T) {
214        self.buf[self.head] = Some(value);
215        self.head = (self.head + 1) % N;
216    }
217
218    /// Removes and returns the oldest value.
219    pub fn pop(&mut self) -> Option<T> {
220        if self.is_empty() {
221            return None;
222        }
223
224        let value = self.buf[self.tail].take();
225        self.tail = (self.tail + 1) % N;
226        value
227    }
228}
229
230impl<T: Copy, const N: usize> Default for RingBuf<T, N> {
231    fn default() -> Self {
232        Self::new()
233    }
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239    use core::sync::atomic::{AtomicUsize, Ordering};
240
241    static_assertions::assert_impl_all!(RingBuf<u8, 4>: Clone, Copy);
242
243    #[test]
244    fn array_vec_preserves_values_and_capacity_errors() {
245        let mut values = ArrayVec::<u8, 2>::new();
246        values.push(2);
247        values.push(1);
248        assert!(matches!(
249            values.try_push(3),
250            Err(ArrayVecError::CapacityOverflow)
251        ));
252        values.sort_unstable();
253        assert_eq!(values.as_slice(), &[1, 2]);
254    }
255
256    #[test]
257    fn array_vec_drops_stored_values() {
258        static DROPS: AtomicUsize = AtomicUsize::new(0);
259
260        struct DropCounter;
261
262        impl Drop for DropCounter {
263            fn drop(&mut self) {
264                DROPS.fetch_add(1, Ordering::Relaxed);
265            }
266        }
267
268        DROPS.store(0, Ordering::Relaxed);
269        {
270            let mut values = ArrayVec::<DropCounter, 2>::new();
271            values.push(DropCounter);
272            values.push(DropCounter);
273        }
274        assert_eq!(DROPS.load(Ordering::Relaxed), 2);
275    }
276
277    #[test]
278    #[should_panic]
279    fn array_vec_rejects_uninitialized_index() {
280        let mut values = ArrayVec::<u8, 2>::new();
281        values.push(1);
282        let _ = values[1];
283    }
284
285    #[test]
286    fn ring_buffer_wraps_and_preserves_fifo_order() {
287        let mut values = RingBuf::<u8, 4>::new();
288        values.push(1);
289        values.push(2);
290        values.push(3);
291        assert!(values.is_full());
292        assert_eq!(values.try_push(4), Err(4));
293        assert_eq!(values.pop(), Some(1));
294        values.push(4);
295        assert_eq!(values.pop(), Some(2));
296        assert_eq!(values.pop(), Some(3));
297        assert_eq!(values.pop(), Some(4));
298        assert_eq!(values.pop(), None);
299    }
300}