hadris_common/types/
no_alloc.rs1use core::fmt;
2use core::ops::{Index, IndexMut};
3
4#[derive(Debug)]
6pub struct ArrayVec<T, const N: usize> {
7 inner: heapless::Vec<T, N>,
8}
9
10#[derive(Debug, Clone)]
12pub enum ArrayVecError {
13 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 pub const fn new() -> Self {
30 Self {
31 inner: heapless::Vec::new(),
32 }
33 }
34
35 pub fn try_push(&mut self, value: T) -> Result<(), ArrayVecError> {
37 self.inner
38 .push(value)
39 .map_err(|_| ArrayVecError::CapacityOverflow)
40 }
41
42 pub fn push(&mut self, value: T) {
48 self.try_push(value).expect("ArrayVec: ran out of capacity");
49 }
50
51 pub fn len(&self) -> usize {
53 self.inner.len()
54 }
55
56 pub fn is_empty(&self) -> bool {
58 self.inner.is_empty()
59 }
60
61 pub fn as_slice(&self) -> &[T] {
63 self.inner.as_slice()
64 }
65
66 pub fn as_mut_slice(&mut self) -> &mut [T] {
68 self.inner.as_mut_slice()
69 }
70
71 pub fn iter(&self) -> core::slice::Iter<'_, T> {
73 self.inner.iter()
74 }
75
76 pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, T> {
78 self.inner.iter_mut()
79 }
80
81 pub fn reverse(&mut self) {
83 self.inner.reverse();
84 }
85
86 pub fn as_ptr(&self) -> *const T {
88 self.inner.as_ptr()
89 }
90
91 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 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 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#[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 pub const SIZE: usize = N;
156
157 pub const fn new() -> Self {
159 Self {
160 buf: [None; N],
161 head: 0,
162 tail: 0,
163 }
164 }
165
166 pub const fn is_empty(&self) -> bool {
168 self.head == self.tail
169 }
170
171 pub const fn len(&self) -> usize {
173 (self.head + Self::SIZE - self.tail) % Self::SIZE
174 }
175
176 pub const fn is_full(&self) -> bool {
178 (self.head + 1) % N == self.tail
179 }
180
181 pub const fn max_capacity(&self) -> usize {
183 Self::SIZE - 1
184 }
185
186 pub fn try_push(&mut self, value: T) -> Result<(), T> {
188 if self.is_full() {
189 return Err(value);
190 }
191
192 unsafe { self.push_unchecked(value) };
194 Ok(())
195 }
196
197 pub fn push(&mut self, value: T) {
203 if self.try_push(value).is_err() {
204 panic!("ringbuf is full");
205 }
206 }
207
208 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 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}