laminar_core/alloc/
ring_buffer.rs1use std::mem::MaybeUninit;
7
8pub struct RingBuffer<T, const N: usize> {
40 buffer: [MaybeUninit<T>; N],
42 tail: usize,
44 head: usize,
46}
47
48impl<T, const N: usize> RingBuffer<T, N> {
49 #[must_use]
55 pub fn new() -> Self {
56 assert!(N >= 2, "RingBuffer requires N >= 2");
57 Self {
58 buffer: unsafe { MaybeUninit::uninit().assume_init() },
60 tail: 0,
61 head: 0,
62 }
63 }
64
65 #[inline]
88 pub fn push(&mut self, item: T) -> Result<(), T> {
89 let next_head = (self.head + 1) % N;
90 if next_head == self.tail {
91 return Err(item); }
93
94 unsafe {
97 self.buffer[self.head].as_mut_ptr().write(item);
98 }
99 self.head = next_head;
100 Ok(())
101 }
102
103 #[inline]
122 pub fn pop(&mut self) -> Option<T> {
123 if self.head == self.tail {
124 return None; }
126
127 let item = unsafe { self.buffer[self.tail].as_ptr().read() };
130 self.tail = (self.tail + 1) % N;
131 Some(item)
132 }
133
134 #[inline]
142 pub fn peek(&self) -> Option<&T> {
143 if self.head == self.tail {
144 return None;
145 }
146
147 Some(unsafe { &*self.buffer[self.tail].as_ptr() })
149 }
150
151 #[inline]
153 pub fn peek_mut(&mut self) -> Option<&mut T> {
154 if self.head == self.tail {
155 return None;
156 }
157
158 Some(unsafe { &mut *self.buffer[self.tail].as_mut_ptr() })
160 }
161
162 #[inline]
164 #[must_use]
165 pub fn is_empty(&self) -> bool {
166 self.head == self.tail
167 }
168
169 #[inline]
171 #[must_use]
172 pub fn is_full(&self) -> bool {
173 (self.head + 1) % N == self.tail
174 }
175
176 #[inline]
178 #[must_use]
179 pub fn len(&self) -> usize {
180 if self.head >= self.tail {
181 self.head - self.tail
182 } else {
183 N - self.tail + self.head
184 }
185 }
186
187 #[inline]
189 #[must_use]
190 pub const fn capacity(&self) -> usize {
191 N - 1
192 }
193
194 pub fn clear(&mut self) {
198 while self.pop().is_some() {}
199 }
200
201 pub fn iter(&self) -> RingBufferIter<'_, T, N> {
203 RingBufferIter {
204 buffer: self,
205 pos: self.tail,
206 remaining: self.len(),
207 }
208 }
209}
210
211impl<T, const N: usize> Default for RingBuffer<T, N> {
212 fn default() -> Self {
213 Self::new()
214 }
215}
216
217impl<T, const N: usize> Drop for RingBuffer<T, N> {
218 fn drop(&mut self) {
219 self.clear();
221 }
222}
223
224impl<T: std::fmt::Debug, const N: usize> std::fmt::Debug for RingBuffer<T, N> {
225 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
226 f.debug_struct("RingBuffer")
227 .field("len", &self.len())
228 .field("capacity", &self.capacity())
229 .field("items", &self.iter().collect::<Vec<_>>())
230 .finish()
231 }
232}
233
234pub struct RingBufferIter<'a, T, const N: usize> {
236 buffer: &'a RingBuffer<T, N>,
237 pos: usize,
238 remaining: usize,
239}
240
241impl<'a, T, const N: usize> Iterator for RingBufferIter<'a, T, N> {
242 type Item = &'a T;
243
244 fn next(&mut self) -> Option<Self::Item> {
245 if self.remaining == 0 {
246 return None;
247 }
248
249 let item = unsafe { &*self.buffer.buffer[self.pos].as_ptr() };
251 self.pos = (self.pos + 1) % N;
252 self.remaining -= 1;
253 Some(item)
254 }
255
256 fn size_hint(&self) -> (usize, Option<usize>) {
257 (self.remaining, Some(self.remaining))
258 }
259}
260
261impl<T, const N: usize> ExactSizeIterator for RingBufferIter<'_, T, N> {}
262
263impl<'a, T, const N: usize> IntoIterator for &'a RingBuffer<T, N> {
264 type Item = &'a T;
265 type IntoIter = RingBufferIter<'a, T, N>;
266
267 fn into_iter(self) -> Self::IntoIter {
268 self.iter()
269 }
270}
271
272#[allow(unsafe_code)]
274const _: () = ();
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279
280 #[test]
281 fn test_new_buffer() {
282 let buf: RingBuffer<u64, 8> = RingBuffer::new();
283 assert!(buf.is_empty());
284 assert!(!buf.is_full());
285 assert_eq!(buf.len(), 0);
286 assert_eq!(buf.capacity(), 7); }
288
289 #[test]
290 fn test_push_pop() {
291 let mut buf: RingBuffer<i32, 4> = RingBuffer::new();
292
293 buf.push(1).unwrap();
294 buf.push(2).unwrap();
295 buf.push(3).unwrap();
296
297 assert_eq!(buf.len(), 3);
298 assert!(buf.is_full());
299
300 assert_eq!(buf.pop(), Some(1));
301 assert_eq!(buf.pop(), Some(2));
302 assert_eq!(buf.pop(), Some(3));
303 assert_eq!(buf.pop(), None);
304 }
305
306 #[test]
307 fn test_full_buffer() {
308 let mut buf: RingBuffer<i32, 4> = RingBuffer::new();
309
310 buf.push(1).unwrap();
311 buf.push(2).unwrap();
312 buf.push(3).unwrap();
313
314 assert!(buf.push(4).is_err());
316 }
317
318 #[test]
319 fn test_wraparound() {
320 let mut buf: RingBuffer<i32, 4> = RingBuffer::new();
321
322 for round in 0..5 {
324 let base = round * 10;
325 buf.push(base + 1).unwrap();
326 buf.push(base + 2).unwrap();
327 buf.push(base + 3).unwrap();
328
329 assert_eq!(buf.pop(), Some(base + 1));
330 assert_eq!(buf.pop(), Some(base + 2));
331 assert_eq!(buf.pop(), Some(base + 3));
332 }
333 }
334
335 #[test]
336 fn test_peek() {
337 let mut buf: RingBuffer<i32, 4> = RingBuffer::new();
338
339 assert_eq!(buf.peek(), None);
340
341 buf.push(42).unwrap();
342 assert_eq!(buf.peek(), Some(&42));
343 assert_eq!(buf.len(), 1); buf.pop();
346 assert_eq!(buf.peek(), None);
347 }
348
349 #[test]
350 fn test_peek_mut() {
351 let mut buf: RingBuffer<i32, 4> = RingBuffer::new();
352 buf.push(10).unwrap();
353
354 if let Some(val) = buf.peek_mut() {
355 *val = 20;
356 }
357
358 assert_eq!(buf.pop(), Some(20));
359 }
360
361 #[test]
362 fn test_clear() {
363 let mut buf: RingBuffer<i32, 8> = RingBuffer::new();
364 buf.push(1).unwrap();
365 buf.push(2).unwrap();
366 buf.push(3).unwrap();
367
368 buf.clear();
369
370 assert!(buf.is_empty());
371 assert_eq!(buf.len(), 0);
372 }
373
374 #[test]
375 fn test_iter() {
376 let mut buf: RingBuffer<i32, 8> = RingBuffer::new();
377 buf.push(1).unwrap();
378 buf.push(2).unwrap();
379 buf.push(3).unwrap();
380
381 let items: Vec<_> = buf.iter().copied().collect();
382 assert_eq!(items, vec![1, 2, 3]);
383
384 assert_eq!(buf.len(), 3);
386 }
387
388 #[test]
389 fn test_debug() {
390 let mut buf: RingBuffer<i32, 4> = RingBuffer::new();
391 buf.push(1).unwrap();
392 buf.push(2).unwrap();
393
394 let debug_str = format!("{buf:?}");
395 assert!(debug_str.contains("RingBuffer"));
396 assert!(debug_str.contains("len"));
397 }
398
399 #[test]
400 fn test_drop_items() {
401 use std::sync::atomic::{AtomicUsize, Ordering};
402
403 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
404
405 #[derive(Debug)]
406 struct DropCounter;
407 impl Drop for DropCounter {
408 fn drop(&mut self) {
409 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
410 }
411 }
412
413 DROP_COUNT.store(0, Ordering::SeqCst);
414
415 {
416 let mut buf: RingBuffer<DropCounter, 8> = RingBuffer::new();
417 buf.push(DropCounter).unwrap();
418 buf.push(DropCounter).unwrap();
419 buf.push(DropCounter).unwrap();
420 }
421
422 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
424 }
425
426 #[test]
427 #[should_panic(expected = "N >= 2")]
428 fn test_invalid_size() {
429 let _: RingBuffer<u8, 1> = RingBuffer::new();
430 }
431}