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 const fn free(&self) -> usize {
255 self.bytes_unused().saturating_sub(8)
256 }
257
258 pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
268 self._push(data, false)
269 }
270
271 pub fn push_force(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
280 self._push(data, true)
281 }
282
283 pub fn push_multipart(&mut self) -> Result<MultipartPush<'_, N>, NotEnoughSpaceError> {
294 if self.bytes_unused() < 8 {
296 return Err(NotEnoughSpaceError);
297 }
298 let start = self.head;
299 self.head = add_wrapping::<N>(self.head, 4);
300 Ok(MultipartPush {
301 buf: self,
302 start,
303 len: 0,
304 force: false,
305 cancelled: false,
306 })
307 }
308
309 pub fn push_multipart_force(&mut self) -> MultipartPush<'_, N> {
317 while self.bytes_unused() < 8 && !self.empty() {
319 self.pop_front();
320 }
321 let start = self.head;
322 self.head = add_wrapping::<N>(self.head, 4);
323 MultipartPush {
324 buf: self,
325 start,
326 len: 0,
327 force: true,
328 cancelled: false,
329 }
330 }
331
332 #[inline(always)]
334 pub const fn empty(&self) -> bool {
335 self.count == 0
336 }
337
338 const fn bytes_unused(&self) -> usize {
340 if self.empty() {
341 N
342 } else if self.head > self.tail {
343 N + self.tail - self.head
344 } else {
345 self.tail - self.head
346 }
347 }
348
349 fn _push(&mut self, data: &[u8], force: bool) -> Result<(), NotEnoughSpaceError> {
350 assert!(data.len() <= u32::MAX as usize);
351
352 if data.len() > N - 8 {
354 return Err(NotEnoughSpaceError);
355 }
356
357 if (data.len() + 8) > self.bytes_unused() {
359 if !force {
360 return Err(NotEnoughSpaceError);
361 }
362 while (data.len() + 8) > self.bytes_unused() {
363 self.pop_front();
364 }
365 }
366
367 let addr_a = self.head;
369 let addr_b = add_wrapping::<N>(self.head, 4);
370 let addr_c = add_wrapping::<N>(self.head, 4 + data.len());
371 let len_buffer: [u8; 4] = (data.len() as u32).to_ne_bytes();
372 write_wrapping(&mut self.buffer, addr_a, &len_buffer);
373 write_wrapping(&mut self.buffer, addr_b, data);
374 write_wrapping(&mut self.buffer, addr_c, &len_buffer);
375
376 self.head = add_wrapping::<N>(self.head, 8 + data.len());
377 self.count += 1;
378
379 Ok(())
380 }
381
382 pub fn pop_front(&mut self) -> Option<Packet<'_>> {
387 if self.empty() {
388 return None;
389 }
390 let mut len_buffer = [0; 4];
391 read_wrapping(&self.buffer, self.tail, &mut len_buffer);
392 let len = u32::from_ne_bytes(len_buffer) as usize;
393
394 let index_data = add_wrapping::<N>(self.tail, 4);
395 let len_a = (N - index_data).min(len);
396 let a = &self.buffer[index_data..index_data + len_a];
397 let b = if len_a == len {
398 &[]
399 } else {
400 &self.buffer[..len - len_a]
401 };
402
403 self.tail = add_wrapping::<N>(self.tail, len + 8);
404 self.count -= 1;
405 Some(Packet { a, b })
406 }
407
408 pub fn iter_backwards<'a>(&'a self) -> IterBackwards<'a, N> {
410 IterBackwards {
411 buffer: &self.buffer,
412 head: self.head,
413 count: self.count,
414 }
415 }
416
417 pub fn iter<'a>(&'a self) -> Iter<'a, N> {
419 Iter {
420 buffer: &self.buffer,
421 head: self.head,
422 tail: self.tail,
423 count: self.count,
424 }
425 }
426
427 #[inline(always)]
429 pub const fn count(&self) -> usize {
430 self.count
431 }
432
433 pub fn nth(&self, n: usize) -> Option<Packet<'_>> {
437 self.iter().nth(n)
438 }
439
440 pub fn nth_reverse(&self, n: usize) -> Option<Packet<'_>> {
444 self.iter_backwards().nth(n)
445 }
446
447 pub fn nth_contiguous(&mut self, mut n: usize) -> Option<&[u8]> {
455 if self.empty() || n >= self.count {
456 return None;
457 }
458
459 let mut tail = self.tail;
461 let len_data = loop {
462 let mut buf = [0u8; 4];
463 read_wrapping(&self.buffer, tail, &mut buf);
464 let len_data = u32::from_ne_bytes(buf) as usize;
465
466 if n == 0 {
467 break len_data;
468 }
469 n -= 1;
470
471 tail = add_wrapping::<N>(tail, len_data + 8);
472 };
473
474 let index_data = add_wrapping::<N>(tail, 4);
475
476 if index_data + len_data <= N {
478 return Some(&self.buffer[index_data..index_data + len_data]);
479 }
480
481 self.buffer.rotate_left(index_data);
483 self.tail = sub_wrapping::<N>(self.tail, index_data);
484 self.head = sub_wrapping::<N>(self.head, index_data);
485
486 Some(&self.buffer[..len_data])
487 }
488}
489
490pub struct IterBackwards<'a, const N: usize> {
492 buffer: &'a [u8; N],
493 head: usize,
494 count: usize,
495}
496
497impl<'a, const N: usize> Iterator for IterBackwards<'a, N> {
498 type Item = Packet<'a>;
499
500 fn next(&mut self) -> Option<Self::Item> {
501 if self.count == 0 {
502 return None;
503 }
504
505 let index_len = sub_wrapping::<N>(self.head, 4);
507 let mut buf = [0u8; 4];
508 read_wrapping(self.buffer, index_len, &mut buf);
509 let len_data = u32::from_ne_bytes(buf) as usize;
510 debug_assert!((len_data + 8) <= N);
511
512 #[cfg(test)]
513 {
514 let index_len = sub_wrapping::<N>(self.head, 8 + len_data);
515 let mut buf = [0u8; 4];
516 read_wrapping(self.buffer, index_len, &mut buf);
517 let len_2 = u32::from_ne_bytes(buf) as usize;
518 assert_eq!(len_data, len_2);
519 }
520
521 let index_data = sub_wrapping::<N>(self.head, 4 + len_data);
523 let first = (N - index_data).min(len_data);
524 let slice_a = &self.buffer[index_data..index_data + first];
525 let slice_b = if first < len_data {
526 &self.buffer[..len_data - first]
527 } else {
528 &[]
529 };
530
531 self.head = sub_wrapping::<N>(self.head, 8 + len_data);
532 self.count -= 1;
533
534 Some(Packet {
535 a: slice_a,
536 b: slice_b,
537 })
538 }
539}
540
541impl<const N: usize> Default for BytearrayRingbuffer<N> {
542 fn default() -> Self {
543 Self::new()
544 }
545}
546
547pub struct Iter<'a, const N: usize> {
549 buffer: &'a [u8; N],
550 head: usize,
551 tail: usize,
552 count: usize,
553}
554
555impl<'a, const N: usize> Iterator for Iter<'a, N> {
556 type Item = Packet<'a>;
557
558 fn next(&mut self) -> Option<Self::Item> {
559 if self.count == 0 {
560 return None;
561 }
562
563 let bytes_unused = if self.head > self.tail {
565 N + self.tail - self.head
566 } else {
567 self.tail - self.head
568 };
569 let bytes_occupied = N - bytes_unused;
570 debug_assert!(bytes_occupied >= 8);
571
572 let mut buf = [0u8; 4];
574 read_wrapping(self.buffer, self.tail, &mut buf);
575 let len_data = u32::from_ne_bytes(buf) as usize;
576 debug_assert!((len_data + 8) <= N);
577 debug_assert!((len_data + 8) <= bytes_occupied);
578
579 let index_data = add_wrapping::<N>(self.tail, 4);
581 let first = (N - index_data).min(len_data);
582 let slice_a = &self.buffer[index_data..index_data + first];
583 let slice_b = if first < len_data {
584 &self.buffer[..len_data - first]
585 } else {
586 &[]
587 };
588
589 self.tail = add_wrapping::<N>(self.tail, 8 + len_data);
590 self.count -= 1;
591
592 Some(Packet {
593 a: slice_a,
594 b: slice_b,
595 })
596 }
597}
598
599fn add_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
600 debug_assert!(addr < N);
601 debug_assert!(offset <= N);
602 let s = addr + offset;
603 if s < N { s } else { s - N }
604}
605
606fn sub_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
607 debug_assert!(addr < N);
608 debug_assert!(offset <= N);
609 if addr >= offset {
610 addr - offset
611 } else {
612 N + addr - offset
613 }
614}
615
616fn write_wrapping(buffer: &mut [u8], index: usize, data: &[u8]) {
618 let first = (buffer.len() - index).min(data.len());
619 buffer[index..index + first].copy_from_slice(&data[..first]);
620 if first < data.len() {
621 buffer[..data.len() - first].copy_from_slice(&data[first..]);
622 }
623}
624
625fn read_wrapping(buffer: &[u8], index: usize, data: &mut [u8]) {
627 let first = (buffer.len() - index).min(data.len());
628 data[..first].copy_from_slice(&buffer[index..index + first]);
629 if first < data.len() {
630 let remaining = data.len() - first;
631 data[first..].copy_from_slice(&buffer[..remaining]);
632 }
633}
634
635#[cfg(test)]
636mod tests {
637 use std::collections::VecDeque;
638
639 use super::BytearrayRingbuffer;
640
641 #[test]
642 fn push_some_packets() {
643 const N: usize = 64;
644 for start_offset in 0..N {
645 let mut buf = BytearrayRingbuffer::<N>::new();
646 buf.head = start_offset;
647 buf.tail = start_offset;
648
649 let free = 64 - 8;
650 assert_eq!(buf.free(), free);
651
652 buf.push(b"01234567").unwrap();
653 let free = free - 8 - 8;
654 assert_eq!(buf.free(), free);
655
656 buf.push(b"").unwrap();
657 let free = free - 8;
658 assert_eq!(buf.free(), free);
659
660 buf.push(b"0123").unwrap();
661 let free = free - 4 - 8;
662 assert_eq!(buf.free(), free);
663
664 buf.push(b"0123").unwrap();
665 let free = free - 4 - 8;
666 assert_eq!(buf.free(), free);
667 }
668 }
669
670 #[test]
671 fn push_force() {
672 let mut buf = BytearrayRingbuffer::<16>::new();
673 assert_eq!(buf.bytes_unused(), 16);
674
675 let a = b"012345";
676 let b = b"0123";
677
678 buf.push(a).unwrap();
679 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
680
681 buf.push(b).unwrap_err();
682 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
683
684 buf.push_force(b).unwrap();
685 assert_eq!(buf.bytes_unused(), 16 - b.len() - 8);
686 }
687
688 #[test]
689 fn push_all_data_lengths() {
690 for n in 0..(32 - 8) {
691 let mut buf = BytearrayRingbuffer::<32>::new();
692 let data = (0..n as u8).collect::<Vec<u8>>();
694
695 assert_eq!(buf.free(), 32 - 8);
696 buf.push(&data).unwrap();
697 assert_eq!(buf.free(), (32usize - 16).saturating_sub(n));
698 }
699 }
700
701 #[test]
702 fn push_sum_of_lengths_possible() {
703 let mut buf = BytearrayRingbuffer::<32>::new();
704 assert_eq!(buf.free(), 32 - 8);
706 buf.push(b"01234567").unwrap();
707 assert_eq!(buf.free(), 32 - 8 - 16);
708 buf.push(b"01234567").unwrap();
709 assert_eq!(buf.free(), 0);
710 }
711
712 #[test]
713 fn push_pop() {
714 const N: usize = 64;
715 for start_offset in 0..N {
716 eprintln!("--------------");
717 let mut buf = BytearrayRingbuffer::<N>::new();
718 buf.head = start_offset;
719 buf.tail = start_offset;
720
721 let data = b"01234567";
722 buf.push(data).unwrap();
723
724 let p = buf.pop_front().unwrap();
725 let mut out = Vec::new();
726 out.extend_from_slice(p.a);
727 out.extend_from_slice(p.b);
728
729 dbg!(out.as_slice());
730 assert!(data == out.as_slice());
731
732 assert_eq!(buf.head, buf.tail);
733 assert_eq!(buf.bytes_unused(), N);
734 }
735 }
736
737 #[test]
738 fn push_read_back() {
739 let data = [b"hello world" as &[u8], b"", b"test"];
740
741 const N: usize = 64;
742 for start_offset in 0..N {
743 let mut buf = BytearrayRingbuffer::<N>::new();
744 buf.head = start_offset;
745 buf.tail = start_offset;
746
747 for &d in &data {
748 buf.push(d).unwrap();
749 }
750
751 let mut it = buf.iter();
753 for &d in data.iter() {
754 let p = it.next().unwrap();
755 let mut ab = Vec::new();
756 ab.extend_from_slice(p.a);
757 ab.extend_from_slice(p.b);
758 let ab = ab.as_slice();
759 assert_eq!(d, ab);
760 }
761 assert_eq!(it.next(), None);
762
763 let mut it = buf.iter_backwards();
765 for &d in data.iter().rev() {
766 let p = it.next().unwrap();
767 let mut ab = Vec::new();
768 ab.extend_from_slice(p.a);
769 ab.extend_from_slice(p.b);
770 let ab = ab.as_slice();
771 assert_eq!(d, ab);
772 }
773 assert_eq!(it.next(), None);
774 }
775 }
776
777 #[test]
778 fn push_count() {
779 let mut buf = BytearrayRingbuffer::<64>::new();
780 buf.push(b"1234").unwrap();
781 assert_eq!(buf.count(), 1);
782 buf.push(b"1234").unwrap();
783 assert_eq!(buf.count(), 2);
784 buf.push(b"1234").unwrap();
785 assert_eq!(buf.count(), 3);
786 }
787
788 fn test_with_readback<const N: usize>(words: &[&'static str]) {
789 eprintln!("--------------------------");
790 let mut buf = BytearrayRingbuffer::<N>::new();
791 let mut current_words = VecDeque::new();
792 for &word in words {
793 eprintln!("adding {word:?}");
794 let word = word.to_owned();
795 let current_bytes: usize = current_words.iter().map(|w: &String| w.len() + 8).sum();
796 if current_bytes + 8 + word.len() > N {
797 current_words.pop_front();
798 }
799
800 buf.push_force(word.as_bytes()).unwrap();
801 current_words.push_back(word);
802
803 for (p, word) in buf.iter_backwards().zip(current_words.iter().rev()) {
804 eprintln!("read back {word:?}");
805 let mut st = String::new();
806 st.push_str(core::str::from_utf8(p.a).unwrap());
807 st.push_str(core::str::from_utf8(p.b).unwrap());
808 assert_eq!(st, *word);
809 }
810 }
811 }
812
813 #[test]
814 fn readback_various() {
815 test_with_readback::<32>(&["ab", "123", "hello", "world"]);
816 test_with_readback::<32>(&["", "", "a", "", "", ""]);
817 test_with_readback::<32>(&["", "", "ab", "", "", ""]);
818 test_with_readback::<32>(&["", "", "abc", "", "", ""]);
819 test_with_readback::<32>(&["", "", "abcd", "", "", ""]);
820 test_with_readback::<32>(&["", "", "abcde", "", "", ""]);
821
822 test_with_readback::<24>(&["0", "1", "a", "2", "3", "4"]);
823 test_with_readback::<24>(&["0", "1", "ab", "2", "3", "4"]);
824 test_with_readback::<24>(&["0", "1", "abc", "2", "3", "4"]);
825 test_with_readback::<24>(&["0", "1", "abcd", "2", "3", "4"]);
826 test_with_readback::<24>(&["0", "1", "abcde", "2", "3", "4"]);
827 test_with_readback::<24>(&["0", "1", "abcdef", "2", "3", "4"]);
828 test_with_readback::<24>(&["0", "1", "abcdefg", "2", "3", "4"]);
829 }
830
831 #[test]
832 fn nth_contiguous_out_of_range_returns_none() {
833 let mut buf = BytearrayRingbuffer::<64>::new();
834 buf.push(b"hello").unwrap();
835 assert_eq!(buf.count(), 1);
836
837 assert_eq!(buf.nth_contiguous(1), None);
838 }
839
840 #[test]
841 fn rotate_contiguous() {
842 const N: usize = 48;
843 let data: [&[u8]; _] = [b"012345", b"hello world", b"xyz"];
844
845 for offset in 0..N {
846 let mut buf = BytearrayRingbuffer::<N>::new();
847 buf.head = offset;
848 buf.tail = offset;
849
850 for &d in &data {
851 buf.push(d).unwrap();
852 }
853
854 let read = buf.nth_contiguous(1).unwrap();
855 assert_eq!(data[1], read);
856
857 for (&r, p) in data.iter().zip(buf.iter()) {
859 let mut out = Vec::new();
860 out.extend_from_slice(p.a);
861 out.extend_from_slice(p.b);
862 assert_eq!(out.as_slice(), r);
863 }
864 }
865 }
866
867 fn collect(a: &[u8], b: &[u8]) -> Vec<u8> {
870 let mut v = Vec::new();
871 v.extend_from_slice(a);
872 v.extend_from_slice(b);
873 v
874 }
875
876 #[test]
877 fn multipart_normal_fits() {
878 const N: usize = 64;
879 for offset in 0..N {
880 let mut buf = BytearrayRingbuffer::<N>::new();
881 buf.head = offset;
882 buf.tail = offset;
883
884 let mut mp = buf.push_multipart().unwrap();
885 mp.push(b"hello").unwrap();
886 mp.push(b" ").unwrap();
887 mp.push(b"world").unwrap();
888 drop(mp);
889
890 assert_eq!(buf.count(), 1);
891 let p = buf.pop_front().unwrap();
892 assert_eq!(collect(p.a, p.b), b"hello world");
893 assert_eq!(buf.count(), 0);
894 }
895 }
896
897 #[test]
898 fn multipart_empty_packet() {
899 let mut buf = BytearrayRingbuffer::<64>::new();
900 let mp = buf.push_multipart().unwrap();
901 drop(mp); assert_eq!(buf.count(), 1);
903 let p = buf.pop_front().unwrap();
904 assert_eq!(collect(p.a, p.b), b"");
905 }
906
907 #[test]
908 fn multipart_normal_overflow_returns_err() {
909 let mut buf = BytearrayRingbuffer::<24>::new();
914 buf.push(b"").unwrap(); let mut mp = buf.push_multipart().unwrap();
917 mp.push(b"abcd").unwrap(); let err = mp.push(b"12345"); assert!(err.is_err());
920
921 drop(mp);
923 assert_eq!(buf.count(), 2);
924 let p = buf.nth(1).unwrap();
926 assert_eq!(collect(p.a, p.b), b"abcd");
927 }
928
929 #[test]
930 fn multipart_cancel_normal_mode() {
931 let mut buf = BytearrayRingbuffer::<64>::new();
932 let original_unused = buf.bytes_unused();
933 let original_count = buf.count();
934
935 let mut mp = buf.push_multipart().unwrap();
936 mp.push(b"data that will be discarded").unwrap();
937 mp.cancel();
938
939 assert_eq!(buf.count(), original_count);
940 assert_eq!(buf.bytes_unused(), original_unused);
941 }
942
943 #[test]
944 fn multipart_normal_no_room_for_start() {
945 let mut buf = BytearrayRingbuffer::<24>::new();
947 buf.push(&[0u8; 16]).unwrap(); assert_eq!(buf.bytes_unused(), 0);
949 assert!(buf.push_multipart().is_err());
950 }
951
952 #[test]
953 fn multipart_force_drops_old_packets() {
954 let mut buf = BytearrayRingbuffer::<24>::new();
959 buf.push(b"AA").unwrap(); buf.push(b"BB").unwrap(); assert_eq!(buf.count(), 2);
962
963 let mut mp = buf.push_multipart_force();
964 mp.push(b"hello world").unwrap(); drop(mp);
966
967 assert_eq!(buf.count(), 1);
968 let p = buf.pop_front().unwrap();
969 assert_eq!(collect(p.a, p.b), b"hello world");
970 }
971
972 #[test]
973 fn multipart_force_cancel_drops_are_permanent() {
974 let mut buf = BytearrayRingbuffer::<24>::new();
976 buf.push(b"AA").unwrap();
977 buf.push(b"BB").unwrap();
978 let count_before = buf.count(); let mut mp = buf.push_multipart_force();
981 mp.push(b"hello world").unwrap(); mp.cancel(); assert!(buf.count() < count_before);
986 assert_eq!(buf.count(), 0);
987 }
988
989 #[test]
990 fn multipart_push_after_multipart() {
991 let mut buf = BytearrayRingbuffer::<64>::new();
992 {
993 let mut mp = buf.push_multipart().unwrap();
994 mp.push(b"first").unwrap();
995 }
996 buf.push(b"second").unwrap();
997
998 assert_eq!(buf.count(), 2);
999 let p = buf.nth(0).unwrap();
1000 assert_eq!(collect(p.a, p.b), b"first");
1001 let p = buf.nth(1).unwrap();
1002 assert_eq!(collect(p.a, p.b), b"second");
1003 }
1004
1005 #[test]
1006 fn multipart_force_max_payload() {
1007 const N: usize = 32;
1009 let mut buf = BytearrayRingbuffer::<N>::new();
1010 buf.push(b"old").unwrap(); let payload: Vec<u8> = (0..((N - 8) as u8)).collect();
1013 let mut mp = buf.push_multipart_force();
1014 mp.push(&payload).unwrap();
1015 drop(mp);
1016
1017 assert_eq!(buf.count(), 1);
1018 let p = buf.pop_front().unwrap();
1019 assert_eq!(collect(p.a, p.b), payload);
1020 }
1021
1022 #[test]
1023 fn multipart_wraparound_all_offsets() {
1024 const N: usize = 48;
1025 for offset in 0..N {
1026 let mut buf = BytearrayRingbuffer::<N>::new();
1027 buf.head = offset;
1028 buf.tail = offset;
1029
1030 buf.push(b"prefix").unwrap();
1032
1033 let mut mp = buf.push_multipart().unwrap();
1035 mp.push(b"foo").unwrap();
1036 mp.push(b"bar").unwrap();
1037 drop(mp);
1038
1039 buf.push(b"suffix").unwrap();
1041
1042 assert_eq!(buf.count(), 3);
1043 let p = buf.nth(0).unwrap();
1044 assert_eq!(collect(p.a, p.b), b"prefix");
1045 let p = buf.nth(1).unwrap();
1046 assert_eq!(collect(p.a, p.b), b"foobar");
1047 let p = buf.nth(2).unwrap();
1048 assert_eq!(collect(p.a, p.b), b"suffix");
1049 }
1050 }
1051
1052 #[test]
1055 fn pop_front_empty_returns_none() {
1056 let mut buf = BytearrayRingbuffer::<32>::new();
1057 assert_eq!(buf.pop_front(), None);
1058 }
1059
1060 #[test]
1061 fn empty_and_count_lifecycle() {
1062 let mut buf = BytearrayRingbuffer::<32>::new();
1063
1064 assert!(buf.empty());
1066 assert_eq!(buf.count(), 0);
1067
1068 buf.push(b"a").unwrap();
1069 assert!(!buf.empty());
1070 assert_eq!(buf.count(), 1);
1071
1072 buf.push(b"b").unwrap();
1073 assert!(!buf.empty());
1074 assert_eq!(buf.count(), 2);
1075
1076 buf.pop_front().unwrap();
1077 assert!(!buf.empty());
1078 assert_eq!(buf.count(), 1);
1079
1080 buf.pop_front().unwrap();
1081 assert!(buf.empty());
1082 assert_eq!(buf.count(), 0);
1083
1084 assert_eq!(buf.pop_front(), None);
1086 }
1087
1088 #[test]
1089 fn default_creates_empty_buffer() {
1090 let buf = BytearrayRingbuffer::<32>::default();
1091 assert!(buf.empty());
1092 assert_eq!(buf.count(), 0);
1093 assert_eq!(buf.free(), 32 - 8);
1094 }
1095
1096 #[test]
1099 fn push_oversized_returns_error() {
1100 let mut buf = BytearrayRingbuffer::<16>::new();
1101 let oversized = [0u8; 9];
1103 assert!(buf.push(&oversized).is_err());
1104 assert!(buf.empty());
1106 }
1107
1108 #[test]
1109 fn push_force_oversized_returns_error() {
1110 let mut buf = BytearrayRingbuffer::<16>::new();
1111 let oversized = [0u8; 9];
1113 assert!(buf.push_force(&oversized).is_err());
1114 assert!(buf.empty());
1115 }
1116
1117 #[test]
1120 fn iter_empty_buffer() {
1121 let buf = BytearrayRingbuffer::<32>::new();
1122 assert_eq!(buf.iter().next(), None);
1123 }
1124
1125 #[test]
1126 fn iter_backwards_empty_buffer() {
1127 let buf = BytearrayRingbuffer::<32>::new();
1128 assert_eq!(buf.iter_backwards().next(), None);
1129 }
1130
1131 #[test]
1134 fn nth_empty_returns_none() {
1135 let buf = BytearrayRingbuffer::<32>::new();
1136 assert_eq!(buf.nth(0), None);
1137 }
1138
1139 #[test]
1140 fn nth_out_of_bounds_returns_none() {
1141 let buf = {
1142 let mut b = BytearrayRingbuffer::<64>::new();
1143 b.push(b"x").unwrap();
1144 b.push(b"y").unwrap();
1145 b
1146 };
1147 assert_eq!(buf.nth(2), None);
1148 assert_eq!(buf.nth(100), None);
1149 }
1150
1151 #[test]
1152 fn nth_reverse_basic() {
1153 let mut buf = BytearrayRingbuffer::<64>::new();
1154 buf.push(b"oldest").unwrap();
1155 buf.push(b"middle").unwrap();
1156 buf.push(b"newest").unwrap();
1157
1158 let p = buf.nth_reverse(0).unwrap();
1159 assert_eq!(collect(p.a, p.b), b"newest");
1160 let p = buf.nth_reverse(1).unwrap();
1161 assert_eq!(collect(p.a, p.b), b"middle");
1162 let p = buf.nth_reverse(2).unwrap();
1163 assert_eq!(collect(p.a, p.b), b"oldest");
1164 }
1165
1166 #[test]
1167 fn nth_reverse_empty_returns_none() {
1168 let buf = BytearrayRingbuffer::<32>::new();
1169 assert_eq!(buf.nth_reverse(0), None);
1170 }
1171
1172 #[test]
1173 fn nth_reverse_out_of_bounds_returns_none() {
1174 let buf = {
1175 let mut b = BytearrayRingbuffer::<64>::new();
1176 b.push(b"only").unwrap();
1177 b
1178 };
1179 assert_eq!(buf.nth_reverse(1), None);
1180 assert_eq!(buf.nth_reverse(99), None);
1181 }
1182
1183 #[test]
1186 fn nth_contiguous_empty_returns_none() {
1187 let mut buf = BytearrayRingbuffer::<32>::new();
1188 assert_eq!(buf.nth_contiguous(0), None);
1189 }
1190
1191 #[test]
1192 fn nth_contiguous_n0_no_rotation() {
1193 let mut buf = BytearrayRingbuffer::<64>::new();
1195 buf.push(b"hello").unwrap();
1196 buf.push(b"world").unwrap();
1197 let slice = buf.nth_contiguous(0).unwrap();
1200 assert_eq!(slice, b"hello");
1201 let slice = buf.nth_contiguous(1).unwrap();
1203 assert_eq!(slice, b"world");
1204 }
1205
1206 #[test]
1207 fn nth_contiguous_called_twice() {
1208 const N: usize = 48;
1211 for offset in 0..N {
1212 let mut buf = BytearrayRingbuffer::<N>::new();
1213 buf.head = offset;
1214 buf.tail = offset;
1215
1216 buf.push(b"alpha").unwrap();
1217 buf.push(b"beta").unwrap();
1218 buf.push(b"gamma").unwrap();
1219
1220 let slice = buf.nth_contiguous(1).unwrap();
1222 assert_eq!(slice, b"beta");
1223
1224 let slice = buf.nth_contiguous(2).unwrap();
1226 assert_eq!(slice, b"gamma");
1227
1228 let payloads: Vec<Vec<u8>> = buf
1230 .iter()
1231 .map(|p| {
1232 let mut v = p.a.to_vec();
1233 v.extend_from_slice(p.b);
1234 v
1235 })
1236 .collect();
1237 assert_eq!(payloads[0], b"alpha");
1238 assert_eq!(payloads[1], b"beta");
1239 assert_eq!(payloads[2], b"gamma");
1240 }
1241 }
1242
1243 #[test]
1246 fn free_returns_zero_when_full() {
1247 let mut buf = BytearrayRingbuffer::<32>::new();
1249 buf.push(b"01234567").unwrap();
1250 buf.push(b"01234567").unwrap();
1251 assert_eq!(buf.free(), 0);
1252 assert!(buf.push(b"x").is_err());
1254 }
1255
1256 #[test]
1259 fn push_force_drops_multiple_packets() {
1260 let mut buf = BytearrayRingbuffer::<32>::new();
1265 buf.push(b"a").unwrap();
1266 buf.push(b"b").unwrap();
1267 buf.push(b"c").unwrap();
1268 assert_eq!(buf.count(), 3);
1269
1270 let payload = b"0123456789abcdef"; buf.push_force(payload).unwrap();
1272
1273 assert_eq!(buf.count(), 1);
1275 let p = buf.pop_front().unwrap();
1276 assert_eq!(collect(p.a, p.b), payload);
1277 }
1278
1279 #[test]
1282 fn multipart_push_total_exceeds_max_returns_error() {
1283 let mut buf = BytearrayRingbuffer::<16>::new();
1286 let mut mp = buf.push_multipart().unwrap();
1287 mp.push(b"abcde").unwrap(); let err = mp.push(b"wxyz"); assert!(err.is_err());
1290 drop(mp); assert_eq!(buf.count(), 1);
1292 let p = buf.pop_front().unwrap();
1293 assert_eq!(collect(p.a, p.b), b"abcde");
1294 }
1295
1296 #[test]
1299 fn multipart_force_full_buffer_start() {
1300 let mut buf = BytearrayRingbuffer::<16>::new();
1303 buf.push(&[0u8; 8]).unwrap(); assert_eq!(buf.bytes_unused(), 0);
1305
1306 let mut mp = buf.push_multipart_force();
1307 mp.push(b"hi").unwrap();
1308 drop(mp);
1309
1310 assert_eq!(buf.count(), 1);
1311 let p = buf.pop_front().unwrap();
1312 assert_eq!(collect(p.a, p.b), b"hi");
1313 }
1314
1315 #[test]
1318 fn copy_into_contiguous() {
1319 let mut buf = BytearrayRingbuffer::<64>::new();
1321 buf.push(b"hello").unwrap();
1322 let p = buf.pop_front().unwrap();
1323 assert!(p.b.is_empty());
1324 let mut out = [0u8; 5];
1325 p.copy_into(&mut out);
1326 assert_eq!(&out, b"hello");
1327 }
1328
1329 #[test]
1330 fn copy_into_wrapped() {
1331 const N: usize = 16;
1333 let mut buf = BytearrayRingbuffer::<N>::new();
1334 buf.head = 9;
1335 buf.tail = 9;
1336 buf.push(b"abcde").unwrap();
1337 let p = buf.pop_front().unwrap();
1338 assert!(!p.b.is_empty(), "expected a wrapped packet");
1339 let mut out = [0u8; 5];
1340 p.copy_into(&mut out);
1341 assert_eq!(&out, b"abcde");
1342 }
1343
1344 #[test]
1345 #[should_panic(expected = "buffer length must equal packet length")]
1346 fn copy_into_wrong_length_panics() {
1347 let mut buf = BytearrayRingbuffer::<64>::new();
1348 buf.push(b"hello").unwrap();
1349 let p = buf.pop_front().unwrap();
1350 let mut out = [0u8; 4]; p.copy_into(&mut out);
1352 }
1353
1354 #[test]
1357 fn copy_part_into_in_a() {
1358 const N: usize = 16;
1361 let mut buf = BytearrayRingbuffer::<N>::new();
1362 buf.head = 9;
1363 buf.tail = 9;
1364 buf.push(b"abcde").unwrap();
1365 let p = buf.pop_front().unwrap();
1366 assert!(!p.b.is_empty(), "expected a wrapped packet");
1367 let mut out = [0u8; 2];
1368 p.copy_part_into(0..2, &mut out);
1369 assert_eq!(&out, b"ab");
1370 }
1371
1372 #[test]
1373 fn copy_part_into_in_b() {
1374 const N: usize = 16;
1377 let mut buf = BytearrayRingbuffer::<N>::new();
1378 buf.head = 9;
1379 buf.tail = 9;
1380 buf.push(b"abcde").unwrap();
1381 let p = buf.pop_front().unwrap();
1382 let mut out = [0u8; 1];
1383 p.copy_part_into(3..4, &mut out);
1384 assert_eq!(&out, b"d");
1385 }
1386
1387 #[test]
1388 fn copy_part_into_spanning() {
1389 const N: usize = 16;
1392 let mut buf = BytearrayRingbuffer::<N>::new();
1393 buf.head = 9;
1394 buf.tail = 9;
1395 buf.push(b"abcde").unwrap();
1396 let p = buf.pop_front().unwrap();
1397 let mut out = [0u8; 3];
1398 p.copy_part_into(1..4, &mut out);
1399 assert_eq!(&out, b"bcd");
1400 }
1401
1402 #[test]
1403 #[should_panic(expected = "buffer length must equal range length")]
1404 fn copy_part_into_wrong_buffer_length_panics() {
1405 let mut buf = BytearrayRingbuffer::<64>::new();
1406 buf.push(b"hello").unwrap();
1407 let p = buf.pop_front().unwrap();
1408 let mut out = [0u8; 3]; p.copy_part_into(0..2, &mut out);
1410 }
1411
1412 #[test]
1413 #[should_panic(expected = "range out of bounds")]
1414 fn copy_part_into_out_of_bounds_panics() {
1415 let mut buf = BytearrayRingbuffer::<64>::new();
1416 buf.push(b"hello").unwrap(); let p = buf.pop_front().unwrap();
1418 let mut out = [0u8; 2];
1419 p.copy_part_into(4..6, &mut out); }
1421
1422 #[test]
1425 fn copy_part_into_range_inclusive() {
1426 let mut buf = BytearrayRingbuffer::<64>::new();
1428 buf.push(b"abcde").unwrap();
1429 let p = buf.pop_front().unwrap();
1430 let mut out = [0u8; 3];
1431 p.copy_part_into(1..=3, &mut out);
1432 assert_eq!(&out, b"bcd");
1433 }
1434
1435 #[test]
1436 fn copy_part_into_range_from() {
1437 let mut buf = BytearrayRingbuffer::<64>::new();
1439 buf.push(b"abcde").unwrap();
1440 let p = buf.pop_front().unwrap();
1441 let mut out = [0u8; 2];
1442 p.copy_part_into(3.., &mut out);
1443 assert_eq!(&out, b"de");
1444 }
1445
1446 #[test]
1447 fn copy_part_into_range_to() {
1448 let mut buf = BytearrayRingbuffer::<64>::new();
1450 buf.push(b"abcde").unwrap();
1451 let p = buf.pop_front().unwrap();
1452 let mut out = [0u8; 3];
1453 p.copy_part_into(..3, &mut out);
1454 assert_eq!(&out, b"abc");
1455 }
1456
1457 #[test]
1458 fn copy_part_into_range_full() {
1459 let mut buf = BytearrayRingbuffer::<64>::new();
1461 buf.push(b"abcde").unwrap();
1462 let p = buf.pop_front().unwrap();
1463 let mut out = [0u8; 5];
1464 p.copy_part_into(.., &mut out);
1465 assert_eq!(&out, b"abcde");
1466 }
1467
1468 #[test]
1469 fn copy_part_into_range_to_inclusive() {
1470 let mut buf = BytearrayRingbuffer::<64>::new();
1472 buf.push(b"abcde").unwrap();
1473 let p = buf.pop_front().unwrap();
1474 let mut out = [0u8; 3];
1475 p.copy_part_into(..=2, &mut out);
1476 assert_eq!(&out, b"abc");
1477 }
1478
1479 #[test]
1482 fn packet_len_contiguous() {
1483 let mut buf = BytearrayRingbuffer::<64>::new();
1484 buf.push(b"hello").unwrap();
1485 let p = buf.pop_front().unwrap();
1486 assert_eq!(p.len(), 5);
1487 assert!(!p.is_empty());
1488 }
1489
1490 #[test]
1491 fn packet_len_wrapped() {
1492 const N: usize = 16;
1493 let mut buf = BytearrayRingbuffer::<N>::new();
1494 buf.head = 9;
1495 buf.tail = 9;
1496 buf.push(b"abcde").unwrap();
1497 let p = buf.pop_front().unwrap();
1498 assert!(!p.b.is_empty(), "expected a wrapped packet");
1499 assert_eq!(p.len(), 5);
1500 assert!(!p.is_empty());
1501 }
1502
1503 #[test]
1504 fn packet_len_empty_payload() {
1505 let mut buf = BytearrayRingbuffer::<64>::new();
1506 buf.push(b"").unwrap();
1507 let p = buf.pop_front().unwrap();
1508 assert_eq!(p.len(), 0);
1509 assert!(p.is_empty());
1510 }
1511}