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(Debug, PartialEq)]
34pub struct Packet<'a> {
35 pub a: &'a [u8],
37 pub b: &'a [u8],
39}
40
41impl<'a> Packet<'a> {
42 pub fn len(&self) -> usize {
44 self.a.len() + self.b.len()
45 }
46
47 pub fn is_empty(&self) -> bool {
49 self.a.is_empty() && self.b.is_empty()
50 }
51
52 pub fn copy_into(&self, buffer: &mut [u8]) {
58 assert_eq!(
59 buffer.len(),
60 self.len(),
61 "buffer length must equal packet length"
62 );
63 buffer[..self.a.len()].copy_from_slice(self.a);
64 buffer[self.a.len()..].copy_from_slice(self.b);
65 }
66
67 pub fn copy_part_into(&self, range: impl core::ops::RangeBounds<usize>, buffer: &mut [u8]) {
78 use core::ops::Bound;
79
80 let total = self.len();
81
82 let start = match range.start_bound() {
83 Bound::Included(&s) => s,
84 Bound::Excluded(&s) => s + 1,
85 Bound::Unbounded => 0,
86 };
87 let end = match range.end_bound() {
88 Bound::Included(&e) => e + 1,
89 Bound::Excluded(&e) => e,
90 Bound::Unbounded => total,
91 };
92
93 assert!(start <= end, "range start must not be greater than end");
94 assert_eq!(
95 buffer.len(),
96 end - start,
97 "buffer length must equal range length"
98 );
99 assert!(end <= total, "range out of bounds");
100 let a_len = self.a.len();
101 let mut buf_pos = 0;
102
103 if start < a_len {
105 let a_end = end.min(a_len);
106 let chunk = &self.a[start..a_end];
107 buffer[buf_pos..buf_pos + chunk.len()].copy_from_slice(chunk);
108 buf_pos += chunk.len();
109 }
110
111 if end > a_len {
113 let b_start = start.saturating_sub(a_len);
114 let b_end = end.saturating_sub(a_len);
115 let chunk = &self.b[b_start..b_end];
116 buffer[buf_pos..buf_pos + chunk.len()].copy_from_slice(chunk);
117 }
118 }
119
120 pub fn extend_into<E: Extend<u8>>(&self, target: &mut E) {
126 target.extend(self.a.iter().copied());
127 target.extend(self.b.iter().copied());
128 }
129}
130
131#[derive(Copy, Clone, Debug)]
137pub struct NotEnoughSpaceError;
138
139pub struct MultipartPush<'a, const N: usize> {
149 buf: &'a mut BytearrayRingbuffer<N>,
150 start: usize,
152 len: usize,
154 force: bool,
156 cancelled: bool,
158}
159
160impl<'a, const N: usize> MultipartPush<'a, N> {
161 pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
177 if data.is_empty() {
178 return Ok(());
179 }
180
181 if self.len + data.len() > N - 8 {
183 return Err(NotEnoughSpaceError);
184 }
185
186 let needed = data.len() + 4;
188
189 if self.force {
190 while self.buf.bytes_unused() < needed && !self.buf.empty() {
191 self.buf.pop_front();
192 }
193 if self.buf.bytes_unused() < needed {
194 return Err(NotEnoughSpaceError);
195 }
196 } else if self.buf.bytes_unused() < needed {
197 return Err(NotEnoughSpaceError);
198 }
199
200 write_wrapping(&mut self.buf.buffer, self.buf.head, data);
201 self.buf.head = add_wrapping::<N>(self.buf.head, data.len());
202 self.len += data.len();
203
204 Ok(())
205 }
206
207 pub fn cancel(mut self) {
212 self.cancelled = true;
213 self.buf.head = self.start;
214 }
216}
217
218impl<'a, const N: usize> Drop for MultipartPush<'a, N> {
219 fn drop(&mut self) {
220 if self.cancelled {
221 return;
222 }
223 let len_bytes: [u8; 4] = (self.len as u32).to_ne_bytes();
224 write_wrapping(&mut self.buf.buffer, self.start, &len_bytes);
226 write_wrapping(&mut self.buf.buffer, self.buf.head, &len_bytes);
228 self.buf.head = add_wrapping::<N>(self.buf.head, 4);
229 self.buf.count += 1;
230 }
231}
232
233impl<const N: usize> BytearrayRingbuffer<N> {
234 pub const fn new() -> Self {
240 assert!(N > 8);
241 assert!(N < (u32::MAX as usize));
242 Self {
243 buffer: [0; N],
244 head: 0,
245 tail: 0,
246 count: 0,
247 }
248 }
249
250 pub fn clear(&mut self) {
253 self.head = 0;
254 self.tail = 0;
255 self.count = 0;
256 }
257
258 pub const fn free(&self) -> usize {
263 self.bytes_unused().saturating_sub(8)
264 }
265
266 pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
276 self._push(data, false)
277 }
278
279 pub fn push_force(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
288 self._push(data, true)
289 }
290
291 pub fn push_multipart(&mut self) -> Result<MultipartPush<'_, N>, NotEnoughSpaceError> {
302 if self.bytes_unused() < 8 {
304 return Err(NotEnoughSpaceError);
305 }
306 let start = self.head;
307 self.head = add_wrapping::<N>(self.head, 4);
308 Ok(MultipartPush {
309 buf: self,
310 start,
311 len: 0,
312 force: false,
313 cancelled: false,
314 })
315 }
316
317 pub fn push_multipart_force(&mut self) -> MultipartPush<'_, N> {
325 while self.bytes_unused() < 8 && !self.empty() {
327 self.pop_front();
328 }
329 let start = self.head;
330 self.head = add_wrapping::<N>(self.head, 4);
331 MultipartPush {
332 buf: self,
333 start,
334 len: 0,
335 force: true,
336 cancelled: false,
337 }
338 }
339
340 #[inline(always)]
342 pub const fn empty(&self) -> bool {
343 self.count == 0
344 }
345
346 const fn bytes_unused(&self) -> usize {
348 if self.empty() {
349 N
350 } else if self.head > self.tail {
351 N + self.tail - self.head
352 } else {
353 self.tail - self.head
354 }
355 }
356
357 fn _push(&mut self, data: &[u8], force: bool) -> Result<(), NotEnoughSpaceError> {
358 assert!(data.len() <= u32::MAX as usize);
359
360 if data.len() > N - 8 {
362 return Err(NotEnoughSpaceError);
363 }
364
365 if (data.len() + 8) > self.bytes_unused() {
367 if !force {
368 return Err(NotEnoughSpaceError);
369 }
370 while (data.len() + 8) > self.bytes_unused() {
371 self.pop_front();
372 }
373 }
374
375 let addr_a = self.head;
377 let addr_b = add_wrapping::<N>(self.head, 4);
378 let addr_c = add_wrapping::<N>(self.head, 4 + data.len());
379 let len_buffer: [u8; 4] = (data.len() as u32).to_ne_bytes();
380 write_wrapping(&mut self.buffer, addr_a, &len_buffer);
381 write_wrapping(&mut self.buffer, addr_b, data);
382 write_wrapping(&mut self.buffer, addr_c, &len_buffer);
383
384 self.head = add_wrapping::<N>(self.head, 8 + data.len());
385 self.count += 1;
386
387 Ok(())
388 }
389
390 pub fn pop_front(&mut self) -> Option<Packet<'_>> {
395 if self.empty() {
396 return None;
397 }
398 let mut len_buffer = [0; 4];
399 read_wrapping(&self.buffer, self.tail, &mut len_buffer);
400 let len = u32::from_ne_bytes(len_buffer) as usize;
401
402 let index_data = add_wrapping::<N>(self.tail, 4);
403 let len_a = (N - index_data).min(len);
404 let a = &self.buffer[index_data..index_data + len_a];
405 let b = if len_a == len {
406 &[]
407 } else {
408 &self.buffer[..len - len_a]
409 };
410
411 self.tail = add_wrapping::<N>(self.tail, len + 8);
412 self.count -= 1;
413 Some(Packet { a, b })
414 }
415
416 pub fn iter_backwards<'a>(&'a self) -> IterBackwards<'a, N> {
418 IterBackwards {
419 buffer: &self.buffer,
420 head: self.head,
421 count: self.count,
422 }
423 }
424
425 pub fn iter<'a>(&'a self) -> Iter<'a, N> {
427 Iter {
428 buffer: &self.buffer,
429 head: self.head,
430 tail: self.tail,
431 count: self.count,
432 }
433 }
434
435 #[inline(always)]
437 pub const fn count(&self) -> usize {
438 self.count
439 }
440
441 pub fn nth(&self, n: usize) -> Option<Packet<'_>> {
445 self.iter().nth(n)
446 }
447
448 pub fn nth_reverse(&self, n: usize) -> Option<Packet<'_>> {
452 self.iter_backwards().nth(n)
453 }
454
455 pub fn nth_contiguous(&mut self, mut n: usize) -> Option<&[u8]> {
463 if self.empty() || n >= self.count {
464 return None;
465 }
466
467 let mut tail = self.tail;
469 let len_data = loop {
470 let mut buf = [0u8; 4];
471 read_wrapping(&self.buffer, tail, &mut buf);
472 let len_data = u32::from_ne_bytes(buf) as usize;
473
474 if n == 0 {
475 break len_data;
476 }
477 n -= 1;
478
479 tail = add_wrapping::<N>(tail, len_data + 8);
480 };
481
482 let index_data = add_wrapping::<N>(tail, 4);
483
484 if index_data + len_data <= N {
486 return Some(&self.buffer[index_data..index_data + len_data]);
487 }
488
489 self.buffer.rotate_left(index_data);
491 self.tail = sub_wrapping::<N>(self.tail, index_data);
492 self.head = sub_wrapping::<N>(self.head, index_data);
493
494 Some(&self.buffer[..len_data])
495 }
496}
497
498pub struct IterBackwards<'a, const N: usize> {
500 buffer: &'a [u8; N],
501 head: usize,
502 count: usize,
503}
504
505impl<'a, const N: usize> Iterator for IterBackwards<'a, N> {
506 type Item = Packet<'a>;
507
508 fn next(&mut self) -> Option<Self::Item> {
509 if self.count == 0 {
510 return None;
511 }
512
513 let index_len = sub_wrapping::<N>(self.head, 4);
515 let mut buf = [0u8; 4];
516 read_wrapping(self.buffer, index_len, &mut buf);
517 let len_data = u32::from_ne_bytes(buf) as usize;
518 debug_assert!((len_data + 8) <= N);
519
520 #[cfg(test)]
521 {
522 let index_len = sub_wrapping::<N>(self.head, 8 + len_data);
523 let mut buf = [0u8; 4];
524 read_wrapping(self.buffer, index_len, &mut buf);
525 let len_2 = u32::from_ne_bytes(buf) as usize;
526 assert_eq!(len_data, len_2);
527 }
528
529 let index_data = sub_wrapping::<N>(self.head, 4 + len_data);
531 let first = (N - index_data).min(len_data);
532 let slice_a = &self.buffer[index_data..index_data + first];
533 let slice_b = if first < len_data {
534 &self.buffer[..len_data - first]
535 } else {
536 &[]
537 };
538
539 self.head = sub_wrapping::<N>(self.head, 8 + len_data);
540 self.count -= 1;
541
542 Some(Packet {
543 a: slice_a,
544 b: slice_b,
545 })
546 }
547}
548
549impl<const N: usize> Default for BytearrayRingbuffer<N> {
550 fn default() -> Self {
551 Self::new()
552 }
553}
554
555pub struct Iter<'a, const N: usize> {
557 buffer: &'a [u8; N],
558 head: usize,
559 tail: usize,
560 count: usize,
561}
562
563impl<'a, const N: usize> Iterator for Iter<'a, N> {
564 type Item = Packet<'a>;
565
566 fn next(&mut self) -> Option<Self::Item> {
567 if self.count == 0 {
568 return None;
569 }
570
571 let bytes_unused = if self.head > self.tail {
573 N + self.tail - self.head
574 } else {
575 self.tail - self.head
576 };
577 let bytes_occupied = N - bytes_unused;
578 debug_assert!(bytes_occupied >= 8);
579
580 let mut buf = [0u8; 4];
582 read_wrapping(self.buffer, self.tail, &mut buf);
583 let len_data = u32::from_ne_bytes(buf) as usize;
584 debug_assert!((len_data + 8) <= N);
585 debug_assert!((len_data + 8) <= bytes_occupied);
586
587 let index_data = add_wrapping::<N>(self.tail, 4);
589 let first = (N - index_data).min(len_data);
590 let slice_a = &self.buffer[index_data..index_data + first];
591 let slice_b = if first < len_data {
592 &self.buffer[..len_data - first]
593 } else {
594 &[]
595 };
596
597 self.tail = add_wrapping::<N>(self.tail, 8 + len_data);
598 self.count -= 1;
599
600 Some(Packet {
601 a: slice_a,
602 b: slice_b,
603 })
604 }
605}
606
607fn add_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
608 debug_assert!(addr < N);
609 debug_assert!(offset <= N);
610 let s = addr + offset;
611 if s < N { s } else { s - N }
612}
613
614fn sub_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
615 debug_assert!(addr < N);
616 debug_assert!(offset <= N);
617 if addr >= offset {
618 addr - offset
619 } else {
620 N + addr - offset
621 }
622}
623
624fn write_wrapping(buffer: &mut [u8], index: usize, data: &[u8]) {
626 let first = (buffer.len() - index).min(data.len());
627 buffer[index..index + first].copy_from_slice(&data[..first]);
628 if first < data.len() {
629 buffer[..data.len() - first].copy_from_slice(&data[first..]);
630 }
631}
632
633fn read_wrapping(buffer: &[u8], index: usize, data: &mut [u8]) {
635 let first = (buffer.len() - index).min(data.len());
636 data[..first].copy_from_slice(&buffer[index..index + first]);
637 if first < data.len() {
638 let remaining = data.len() - first;
639 data[first..].copy_from_slice(&buffer[..remaining]);
640 }
641}
642
643#[cfg(test)]
644mod tests {
645 use std::collections::VecDeque;
646
647 use super::BytearrayRingbuffer;
648
649 #[test]
650 fn push_some_packets() {
651 const N: usize = 64;
652 for start_offset in 0..N {
653 let mut buf = BytearrayRingbuffer::<N>::new();
654 buf.head = start_offset;
655 buf.tail = start_offset;
656
657 let free = 64 - 8;
658 assert_eq!(buf.free(), free);
659
660 buf.push(b"01234567").unwrap();
661 let free = free - 8 - 8;
662 assert_eq!(buf.free(), free);
663
664 buf.push(b"").unwrap();
665 let free = free - 8;
666 assert_eq!(buf.free(), free);
667
668 buf.push(b"0123").unwrap();
669 let free = free - 4 - 8;
670 assert_eq!(buf.free(), free);
671
672 buf.push(b"0123").unwrap();
673 let free = free - 4 - 8;
674 assert_eq!(buf.free(), free);
675 }
676 }
677
678 #[test]
679 fn push_force() {
680 let mut buf = BytearrayRingbuffer::<16>::new();
681 assert_eq!(buf.bytes_unused(), 16);
682
683 let a = b"012345";
684 let b = b"0123";
685
686 buf.push(a).unwrap();
687 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
688
689 buf.push(b).unwrap_err();
690 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
691
692 buf.push_force(b).unwrap();
693 assert_eq!(buf.bytes_unused(), 16 - b.len() - 8);
694 }
695
696 #[test]
697 fn push_all_data_lengths() {
698 for n in 0..(32 - 8) {
699 let mut buf = BytearrayRingbuffer::<32>::new();
700 let data = (0..n as u8).collect::<Vec<u8>>();
702
703 assert_eq!(buf.free(), 32 - 8);
704 buf.push(&data).unwrap();
705 assert_eq!(buf.free(), (32usize - 16).saturating_sub(n));
706 }
707 }
708
709 #[test]
710 fn push_sum_of_lengths_possible() {
711 let mut buf = BytearrayRingbuffer::<32>::new();
712 assert_eq!(buf.free(), 32 - 8);
714 buf.push(b"01234567").unwrap();
715 assert_eq!(buf.free(), 32 - 8 - 16);
716 buf.push(b"01234567").unwrap();
717 assert_eq!(buf.free(), 0);
718 }
719
720 #[test]
721 fn push_pop() {
722 const N: usize = 64;
723 for start_offset in 0..N {
724 eprintln!("--------------");
725 let mut buf = BytearrayRingbuffer::<N>::new();
726 buf.head = start_offset;
727 buf.tail = start_offset;
728
729 let data = b"01234567";
730 buf.push(data).unwrap();
731
732 let p = buf.pop_front().unwrap();
733 let mut out = Vec::new();
734 out.extend_from_slice(p.a);
735 out.extend_from_slice(p.b);
736
737 dbg!(out.as_slice());
738 assert!(data == out.as_slice());
739
740 assert_eq!(buf.head, buf.tail);
741 assert_eq!(buf.bytes_unused(), N);
742 }
743 }
744
745 #[test]
746 fn push_read_back() {
747 let data = [b"hello world" as &[u8], b"", b"test"];
748
749 const N: usize = 64;
750 for start_offset in 0..N {
751 let mut buf = BytearrayRingbuffer::<N>::new();
752 buf.head = start_offset;
753 buf.tail = start_offset;
754
755 for &d in &data {
756 buf.push(d).unwrap();
757 }
758
759 let mut it = buf.iter();
761 for &d in data.iter() {
762 let p = it.next().unwrap();
763 let mut ab = Vec::new();
764 ab.extend_from_slice(p.a);
765 ab.extend_from_slice(p.b);
766 let ab = ab.as_slice();
767 assert_eq!(d, ab);
768 }
769 assert_eq!(it.next(), None);
770
771 let mut it = buf.iter_backwards();
773 for &d in data.iter().rev() {
774 let p = it.next().unwrap();
775 let mut ab = Vec::new();
776 ab.extend_from_slice(p.a);
777 ab.extend_from_slice(p.b);
778 let ab = ab.as_slice();
779 assert_eq!(d, ab);
780 }
781 assert_eq!(it.next(), None);
782 }
783 }
784
785 #[test]
786 fn push_count() {
787 let mut buf = BytearrayRingbuffer::<64>::new();
788 buf.push(b"1234").unwrap();
789 assert_eq!(buf.count(), 1);
790 buf.push(b"1234").unwrap();
791 assert_eq!(buf.count(), 2);
792 buf.push(b"1234").unwrap();
793 assert_eq!(buf.count(), 3);
794 }
795
796 fn test_with_readback<const N: usize>(words: &[&'static str]) {
797 eprintln!("--------------------------");
798 let mut buf = BytearrayRingbuffer::<N>::new();
799 let mut current_words = VecDeque::new();
800 for &word in words {
801 eprintln!("adding {word:?}");
802 let word = word.to_owned();
803 let current_bytes: usize = current_words.iter().map(|w: &String| w.len() + 8).sum();
804 if current_bytes + 8 + word.len() > N {
805 current_words.pop_front();
806 }
807
808 buf.push_force(word.as_bytes()).unwrap();
809 current_words.push_back(word);
810
811 for (p, word) in buf.iter_backwards().zip(current_words.iter().rev()) {
812 eprintln!("read back {word:?}");
813 let mut st = String::new();
814 st.push_str(core::str::from_utf8(p.a).unwrap());
815 st.push_str(core::str::from_utf8(p.b).unwrap());
816 assert_eq!(st, *word);
817 }
818 }
819 }
820
821 #[test]
822 fn readback_various() {
823 test_with_readback::<32>(&["ab", "123", "hello", "world"]);
824 test_with_readback::<32>(&["", "", "a", "", "", ""]);
825 test_with_readback::<32>(&["", "", "ab", "", "", ""]);
826 test_with_readback::<32>(&["", "", "abc", "", "", ""]);
827 test_with_readback::<32>(&["", "", "abcd", "", "", ""]);
828 test_with_readback::<32>(&["", "", "abcde", "", "", ""]);
829
830 test_with_readback::<24>(&["0", "1", "a", "2", "3", "4"]);
831 test_with_readback::<24>(&["0", "1", "ab", "2", "3", "4"]);
832 test_with_readback::<24>(&["0", "1", "abc", "2", "3", "4"]);
833 test_with_readback::<24>(&["0", "1", "abcd", "2", "3", "4"]);
834 test_with_readback::<24>(&["0", "1", "abcde", "2", "3", "4"]);
835 test_with_readback::<24>(&["0", "1", "abcdef", "2", "3", "4"]);
836 test_with_readback::<24>(&["0", "1", "abcdefg", "2", "3", "4"]);
837 }
838
839 #[test]
840 fn nth_contiguous_out_of_range_returns_none() {
841 let mut buf = BytearrayRingbuffer::<64>::new();
842 buf.push(b"hello").unwrap();
843 assert_eq!(buf.count(), 1);
844
845 assert_eq!(buf.nth_contiguous(1), None);
846 }
847
848 #[test]
849 fn rotate_contiguous() {
850 const N: usize = 48;
851 let data: [&[u8]; _] = [b"012345", b"hello world", b"xyz"];
852
853 for offset in 0..N {
854 let mut buf = BytearrayRingbuffer::<N>::new();
855 buf.head = offset;
856 buf.tail = offset;
857
858 for &d in &data {
859 buf.push(d).unwrap();
860 }
861
862 let read = buf.nth_contiguous(1).unwrap();
863 assert_eq!(data[1], read);
864
865 for (&r, p) in data.iter().zip(buf.iter()) {
867 let mut out = Vec::new();
868 out.extend_from_slice(p.a);
869 out.extend_from_slice(p.b);
870 assert_eq!(out.as_slice(), r);
871 }
872 }
873 }
874
875 fn collect(a: &[u8], b: &[u8]) -> Vec<u8> {
878 let mut v = Vec::new();
879 v.extend_from_slice(a);
880 v.extend_from_slice(b);
881 v
882 }
883
884 #[test]
885 fn multipart_normal_fits() {
886 const N: usize = 64;
887 for offset in 0..N {
888 let mut buf = BytearrayRingbuffer::<N>::new();
889 buf.head = offset;
890 buf.tail = offset;
891
892 let mut mp = buf.push_multipart().unwrap();
893 mp.push(b"hello").unwrap();
894 mp.push(b" ").unwrap();
895 mp.push(b"world").unwrap();
896 drop(mp);
897
898 assert_eq!(buf.count(), 1);
899 let p = buf.pop_front().unwrap();
900 assert_eq!(collect(p.a, p.b), b"hello world");
901 assert_eq!(buf.count(), 0);
902 }
903 }
904
905 #[test]
906 fn multipart_empty_packet() {
907 let mut buf = BytearrayRingbuffer::<64>::new();
908 let mp = buf.push_multipart().unwrap();
909 drop(mp); assert_eq!(buf.count(), 1);
911 let p = buf.pop_front().unwrap();
912 assert_eq!(collect(p.a, p.b), b"");
913 }
914
915 #[test]
916 fn multipart_normal_overflow_returns_err() {
917 let mut buf = BytearrayRingbuffer::<24>::new();
922 buf.push(b"").unwrap(); let mut mp = buf.push_multipart().unwrap();
925 mp.push(b"abcd").unwrap(); let err = mp.push(b"12345"); assert!(err.is_err());
928
929 drop(mp);
931 assert_eq!(buf.count(), 2);
932 let p = buf.nth(1).unwrap();
934 assert_eq!(collect(p.a, p.b), b"abcd");
935 }
936
937 #[test]
938 fn multipart_cancel_normal_mode() {
939 let mut buf = BytearrayRingbuffer::<64>::new();
940 let original_unused = buf.bytes_unused();
941 let original_count = buf.count();
942
943 let mut mp = buf.push_multipart().unwrap();
944 mp.push(b"data that will be discarded").unwrap();
945 mp.cancel();
946
947 assert_eq!(buf.count(), original_count);
948 assert_eq!(buf.bytes_unused(), original_unused);
949 }
950
951 #[test]
952 fn multipart_normal_no_room_for_start() {
953 let mut buf = BytearrayRingbuffer::<24>::new();
955 buf.push(&[0u8; 16]).unwrap(); assert_eq!(buf.bytes_unused(), 0);
957 assert!(buf.push_multipart().is_err());
958 }
959
960 #[test]
961 fn multipart_force_drops_old_packets() {
962 let mut buf = BytearrayRingbuffer::<24>::new();
967 buf.push(b"AA").unwrap(); buf.push(b"BB").unwrap(); assert_eq!(buf.count(), 2);
970
971 let mut mp = buf.push_multipart_force();
972 mp.push(b"hello world").unwrap(); drop(mp);
974
975 assert_eq!(buf.count(), 1);
976 let p = buf.pop_front().unwrap();
977 assert_eq!(collect(p.a, p.b), b"hello world");
978 }
979
980 #[test]
981 fn multipart_force_cancel_drops_are_permanent() {
982 let mut buf = BytearrayRingbuffer::<24>::new();
984 buf.push(b"AA").unwrap();
985 buf.push(b"BB").unwrap();
986 let count_before = buf.count(); let mut mp = buf.push_multipart_force();
989 mp.push(b"hello world").unwrap(); mp.cancel(); assert!(buf.count() < count_before);
994 assert_eq!(buf.count(), 0);
995 }
996
997 #[test]
998 fn multipart_push_after_multipart() {
999 let mut buf = BytearrayRingbuffer::<64>::new();
1000 {
1001 let mut mp = buf.push_multipart().unwrap();
1002 mp.push(b"first").unwrap();
1003 }
1004 buf.push(b"second").unwrap();
1005
1006 assert_eq!(buf.count(), 2);
1007 let p = buf.nth(0).unwrap();
1008 assert_eq!(collect(p.a, p.b), b"first");
1009 let p = buf.nth(1).unwrap();
1010 assert_eq!(collect(p.a, p.b), b"second");
1011 }
1012
1013 #[test]
1014 fn multipart_force_max_payload() {
1015 const N: usize = 32;
1017 let mut buf = BytearrayRingbuffer::<N>::new();
1018 buf.push(b"old").unwrap(); let payload: Vec<u8> = (0..((N - 8) as u8)).collect();
1021 let mut mp = buf.push_multipart_force();
1022 mp.push(&payload).unwrap();
1023 drop(mp);
1024
1025 assert_eq!(buf.count(), 1);
1026 let p = buf.pop_front().unwrap();
1027 assert_eq!(collect(p.a, p.b), payload);
1028 }
1029
1030 #[test]
1031 fn multipart_wraparound_all_offsets() {
1032 const N: usize = 48;
1033 for offset in 0..N {
1034 let mut buf = BytearrayRingbuffer::<N>::new();
1035 buf.head = offset;
1036 buf.tail = offset;
1037
1038 buf.push(b"prefix").unwrap();
1040
1041 let mut mp = buf.push_multipart().unwrap();
1043 mp.push(b"foo").unwrap();
1044 mp.push(b"bar").unwrap();
1045 drop(mp);
1046
1047 buf.push(b"suffix").unwrap();
1049
1050 assert_eq!(buf.count(), 3);
1051 let p = buf.nth(0).unwrap();
1052 assert_eq!(collect(p.a, p.b), b"prefix");
1053 let p = buf.nth(1).unwrap();
1054 assert_eq!(collect(p.a, p.b), b"foobar");
1055 let p = buf.nth(2).unwrap();
1056 assert_eq!(collect(p.a, p.b), b"suffix");
1057 }
1058 }
1059
1060 #[test]
1063 fn pop_front_empty_returns_none() {
1064 let mut buf = BytearrayRingbuffer::<32>::new();
1065 assert_eq!(buf.pop_front(), None);
1066 }
1067
1068 #[test]
1069 fn empty_and_count_lifecycle() {
1070 let mut buf = BytearrayRingbuffer::<32>::new();
1071
1072 assert!(buf.empty());
1074 assert_eq!(buf.count(), 0);
1075
1076 buf.push(b"a").unwrap();
1077 assert!(!buf.empty());
1078 assert_eq!(buf.count(), 1);
1079
1080 buf.push(b"b").unwrap();
1081 assert!(!buf.empty());
1082 assert_eq!(buf.count(), 2);
1083
1084 buf.pop_front().unwrap();
1085 assert!(!buf.empty());
1086 assert_eq!(buf.count(), 1);
1087
1088 buf.pop_front().unwrap();
1089 assert!(buf.empty());
1090 assert_eq!(buf.count(), 0);
1091
1092 assert_eq!(buf.pop_front(), None);
1094 }
1095
1096 #[test]
1097 fn default_creates_empty_buffer() {
1098 let buf = BytearrayRingbuffer::<32>::default();
1099 assert!(buf.empty());
1100 assert_eq!(buf.count(), 0);
1101 assert_eq!(buf.free(), 32 - 8);
1102 }
1103
1104 #[test]
1107 fn push_oversized_returns_error() {
1108 let mut buf = BytearrayRingbuffer::<16>::new();
1109 let oversized = [0u8; 9];
1111 assert!(buf.push(&oversized).is_err());
1112 assert!(buf.empty());
1114 }
1115
1116 #[test]
1117 fn push_force_oversized_returns_error() {
1118 let mut buf = BytearrayRingbuffer::<16>::new();
1119 let oversized = [0u8; 9];
1121 assert!(buf.push_force(&oversized).is_err());
1122 assert!(buf.empty());
1123 }
1124
1125 #[test]
1128 fn iter_empty_buffer() {
1129 let buf = BytearrayRingbuffer::<32>::new();
1130 assert_eq!(buf.iter().next(), None);
1131 }
1132
1133 #[test]
1134 fn iter_backwards_empty_buffer() {
1135 let buf = BytearrayRingbuffer::<32>::new();
1136 assert_eq!(buf.iter_backwards().next(), None);
1137 }
1138
1139 #[test]
1142 fn nth_empty_returns_none() {
1143 let buf = BytearrayRingbuffer::<32>::new();
1144 assert_eq!(buf.nth(0), None);
1145 }
1146
1147 #[test]
1148 fn nth_out_of_bounds_returns_none() {
1149 let buf = {
1150 let mut b = BytearrayRingbuffer::<64>::new();
1151 b.push(b"x").unwrap();
1152 b.push(b"y").unwrap();
1153 b
1154 };
1155 assert_eq!(buf.nth(2), None);
1156 assert_eq!(buf.nth(100), None);
1157 }
1158
1159 #[test]
1160 fn nth_reverse_basic() {
1161 let mut buf = BytearrayRingbuffer::<64>::new();
1162 buf.push(b"oldest").unwrap();
1163 buf.push(b"middle").unwrap();
1164 buf.push(b"newest").unwrap();
1165
1166 let p = buf.nth_reverse(0).unwrap();
1167 assert_eq!(collect(p.a, p.b), b"newest");
1168 let p = buf.nth_reverse(1).unwrap();
1169 assert_eq!(collect(p.a, p.b), b"middle");
1170 let p = buf.nth_reverse(2).unwrap();
1171 assert_eq!(collect(p.a, p.b), b"oldest");
1172 }
1173
1174 #[test]
1175 fn nth_reverse_empty_returns_none() {
1176 let buf = BytearrayRingbuffer::<32>::new();
1177 assert_eq!(buf.nth_reverse(0), None);
1178 }
1179
1180 #[test]
1181 fn nth_reverse_out_of_bounds_returns_none() {
1182 let buf = {
1183 let mut b = BytearrayRingbuffer::<64>::new();
1184 b.push(b"only").unwrap();
1185 b
1186 };
1187 assert_eq!(buf.nth_reverse(1), None);
1188 assert_eq!(buf.nth_reverse(99), None);
1189 }
1190
1191 #[test]
1194 fn nth_contiguous_empty_returns_none() {
1195 let mut buf = BytearrayRingbuffer::<32>::new();
1196 assert_eq!(buf.nth_contiguous(0), None);
1197 }
1198
1199 #[test]
1200 fn nth_contiguous_n0_no_rotation() {
1201 let mut buf = BytearrayRingbuffer::<64>::new();
1203 buf.push(b"hello").unwrap();
1204 buf.push(b"world").unwrap();
1205 let slice = buf.nth_contiguous(0).unwrap();
1208 assert_eq!(slice, b"hello");
1209 let slice = buf.nth_contiguous(1).unwrap();
1211 assert_eq!(slice, b"world");
1212 }
1213
1214 #[test]
1215 fn nth_contiguous_called_twice() {
1216 const N: usize = 48;
1219 for offset in 0..N {
1220 let mut buf = BytearrayRingbuffer::<N>::new();
1221 buf.head = offset;
1222 buf.tail = offset;
1223
1224 buf.push(b"alpha").unwrap();
1225 buf.push(b"beta").unwrap();
1226 buf.push(b"gamma").unwrap();
1227
1228 let slice = buf.nth_contiguous(1).unwrap();
1230 assert_eq!(slice, b"beta");
1231
1232 let slice = buf.nth_contiguous(2).unwrap();
1234 assert_eq!(slice, b"gamma");
1235
1236 let payloads: Vec<Vec<u8>> = buf
1238 .iter()
1239 .map(|p| {
1240 let mut v = p.a.to_vec();
1241 v.extend_from_slice(p.b);
1242 v
1243 })
1244 .collect();
1245 assert_eq!(payloads[0], b"alpha");
1246 assert_eq!(payloads[1], b"beta");
1247 assert_eq!(payloads[2], b"gamma");
1248 }
1249 }
1250
1251 #[test]
1254 fn free_returns_zero_when_full() {
1255 let mut buf = BytearrayRingbuffer::<32>::new();
1257 buf.push(b"01234567").unwrap();
1258 buf.push(b"01234567").unwrap();
1259 assert_eq!(buf.free(), 0);
1260 assert!(buf.push(b"x").is_err());
1262 }
1263
1264 #[test]
1267 fn push_force_drops_multiple_packets() {
1268 let mut buf = BytearrayRingbuffer::<32>::new();
1273 buf.push(b"a").unwrap();
1274 buf.push(b"b").unwrap();
1275 buf.push(b"c").unwrap();
1276 assert_eq!(buf.count(), 3);
1277
1278 let payload = b"0123456789abcdef"; buf.push_force(payload).unwrap();
1280
1281 assert_eq!(buf.count(), 1);
1283 let p = buf.pop_front().unwrap();
1284 assert_eq!(collect(p.a, p.b), payload);
1285 }
1286
1287 #[test]
1290 fn multipart_push_total_exceeds_max_returns_error() {
1291 let mut buf = BytearrayRingbuffer::<16>::new();
1294 let mut mp = buf.push_multipart().unwrap();
1295 mp.push(b"abcde").unwrap(); let err = mp.push(b"wxyz"); assert!(err.is_err());
1298 drop(mp); assert_eq!(buf.count(), 1);
1300 let p = buf.pop_front().unwrap();
1301 assert_eq!(collect(p.a, p.b), b"abcde");
1302 }
1303
1304 #[test]
1307 fn multipart_force_full_buffer_start() {
1308 let mut buf = BytearrayRingbuffer::<16>::new();
1311 buf.push(&[0u8; 8]).unwrap(); assert_eq!(buf.bytes_unused(), 0);
1313
1314 let mut mp = buf.push_multipart_force();
1315 mp.push(b"hi").unwrap();
1316 drop(mp);
1317
1318 assert_eq!(buf.count(), 1);
1319 let p = buf.pop_front().unwrap();
1320 assert_eq!(collect(p.a, p.b), b"hi");
1321 }
1322
1323 #[test]
1326 fn copy_into_contiguous() {
1327 let mut buf = BytearrayRingbuffer::<64>::new();
1329 buf.push(b"hello").unwrap();
1330 let p = buf.pop_front().unwrap();
1331 assert!(p.b.is_empty());
1332 let mut out = [0u8; 5];
1333 p.copy_into(&mut out);
1334 assert_eq!(&out, b"hello");
1335 }
1336
1337 #[test]
1338 fn copy_into_wrapped() {
1339 const N: usize = 16;
1341 let mut buf = BytearrayRingbuffer::<N>::new();
1342 buf.head = 9;
1343 buf.tail = 9;
1344 buf.push(b"abcde").unwrap();
1345 let p = buf.pop_front().unwrap();
1346 assert!(!p.b.is_empty(), "expected a wrapped packet");
1347 let mut out = [0u8; 5];
1348 p.copy_into(&mut out);
1349 assert_eq!(&out, b"abcde");
1350 }
1351
1352 #[test]
1353 #[should_panic(expected = "buffer length must equal packet length")]
1354 fn copy_into_wrong_length_panics() {
1355 let mut buf = BytearrayRingbuffer::<64>::new();
1356 buf.push(b"hello").unwrap();
1357 let p = buf.pop_front().unwrap();
1358 let mut out = [0u8; 4]; p.copy_into(&mut out);
1360 }
1361
1362 #[test]
1365 fn copy_part_into_in_a() {
1366 const N: usize = 16;
1369 let mut buf = BytearrayRingbuffer::<N>::new();
1370 buf.head = 9;
1371 buf.tail = 9;
1372 buf.push(b"abcde").unwrap();
1373 let p = buf.pop_front().unwrap();
1374 assert!(!p.b.is_empty(), "expected a wrapped packet");
1375 let mut out = [0u8; 2];
1376 p.copy_part_into(0..2, &mut out);
1377 assert_eq!(&out, b"ab");
1378 }
1379
1380 #[test]
1381 fn copy_part_into_in_b() {
1382 const N: usize = 16;
1385 let mut buf = BytearrayRingbuffer::<N>::new();
1386 buf.head = 9;
1387 buf.tail = 9;
1388 buf.push(b"abcde").unwrap();
1389 let p = buf.pop_front().unwrap();
1390 let mut out = [0u8; 1];
1391 p.copy_part_into(3..4, &mut out);
1392 assert_eq!(&out, b"d");
1393 }
1394
1395 #[test]
1396 fn copy_part_into_spanning() {
1397 const N: usize = 16;
1400 let mut buf = BytearrayRingbuffer::<N>::new();
1401 buf.head = 9;
1402 buf.tail = 9;
1403 buf.push(b"abcde").unwrap();
1404 let p = buf.pop_front().unwrap();
1405 let mut out = [0u8; 3];
1406 p.copy_part_into(1..4, &mut out);
1407 assert_eq!(&out, b"bcd");
1408 }
1409
1410 #[test]
1411 #[should_panic(expected = "buffer length must equal range length")]
1412 fn copy_part_into_wrong_buffer_length_panics() {
1413 let mut buf = BytearrayRingbuffer::<64>::new();
1414 buf.push(b"hello").unwrap();
1415 let p = buf.pop_front().unwrap();
1416 let mut out = [0u8; 3]; p.copy_part_into(0..2, &mut out);
1418 }
1419
1420 #[test]
1421 #[should_panic(expected = "range out of bounds")]
1422 fn copy_part_into_out_of_bounds_panics() {
1423 let mut buf = BytearrayRingbuffer::<64>::new();
1424 buf.push(b"hello").unwrap(); let p = buf.pop_front().unwrap();
1426 let mut out = [0u8; 2];
1427 p.copy_part_into(4..6, &mut out); }
1429
1430 #[test]
1433 fn copy_part_into_range_inclusive() {
1434 let mut buf = BytearrayRingbuffer::<64>::new();
1436 buf.push(b"abcde").unwrap();
1437 let p = buf.pop_front().unwrap();
1438 let mut out = [0u8; 3];
1439 p.copy_part_into(1..=3, &mut out);
1440 assert_eq!(&out, b"bcd");
1441 }
1442
1443 #[test]
1444 fn copy_part_into_range_from() {
1445 let mut buf = BytearrayRingbuffer::<64>::new();
1447 buf.push(b"abcde").unwrap();
1448 let p = buf.pop_front().unwrap();
1449 let mut out = [0u8; 2];
1450 p.copy_part_into(3.., &mut out);
1451 assert_eq!(&out, b"de");
1452 }
1453
1454 #[test]
1455 fn copy_part_into_range_to() {
1456 let mut buf = BytearrayRingbuffer::<64>::new();
1458 buf.push(b"abcde").unwrap();
1459 let p = buf.pop_front().unwrap();
1460 let mut out = [0u8; 3];
1461 p.copy_part_into(..3, &mut out);
1462 assert_eq!(&out, b"abc");
1463 }
1464
1465 #[test]
1466 fn copy_part_into_range_full() {
1467 let mut buf = BytearrayRingbuffer::<64>::new();
1469 buf.push(b"abcde").unwrap();
1470 let p = buf.pop_front().unwrap();
1471 let mut out = [0u8; 5];
1472 p.copy_part_into(.., &mut out);
1473 assert_eq!(&out, b"abcde");
1474 }
1475
1476 #[test]
1477 fn copy_part_into_range_to_inclusive() {
1478 let mut buf = BytearrayRingbuffer::<64>::new();
1480 buf.push(b"abcde").unwrap();
1481 let p = buf.pop_front().unwrap();
1482 let mut out = [0u8; 3];
1483 p.copy_part_into(..=2, &mut out);
1484 assert_eq!(&out, b"abc");
1485 }
1486
1487 #[test]
1490 fn packet_len_contiguous() {
1491 let mut buf = BytearrayRingbuffer::<64>::new();
1492 buf.push(b"hello").unwrap();
1493 let p = buf.pop_front().unwrap();
1494 assert_eq!(p.len(), 5);
1495 assert!(!p.is_empty());
1496 }
1497
1498 #[test]
1499 fn packet_len_wrapped() {
1500 const N: usize = 16;
1501 let mut buf = BytearrayRingbuffer::<N>::new();
1502 buf.head = 9;
1503 buf.tail = 9;
1504 buf.push(b"abcde").unwrap();
1505 let p = buf.pop_front().unwrap();
1506 assert!(!p.b.is_empty(), "expected a wrapped packet");
1507 assert_eq!(p.len(), 5);
1508 assert!(!p.is_empty());
1509 }
1510
1511 #[test]
1512 fn packet_len_empty_payload() {
1513 let mut buf = BytearrayRingbuffer::<64>::new();
1514 buf.push(b"").unwrap();
1515 let p = buf.pop_front().unwrap();
1516 assert_eq!(p.len(), 0);
1517 assert!(p.is_empty());
1518 }
1519}