1#![cfg_attr(not(test), no_std)]
2#![forbid(unsafe_code)]
3#![doc = include_str!("../README.md")]
4
5pub struct BytearrayRingbuffer<const N: usize> {
17 buffer: [u8; N],
18 head: usize,
20 tail: usize,
22 count: usize,
24}
25
26#[derive(Copy, Clone, Debug)]
32pub struct NotEnoughSpaceError;
33
34impl<const N: usize> BytearrayRingbuffer<N> {
35 pub const fn new() -> Self {
41 assert!(N > 8);
42 assert!(N < (u32::MAX as usize));
43 Self {
44 buffer: [0; N],
45 head: 0,
46 tail: 0,
47 count: 0,
48 }
49 }
50
51 pub const fn free(&self) -> usize {
56 self.bytes_unused().saturating_sub(8)
57 }
58
59 pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
69 self._push(data, false)
70 }
71
72 pub fn push_force(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
81 self._push(data, true)
82 }
83
84 #[inline(always)]
86 pub const fn empty(&self) -> bool {
87 self.count == 0
88 }
89
90 const fn bytes_unused(&self) -> usize {
92 if self.empty() {
93 N
94 } else if self.head > self.tail {
95 N + self.tail - self.head
96 } else {
97 self.tail - self.head
98 }
99 }
100
101 fn _push(&mut self, data: &[u8], force: bool) -> Result<(), NotEnoughSpaceError> {
102 assert!(data.len() <= u32::MAX as usize);
103
104 if data.len() > N - 8 {
106 return Err(NotEnoughSpaceError);
107 }
108
109 if (data.len() + 8) > self.bytes_unused() {
111 if !force {
112 return Err(NotEnoughSpaceError);
113 }
114 while (data.len() + 8) > self.bytes_unused() {
115 self.pop_front();
116 }
117 }
118
119 let addr_a = self.head;
121 let addr_b = add_wrapping::<N>(self.head, 4);
122 let addr_c = add_wrapping::<N>(self.head, 4 + data.len());
123 let len_buffer: [u8; 4] = (data.len() as u32).to_ne_bytes();
124 write_wrapping(&mut self.buffer, addr_a, &len_buffer);
125 write_wrapping(&mut self.buffer, addr_b, data);
126 write_wrapping(&mut self.buffer, addr_c, &len_buffer);
127
128 self.head = add_wrapping::<N>(self.head, 8 + data.len());
129 self.count += 1;
130
131 Ok(())
132 }
133
134 pub fn pop_front(&mut self) -> Option<(&[u8], &[u8])> {
139 if self.empty() {
140 return None;
141 }
142 let mut len_buffer = [0; 4];
143 read_wrapping(&self.buffer, self.tail, &mut len_buffer);
144 let len = u32::from_ne_bytes(len_buffer) as usize;
145
146 let index_data = add_wrapping::<N>(self.tail, 4);
147 let len_a = (N - index_data).min(len);
148 let a = &self.buffer[index_data..index_data + len_a];
149 let b = if len_a == len {
150 &[]
151 } else {
152 &self.buffer[..len - len_a]
153 };
154
155 self.tail = add_wrapping::<N>(self.tail, len + 8);
156 self.count -= 1;
157 Some((a, b))
158 }
159
160 pub fn iter_backwards<'a>(&'a self) -> IterBackwards<'a, N> {
162 IterBackwards {
163 buffer: &self.buffer,
164 head: self.head,
165 count: self.count,
166 }
167 }
168
169 pub fn iter<'a>(&'a self) -> Iter<'a, N> {
171 Iter {
172 buffer: &self.buffer,
173 head: self.head,
174 tail: self.tail,
175 count: self.count,
176 }
177 }
178
179 #[inline(always)]
181 pub const fn count(&self) -> usize {
182 self.count
183 }
184
185 pub fn nth(&self, n: usize) -> Option<(&[u8], &[u8])> {
189 self.iter().nth(n)
190 }
191
192 pub fn nth_reverse(&self, n: usize) -> Option<(&[u8], &[u8])> {
196 self.iter_backwards().nth(n)
197 }
198
199 pub fn nth_contiguous(&mut self, mut n: usize) -> Option<&[u8]> {
207 if self.empty() || n >= self.count {
208 return None;
209 }
210
211 let mut tail = self.tail;
213 let len_data = loop {
214 let mut buf = [0u8; 4];
215 read_wrapping(&self.buffer, tail, &mut buf);
216 let len_data = u32::from_ne_bytes(buf) as usize;
217
218 if n == 0 {
219 break len_data;
220 }
221 n -= 1;
222
223 tail = add_wrapping::<N>(tail, len_data + 8);
224 };
225
226 let index_data = add_wrapping::<N>(tail, 4);
227
228 if index_data + len_data <= N {
230 return Some(&self.buffer[index_data..index_data + len_data]);
231 }
232
233 self.buffer.rotate_left(index_data);
235 self.tail = sub_wrapping::<N>(self.tail, index_data);
236 self.head = sub_wrapping::<N>(self.head, index_data);
237
238 Some(&self.buffer[..len_data])
239 }
240}
241
242pub struct IterBackwards<'a, const N: usize> {
244 buffer: &'a [u8; N],
245 head: usize,
246 count: usize,
247}
248
249impl<'a, const N: usize> Iterator for IterBackwards<'a, N> {
250 type Item = (&'a [u8], &'a [u8]);
251
252 fn next(&mut self) -> Option<Self::Item> {
253 if self.count == 0 {
254 return None;
255 }
256
257 let index_len = sub_wrapping::<N>(self.head, 4);
259 let mut buf = [0u8; 4];
260 read_wrapping(self.buffer, index_len, &mut buf);
261 let len_data = u32::from_ne_bytes(buf) as usize;
262 debug_assert!((len_data + 8) <= N);
263
264 #[cfg(test)]
265 {
266 let index_len = sub_wrapping::<N>(self.head, 8 + len_data);
267 let mut buf = [0u8; 4];
268 read_wrapping(self.buffer, index_len, &mut buf);
269 let len_2 = u32::from_ne_bytes(buf) as usize;
270 assert_eq!(len_data, len_2);
271 }
272
273 let index_data = sub_wrapping::<N>(self.head, 4 + len_data);
275 let first = (N - index_data).min(len_data);
276 let slice_a = &self.buffer[index_data..index_data + first];
277 let slice_b = if first < len_data {
278 &self.buffer[..len_data - first]
279 } else {
280 &[]
281 };
282
283 self.head = sub_wrapping::<N>(self.head, 8 + len_data);
284 self.count -= 1;
285
286 Some((slice_a, slice_b))
287 }
288}
289
290impl<const N: usize> Default for BytearrayRingbuffer<N> {
291 fn default() -> Self {
292 Self::new()
293 }
294}
295
296pub struct Iter<'a, const N: usize> {
298 buffer: &'a [u8; N],
299 head: usize,
300 tail: usize,
301 count: usize,
302}
303
304impl<'a, const N: usize> Iterator for Iter<'a, N> {
305 type Item = (&'a [u8], &'a [u8]);
306
307 fn next(&mut self) -> Option<Self::Item> {
308 if self.count == 0 {
309 return None;
310 }
311
312 let bytes_unused = if self.head > self.tail {
314 N + self.tail - self.head
315 } else {
316 self.tail - self.head
317 };
318 let bytes_occupied = N - bytes_unused;
319 debug_assert!(bytes_occupied >= 8);
320
321 let mut buf = [0u8; 4];
323 read_wrapping(self.buffer, self.tail, &mut buf);
324 let len_data = u32::from_ne_bytes(buf) as usize;
325 debug_assert!((len_data + 8) <= N);
326 debug_assert!((len_data + 8) <= bytes_occupied);
327
328 let index_data = add_wrapping::<N>(self.tail, 4);
330 let first = (N - index_data).min(len_data);
331 let slice_a = &self.buffer[index_data..index_data + first];
332 let slice_b = if first < len_data {
333 &self.buffer[..len_data - first]
334 } else {
335 &[]
336 };
337
338 self.tail = add_wrapping::<N>(self.tail, 8 + len_data);
339 self.count -= 1;
340
341 Some((slice_a, slice_b))
342 }
343}
344
345fn add_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
346 debug_assert!(addr < N);
347 debug_assert!(offset <= N);
348 let s = addr + offset;
349 if s < N { s } else { s - N }
350}
351
352fn sub_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
353 debug_assert!(addr < N);
354 debug_assert!(offset <= N);
355 if addr >= offset {
356 addr - offset
357 } else {
358 N + addr - offset
359 }
360}
361
362fn write_wrapping(buffer: &mut [u8], index: usize, data: &[u8]) {
364 let first = (buffer.len() - index).min(data.len());
365 buffer[index..index + first].copy_from_slice(&data[..first]);
366 if first < data.len() {
367 buffer[..data.len() - first].copy_from_slice(&data[first..]);
368 }
369}
370
371fn read_wrapping(buffer: &[u8], index: usize, data: &mut [u8]) {
373 let first = (buffer.len() - index).min(data.len());
374 data[..first].copy_from_slice(&buffer[index..index + first]);
375 if first < data.len() {
376 let remaining = data.len() - first;
377 data[first..].copy_from_slice(&buffer[..remaining]);
378 }
379}
380
381#[cfg(test)]
382mod tests {
383 use std::collections::VecDeque;
384
385 use super::BytearrayRingbuffer;
386
387 #[test]
388 fn push_some_packets() {
389 const N: usize = 64;
390 for start_offset in 0..N {
391 let mut buf = BytearrayRingbuffer::<N>::new();
392 buf.head = start_offset;
393 buf.tail = start_offset;
394
395 let free = 64 - 8;
396 assert_eq!(buf.free(), free);
397
398 buf.push(b"01234567").unwrap();
399 let free = free - 8 - 8;
400 assert_eq!(buf.free(), free);
401
402 buf.push(b"").unwrap();
403 let free = free - 8;
404 assert_eq!(buf.free(), free);
405
406 buf.push(b"0123").unwrap();
407 let free = free - 4 - 8;
408 assert_eq!(buf.free(), free);
409
410 buf.push(b"0123").unwrap();
411 let free = free - 4 - 8;
412 assert_eq!(buf.free(), free);
413 }
414 }
415
416 #[test]
417 fn push_force() {
418 let mut buf = BytearrayRingbuffer::<16>::new();
419 assert_eq!(buf.bytes_unused(), 16);
420
421 let a = b"012345";
422 let b = b"0123";
423
424 buf.push(a).unwrap();
425 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
426
427 buf.push(b).unwrap_err();
428 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
429
430 buf.push_force(b).unwrap();
431 assert_eq!(buf.bytes_unused(), 16 - b.len() - 8);
432 }
433
434 #[test]
435 fn push_all_data_lengths() {
436 for n in 0..(32 - 8) {
437 let mut buf = BytearrayRingbuffer::<32>::new();
438 let data = (0..n as u8).collect::<Vec<u8>>();
440
441 assert_eq!(buf.free(), 32 - 8);
442 buf.push(&data).unwrap();
443 assert_eq!(buf.free(), (32usize - 16).saturating_sub(n));
444 }
445 }
446
447 #[test]
448 fn push_sum_of_lengths_possible() {
449 let mut buf = BytearrayRingbuffer::<32>::new();
450 assert_eq!(buf.free(), 32 - 8);
452 buf.push(b"01234567").unwrap();
453 assert_eq!(buf.free(), 32 - 8 - 16);
454 buf.push(b"01234567").unwrap();
455 assert_eq!(buf.free(), 0);
456 }
457
458 #[test]
459 fn push_pop() {
460 const N: usize = 64;
461 for start_offset in 0..N {
462 eprintln!("--------------");
463 let mut buf = BytearrayRingbuffer::<N>::new();
464 buf.head = start_offset;
465 buf.tail = start_offset;
466
467 let data = b"01234567";
468 buf.push(data).unwrap();
469
470 let (a, b) = buf.pop_front().unwrap();
471 let mut out = Vec::new();
472 out.extend_from_slice(a);
473 out.extend_from_slice(b);
474
475 dbg!(out.as_slice());
476 assert!(data == out.as_slice());
477
478 assert_eq!(buf.head, buf.tail);
479 assert_eq!(buf.bytes_unused(), N);
480 }
481 }
482
483 #[test]
484 fn push_read_back() {
485 let data = [b"hello world" as &[u8], b"", b"test"];
486
487 const N: usize = 64;
488 for start_offset in 0..N {
489 let mut buf = BytearrayRingbuffer::<N>::new();
490 buf.head = start_offset;
491 buf.tail = start_offset;
492
493 for &d in &data {
494 buf.push(d).unwrap();
495 }
496
497 let mut it = buf.iter();
499 for &d in data.iter() {
500 let (a, b) = it.next().unwrap();
501 let mut ab = Vec::new();
502 ab.extend_from_slice(a);
503 ab.extend_from_slice(b);
504 let ab = ab.as_slice();
505 assert_eq!(d, ab);
506 }
507 assert_eq!(it.next(), None);
508
509 let mut it = buf.iter_backwards();
511 for &d in data.iter().rev() {
512 let (a, b) = it.next().unwrap();
513 let mut ab = Vec::new();
514 ab.extend_from_slice(a);
515 ab.extend_from_slice(b);
516 let ab = ab.as_slice();
517 assert_eq!(d, ab);
518 }
519 assert_eq!(it.next(), None);
520 }
521 }
522
523 #[test]
524 fn push_count() {
525 let mut buf = BytearrayRingbuffer::<64>::new();
526 buf.push(b"1234").unwrap();
527 assert_eq!(buf.count(), 1);
528 buf.push(b"1234").unwrap();
529 assert_eq!(buf.count(), 2);
530 buf.push(b"1234").unwrap();
531 assert_eq!(buf.count(), 3);
532 }
533
534 fn test_with_readback<const N: usize>(words: &[&'static str]) {
535 eprintln!("--------------------------");
536 let mut buf = BytearrayRingbuffer::<N>::new();
537 let mut current_words = VecDeque::new();
538 for &word in words {
539 eprintln!("adding {word:?}");
540 let word = word.to_owned();
541 let current_bytes: usize = current_words.iter().map(|w: &String| w.len() + 8).sum();
542 if current_bytes + 8 + word.len() > N {
543 current_words.pop_front();
544 }
545
546 buf.push_force(word.as_bytes()).unwrap();
547 current_words.push_back(word);
548
549 for (a, b) in buf.iter_backwards().zip(current_words.iter().rev()) {
550 eprintln!("read back {b:?}");
551 let mut st = String::new();
552 st.push_str(core::str::from_utf8(a.0).unwrap());
553 st.push_str(core::str::from_utf8(a.1).unwrap());
554 assert_eq!(st, *b);
555 }
556 }
557 }
558
559 #[test]
560 fn readback_various() {
561 test_with_readback::<32>(&["ab", "123", "hello", "world"]);
562 test_with_readback::<32>(&["", "", "a", "", "", ""]);
563 test_with_readback::<32>(&["", "", "ab", "", "", ""]);
564 test_with_readback::<32>(&["", "", "abc", "", "", ""]);
565 test_with_readback::<32>(&["", "", "abcd", "", "", ""]);
566 test_with_readback::<32>(&["", "", "abcde", "", "", ""]);
567
568 test_with_readback::<24>(&["0", "1", "a", "2", "3", "4"]);
569 test_with_readback::<24>(&["0", "1", "ab", "2", "3", "4"]);
570 test_with_readback::<24>(&["0", "1", "abc", "2", "3", "4"]);
571 test_with_readback::<24>(&["0", "1", "abcd", "2", "3", "4"]);
572 test_with_readback::<24>(&["0", "1", "abcde", "2", "3", "4"]);
573 test_with_readback::<24>(&["0", "1", "abcdef", "2", "3", "4"]);
574 test_with_readback::<24>(&["0", "1", "abcdefg", "2", "3", "4"]);
575 }
576
577 #[test]
578 fn nth_contiguous_out_of_range_returns_none() {
579 let mut buf = BytearrayRingbuffer::<64>::new();
580 buf.push(b"hello").unwrap();
581 assert_eq!(buf.count(), 1);
582
583 assert_eq!(buf.nth_contiguous(1), None);
584 }
585
586 #[test]
587 fn rotate_contiguous() {
588 const N: usize = 48;
589 let data: [&[u8]; _] = [b"012345", b"hello world", b"xyz"];
590
591 for offset in 0..N {
592 let mut buf = BytearrayRingbuffer::<N>::new();
593 buf.head = offset;
594 buf.tail = offset;
595
596 for &d in &data {
597 buf.push(d).unwrap();
598 }
599
600 let read = buf.nth_contiguous(1).unwrap();
601 assert_eq!(data[1], read);
602
603 for (&r, (a, b)) in data.iter().zip(buf.iter()) {
605 let mut out = Vec::new();
606 out.extend_from_slice(a);
607 out.extend_from_slice(b);
608 assert_eq!(out.as_slice(), r);
609 }
610 }
611 }
612}