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: core::ops::Range<usize>, buffer: &mut [u8]) {
75 assert_eq!(
76 buffer.len(),
77 range.len(),
78 "buffer length must equal range length"
79 );
80 assert!(range.end <= self.len(), "range out of bounds");
81
82 let start = range.start;
83 let end = range.end;
84 let a_len = self.a.len();
85 let mut buf_pos = 0;
86
87 if start < a_len {
89 let a_end = end.min(a_len);
90 let chunk = &self.a[start..a_end];
91 buffer[buf_pos..buf_pos + chunk.len()].copy_from_slice(chunk);
92 buf_pos += chunk.len();
93 }
94
95 if end > a_len {
97 let b_start = start.saturating_sub(a_len);
98 let b_end = end.saturating_sub(a_len);
99 let chunk = &self.b[b_start..b_end];
100 buffer[buf_pos..buf_pos + chunk.len()].copy_from_slice(chunk);
101 }
102 }
103
104 pub fn extend_into<E: Extend<u8>>(&self, target: &mut E) {
110 target.extend(self.a.iter().copied());
111 target.extend(self.b.iter().copied());
112 }
113}
114
115#[derive(Copy, Clone, Debug)]
121pub struct NotEnoughSpaceError;
122
123pub struct MultipartPush<'a, const N: usize> {
133 buf: &'a mut BytearrayRingbuffer<N>,
134 start: usize,
136 len: usize,
138 force: bool,
140 cancelled: bool,
142}
143
144impl<'a, const N: usize> MultipartPush<'a, N> {
145 pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
161 if data.is_empty() {
162 return Ok(());
163 }
164
165 if self.len + data.len() > N - 8 {
167 return Err(NotEnoughSpaceError);
168 }
169
170 let needed = data.len() + 4;
172
173 if self.force {
174 while self.buf.bytes_unused() < needed && !self.buf.empty() {
175 self.buf.pop_front();
176 }
177 if self.buf.bytes_unused() < needed {
178 return Err(NotEnoughSpaceError);
179 }
180 } else if self.buf.bytes_unused() < needed {
181 return Err(NotEnoughSpaceError);
182 }
183
184 write_wrapping(&mut self.buf.buffer, self.buf.head, data);
185 self.buf.head = add_wrapping::<N>(self.buf.head, data.len());
186 self.len += data.len();
187
188 Ok(())
189 }
190
191 pub fn cancel(mut self) {
196 self.cancelled = true;
197 self.buf.head = self.start;
198 }
200}
201
202impl<'a, const N: usize> Drop for MultipartPush<'a, N> {
203 fn drop(&mut self) {
204 if self.cancelled {
205 return;
206 }
207 let len_bytes: [u8; 4] = (self.len as u32).to_ne_bytes();
208 write_wrapping(&mut self.buf.buffer, self.start, &len_bytes);
210 write_wrapping(&mut self.buf.buffer, self.buf.head, &len_bytes);
212 self.buf.head = add_wrapping::<N>(self.buf.head, 4);
213 self.buf.count += 1;
214 }
215}
216
217impl<const N: usize> BytearrayRingbuffer<N> {
218 pub const fn new() -> Self {
224 assert!(N > 8);
225 assert!(N < (u32::MAX as usize));
226 Self {
227 buffer: [0; N],
228 head: 0,
229 tail: 0,
230 count: 0,
231 }
232 }
233
234 pub const fn free(&self) -> usize {
239 self.bytes_unused().saturating_sub(8)
240 }
241
242 pub fn push(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
252 self._push(data, false)
253 }
254
255 pub fn push_force(&mut self, data: &[u8]) -> Result<(), NotEnoughSpaceError> {
264 self._push(data, true)
265 }
266
267 pub fn push_multipart(&mut self) -> Result<MultipartPush<'_, N>, NotEnoughSpaceError> {
278 if self.bytes_unused() < 8 {
280 return Err(NotEnoughSpaceError);
281 }
282 let start = self.head;
283 self.head = add_wrapping::<N>(self.head, 4);
284 Ok(MultipartPush {
285 buf: self,
286 start,
287 len: 0,
288 force: false,
289 cancelled: false,
290 })
291 }
292
293 pub fn push_multipart_force(&mut self) -> MultipartPush<'_, N> {
301 while self.bytes_unused() < 8 && !self.empty() {
303 self.pop_front();
304 }
305 let start = self.head;
306 self.head = add_wrapping::<N>(self.head, 4);
307 MultipartPush {
308 buf: self,
309 start,
310 len: 0,
311 force: true,
312 cancelled: false,
313 }
314 }
315
316 #[inline(always)]
318 pub const fn empty(&self) -> bool {
319 self.count == 0
320 }
321
322 const fn bytes_unused(&self) -> usize {
324 if self.empty() {
325 N
326 } else if self.head > self.tail {
327 N + self.tail - self.head
328 } else {
329 self.tail - self.head
330 }
331 }
332
333 fn _push(&mut self, data: &[u8], force: bool) -> Result<(), NotEnoughSpaceError> {
334 assert!(data.len() <= u32::MAX as usize);
335
336 if data.len() > N - 8 {
338 return Err(NotEnoughSpaceError);
339 }
340
341 if (data.len() + 8) > self.bytes_unused() {
343 if !force {
344 return Err(NotEnoughSpaceError);
345 }
346 while (data.len() + 8) > self.bytes_unused() {
347 self.pop_front();
348 }
349 }
350
351 let addr_a = self.head;
353 let addr_b = add_wrapping::<N>(self.head, 4);
354 let addr_c = add_wrapping::<N>(self.head, 4 + data.len());
355 let len_buffer: [u8; 4] = (data.len() as u32).to_ne_bytes();
356 write_wrapping(&mut self.buffer, addr_a, &len_buffer);
357 write_wrapping(&mut self.buffer, addr_b, data);
358 write_wrapping(&mut self.buffer, addr_c, &len_buffer);
359
360 self.head = add_wrapping::<N>(self.head, 8 + data.len());
361 self.count += 1;
362
363 Ok(())
364 }
365
366 pub fn pop_front(&mut self) -> Option<Packet<'_>> {
371 if self.empty() {
372 return None;
373 }
374 let mut len_buffer = [0; 4];
375 read_wrapping(&self.buffer, self.tail, &mut len_buffer);
376 let len = u32::from_ne_bytes(len_buffer) as usize;
377
378 let index_data = add_wrapping::<N>(self.tail, 4);
379 let len_a = (N - index_data).min(len);
380 let a = &self.buffer[index_data..index_data + len_a];
381 let b = if len_a == len {
382 &[]
383 } else {
384 &self.buffer[..len - len_a]
385 };
386
387 self.tail = add_wrapping::<N>(self.tail, len + 8);
388 self.count -= 1;
389 Some(Packet { a, b })
390 }
391
392 pub fn iter_backwards<'a>(&'a self) -> IterBackwards<'a, N> {
394 IterBackwards {
395 buffer: &self.buffer,
396 head: self.head,
397 count: self.count,
398 }
399 }
400
401 pub fn iter<'a>(&'a self) -> Iter<'a, N> {
403 Iter {
404 buffer: &self.buffer,
405 head: self.head,
406 tail: self.tail,
407 count: self.count,
408 }
409 }
410
411 #[inline(always)]
413 pub const fn count(&self) -> usize {
414 self.count
415 }
416
417 pub fn nth(&self, n: usize) -> Option<Packet<'_>> {
421 self.iter().nth(n)
422 }
423
424 pub fn nth_reverse(&self, n: usize) -> Option<Packet<'_>> {
428 self.iter_backwards().nth(n)
429 }
430
431 pub fn nth_contiguous(&mut self, mut n: usize) -> Option<&[u8]> {
439 if self.empty() || n >= self.count {
440 return None;
441 }
442
443 let mut tail = self.tail;
445 let len_data = loop {
446 let mut buf = [0u8; 4];
447 read_wrapping(&self.buffer, tail, &mut buf);
448 let len_data = u32::from_ne_bytes(buf) as usize;
449
450 if n == 0 {
451 break len_data;
452 }
453 n -= 1;
454
455 tail = add_wrapping::<N>(tail, len_data + 8);
456 };
457
458 let index_data = add_wrapping::<N>(tail, 4);
459
460 if index_data + len_data <= N {
462 return Some(&self.buffer[index_data..index_data + len_data]);
463 }
464
465 self.buffer.rotate_left(index_data);
467 self.tail = sub_wrapping::<N>(self.tail, index_data);
468 self.head = sub_wrapping::<N>(self.head, index_data);
469
470 Some(&self.buffer[..len_data])
471 }
472}
473
474pub struct IterBackwards<'a, const N: usize> {
476 buffer: &'a [u8; N],
477 head: usize,
478 count: usize,
479}
480
481impl<'a, const N: usize> Iterator for IterBackwards<'a, N> {
482 type Item = Packet<'a>;
483
484 fn next(&mut self) -> Option<Self::Item> {
485 if self.count == 0 {
486 return None;
487 }
488
489 let index_len = sub_wrapping::<N>(self.head, 4);
491 let mut buf = [0u8; 4];
492 read_wrapping(self.buffer, index_len, &mut buf);
493 let len_data = u32::from_ne_bytes(buf) as usize;
494 debug_assert!((len_data + 8) <= N);
495
496 #[cfg(test)]
497 {
498 let index_len = sub_wrapping::<N>(self.head, 8 + len_data);
499 let mut buf = [0u8; 4];
500 read_wrapping(self.buffer, index_len, &mut buf);
501 let len_2 = u32::from_ne_bytes(buf) as usize;
502 assert_eq!(len_data, len_2);
503 }
504
505 let index_data = sub_wrapping::<N>(self.head, 4 + len_data);
507 let first = (N - index_data).min(len_data);
508 let slice_a = &self.buffer[index_data..index_data + first];
509 let slice_b = if first < len_data {
510 &self.buffer[..len_data - first]
511 } else {
512 &[]
513 };
514
515 self.head = sub_wrapping::<N>(self.head, 8 + len_data);
516 self.count -= 1;
517
518 Some(Packet {
519 a: slice_a,
520 b: slice_b,
521 })
522 }
523}
524
525impl<const N: usize> Default for BytearrayRingbuffer<N> {
526 fn default() -> Self {
527 Self::new()
528 }
529}
530
531pub struct Iter<'a, const N: usize> {
533 buffer: &'a [u8; N],
534 head: usize,
535 tail: usize,
536 count: usize,
537}
538
539impl<'a, const N: usize> Iterator for Iter<'a, N> {
540 type Item = Packet<'a>;
541
542 fn next(&mut self) -> Option<Self::Item> {
543 if self.count == 0 {
544 return None;
545 }
546
547 let bytes_unused = if self.head > self.tail {
549 N + self.tail - self.head
550 } else {
551 self.tail - self.head
552 };
553 let bytes_occupied = N - bytes_unused;
554 debug_assert!(bytes_occupied >= 8);
555
556 let mut buf = [0u8; 4];
558 read_wrapping(self.buffer, self.tail, &mut buf);
559 let len_data = u32::from_ne_bytes(buf) as usize;
560 debug_assert!((len_data + 8) <= N);
561 debug_assert!((len_data + 8) <= bytes_occupied);
562
563 let index_data = add_wrapping::<N>(self.tail, 4);
565 let first = (N - index_data).min(len_data);
566 let slice_a = &self.buffer[index_data..index_data + first];
567 let slice_b = if first < len_data {
568 &self.buffer[..len_data - first]
569 } else {
570 &[]
571 };
572
573 self.tail = add_wrapping::<N>(self.tail, 8 + len_data);
574 self.count -= 1;
575
576 Some(Packet {
577 a: slice_a,
578 b: slice_b,
579 })
580 }
581}
582
583fn add_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
584 debug_assert!(addr < N);
585 debug_assert!(offset <= N);
586 let s = addr + offset;
587 if s < N { s } else { s - N }
588}
589
590fn sub_wrapping<const N: usize>(addr: usize, offset: usize) -> usize {
591 debug_assert!(addr < N);
592 debug_assert!(offset <= N);
593 if addr >= offset {
594 addr - offset
595 } else {
596 N + addr - offset
597 }
598}
599
600fn write_wrapping(buffer: &mut [u8], index: usize, data: &[u8]) {
602 let first = (buffer.len() - index).min(data.len());
603 buffer[index..index + first].copy_from_slice(&data[..first]);
604 if first < data.len() {
605 buffer[..data.len() - first].copy_from_slice(&data[first..]);
606 }
607}
608
609fn read_wrapping(buffer: &[u8], index: usize, data: &mut [u8]) {
611 let first = (buffer.len() - index).min(data.len());
612 data[..first].copy_from_slice(&buffer[index..index + first]);
613 if first < data.len() {
614 let remaining = data.len() - first;
615 data[first..].copy_from_slice(&buffer[..remaining]);
616 }
617}
618
619#[cfg(test)]
620mod tests {
621 use std::collections::VecDeque;
622
623 use super::BytearrayRingbuffer;
624
625 #[test]
626 fn push_some_packets() {
627 const N: usize = 64;
628 for start_offset in 0..N {
629 let mut buf = BytearrayRingbuffer::<N>::new();
630 buf.head = start_offset;
631 buf.tail = start_offset;
632
633 let free = 64 - 8;
634 assert_eq!(buf.free(), free);
635
636 buf.push(b"01234567").unwrap();
637 let free = free - 8 - 8;
638 assert_eq!(buf.free(), free);
639
640 buf.push(b"").unwrap();
641 let free = free - 8;
642 assert_eq!(buf.free(), free);
643
644 buf.push(b"0123").unwrap();
645 let free = free - 4 - 8;
646 assert_eq!(buf.free(), free);
647
648 buf.push(b"0123").unwrap();
649 let free = free - 4 - 8;
650 assert_eq!(buf.free(), free);
651 }
652 }
653
654 #[test]
655 fn push_force() {
656 let mut buf = BytearrayRingbuffer::<16>::new();
657 assert_eq!(buf.bytes_unused(), 16);
658
659 let a = b"012345";
660 let b = b"0123";
661
662 buf.push(a).unwrap();
663 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
664
665 buf.push(b).unwrap_err();
666 assert_eq!(buf.bytes_unused(), 16 - a.len() - 8);
667
668 buf.push_force(b).unwrap();
669 assert_eq!(buf.bytes_unused(), 16 - b.len() - 8);
670 }
671
672 #[test]
673 fn push_all_data_lengths() {
674 for n in 0..(32 - 8) {
675 let mut buf = BytearrayRingbuffer::<32>::new();
676 let data = (0..n as u8).collect::<Vec<u8>>();
678
679 assert_eq!(buf.free(), 32 - 8);
680 buf.push(&data).unwrap();
681 assert_eq!(buf.free(), (32usize - 16).saturating_sub(n));
682 }
683 }
684
685 #[test]
686 fn push_sum_of_lengths_possible() {
687 let mut buf = BytearrayRingbuffer::<32>::new();
688 assert_eq!(buf.free(), 32 - 8);
690 buf.push(b"01234567").unwrap();
691 assert_eq!(buf.free(), 32 - 8 - 16);
692 buf.push(b"01234567").unwrap();
693 assert_eq!(buf.free(), 0);
694 }
695
696 #[test]
697 fn push_pop() {
698 const N: usize = 64;
699 for start_offset in 0..N {
700 eprintln!("--------------");
701 let mut buf = BytearrayRingbuffer::<N>::new();
702 buf.head = start_offset;
703 buf.tail = start_offset;
704
705 let data = b"01234567";
706 buf.push(data).unwrap();
707
708 let p = buf.pop_front().unwrap();
709 let mut out = Vec::new();
710 out.extend_from_slice(p.a);
711 out.extend_from_slice(p.b);
712
713 dbg!(out.as_slice());
714 assert!(data == out.as_slice());
715
716 assert_eq!(buf.head, buf.tail);
717 assert_eq!(buf.bytes_unused(), N);
718 }
719 }
720
721 #[test]
722 fn push_read_back() {
723 let data = [b"hello world" as &[u8], b"", b"test"];
724
725 const N: usize = 64;
726 for start_offset in 0..N {
727 let mut buf = BytearrayRingbuffer::<N>::new();
728 buf.head = start_offset;
729 buf.tail = start_offset;
730
731 for &d in &data {
732 buf.push(d).unwrap();
733 }
734
735 let mut it = buf.iter();
737 for &d in data.iter() {
738 let p = it.next().unwrap();
739 let mut ab = Vec::new();
740 ab.extend_from_slice(p.a);
741 ab.extend_from_slice(p.b);
742 let ab = ab.as_slice();
743 assert_eq!(d, ab);
744 }
745 assert_eq!(it.next(), None);
746
747 let mut it = buf.iter_backwards();
749 for &d in data.iter().rev() {
750 let p = it.next().unwrap();
751 let mut ab = Vec::new();
752 ab.extend_from_slice(p.a);
753 ab.extend_from_slice(p.b);
754 let ab = ab.as_slice();
755 assert_eq!(d, ab);
756 }
757 assert_eq!(it.next(), None);
758 }
759 }
760
761 #[test]
762 fn push_count() {
763 let mut buf = BytearrayRingbuffer::<64>::new();
764 buf.push(b"1234").unwrap();
765 assert_eq!(buf.count(), 1);
766 buf.push(b"1234").unwrap();
767 assert_eq!(buf.count(), 2);
768 buf.push(b"1234").unwrap();
769 assert_eq!(buf.count(), 3);
770 }
771
772 fn test_with_readback<const N: usize>(words: &[&'static str]) {
773 eprintln!("--------------------------");
774 let mut buf = BytearrayRingbuffer::<N>::new();
775 let mut current_words = VecDeque::new();
776 for &word in words {
777 eprintln!("adding {word:?}");
778 let word = word.to_owned();
779 let current_bytes: usize = current_words.iter().map(|w: &String| w.len() + 8).sum();
780 if current_bytes + 8 + word.len() > N {
781 current_words.pop_front();
782 }
783
784 buf.push_force(word.as_bytes()).unwrap();
785 current_words.push_back(word);
786
787 for (p, word) in buf.iter_backwards().zip(current_words.iter().rev()) {
788 eprintln!("read back {word:?}");
789 let mut st = String::new();
790 st.push_str(core::str::from_utf8(p.a).unwrap());
791 st.push_str(core::str::from_utf8(p.b).unwrap());
792 assert_eq!(st, *word);
793 }
794 }
795 }
796
797 #[test]
798 fn readback_various() {
799 test_with_readback::<32>(&["ab", "123", "hello", "world"]);
800 test_with_readback::<32>(&["", "", "a", "", "", ""]);
801 test_with_readback::<32>(&["", "", "ab", "", "", ""]);
802 test_with_readback::<32>(&["", "", "abc", "", "", ""]);
803 test_with_readback::<32>(&["", "", "abcd", "", "", ""]);
804 test_with_readback::<32>(&["", "", "abcde", "", "", ""]);
805
806 test_with_readback::<24>(&["0", "1", "a", "2", "3", "4"]);
807 test_with_readback::<24>(&["0", "1", "ab", "2", "3", "4"]);
808 test_with_readback::<24>(&["0", "1", "abc", "2", "3", "4"]);
809 test_with_readback::<24>(&["0", "1", "abcd", "2", "3", "4"]);
810 test_with_readback::<24>(&["0", "1", "abcde", "2", "3", "4"]);
811 test_with_readback::<24>(&["0", "1", "abcdef", "2", "3", "4"]);
812 test_with_readback::<24>(&["0", "1", "abcdefg", "2", "3", "4"]);
813 }
814
815 #[test]
816 fn nth_contiguous_out_of_range_returns_none() {
817 let mut buf = BytearrayRingbuffer::<64>::new();
818 buf.push(b"hello").unwrap();
819 assert_eq!(buf.count(), 1);
820
821 assert_eq!(buf.nth_contiguous(1), None);
822 }
823
824 #[test]
825 fn rotate_contiguous() {
826 const N: usize = 48;
827 let data: [&[u8]; _] = [b"012345", b"hello world", b"xyz"];
828
829 for offset in 0..N {
830 let mut buf = BytearrayRingbuffer::<N>::new();
831 buf.head = offset;
832 buf.tail = offset;
833
834 for &d in &data {
835 buf.push(d).unwrap();
836 }
837
838 let read = buf.nth_contiguous(1).unwrap();
839 assert_eq!(data[1], read);
840
841 for (&r, p) in data.iter().zip(buf.iter()) {
843 let mut out = Vec::new();
844 out.extend_from_slice(p.a);
845 out.extend_from_slice(p.b);
846 assert_eq!(out.as_slice(), r);
847 }
848 }
849 }
850
851 fn collect(a: &[u8], b: &[u8]) -> Vec<u8> {
854 let mut v = Vec::new();
855 v.extend_from_slice(a);
856 v.extend_from_slice(b);
857 v
858 }
859
860 #[test]
861 fn multipart_normal_fits() {
862 const N: usize = 64;
863 for offset in 0..N {
864 let mut buf = BytearrayRingbuffer::<N>::new();
865 buf.head = offset;
866 buf.tail = offset;
867
868 let mut mp = buf.push_multipart().unwrap();
869 mp.push(b"hello").unwrap();
870 mp.push(b" ").unwrap();
871 mp.push(b"world").unwrap();
872 drop(mp);
873
874 assert_eq!(buf.count(), 1);
875 let p = buf.pop_front().unwrap();
876 assert_eq!(collect(p.a, p.b), b"hello world");
877 assert_eq!(buf.count(), 0);
878 }
879 }
880
881 #[test]
882 fn multipart_empty_packet() {
883 let mut buf = BytearrayRingbuffer::<64>::new();
884 let mp = buf.push_multipart().unwrap();
885 drop(mp); assert_eq!(buf.count(), 1);
887 let p = buf.pop_front().unwrap();
888 assert_eq!(collect(p.a, p.b), b"");
889 }
890
891 #[test]
892 fn multipart_normal_overflow_returns_err() {
893 let mut buf = BytearrayRingbuffer::<24>::new();
898 buf.push(b"").unwrap(); let mut mp = buf.push_multipart().unwrap();
901 mp.push(b"abcd").unwrap(); let err = mp.push(b"12345"); assert!(err.is_err());
904
905 drop(mp);
907 assert_eq!(buf.count(), 2);
908 let p = buf.nth(1).unwrap();
910 assert_eq!(collect(p.a, p.b), b"abcd");
911 }
912
913 #[test]
914 fn multipart_cancel_normal_mode() {
915 let mut buf = BytearrayRingbuffer::<64>::new();
916 let original_unused = buf.bytes_unused();
917 let original_count = buf.count();
918
919 let mut mp = buf.push_multipart().unwrap();
920 mp.push(b"data that will be discarded").unwrap();
921 mp.cancel();
922
923 assert_eq!(buf.count(), original_count);
924 assert_eq!(buf.bytes_unused(), original_unused);
925 }
926
927 #[test]
928 fn multipart_normal_no_room_for_start() {
929 let mut buf = BytearrayRingbuffer::<24>::new();
931 buf.push(&[0u8; 16]).unwrap(); assert_eq!(buf.bytes_unused(), 0);
933 assert!(buf.push_multipart().is_err());
934 }
935
936 #[test]
937 fn multipart_force_drops_old_packets() {
938 let mut buf = BytearrayRingbuffer::<24>::new();
943 buf.push(b"AA").unwrap(); buf.push(b"BB").unwrap(); assert_eq!(buf.count(), 2);
946
947 let mut mp = buf.push_multipart_force();
948 mp.push(b"hello world").unwrap(); drop(mp);
950
951 assert_eq!(buf.count(), 1);
952 let p = buf.pop_front().unwrap();
953 assert_eq!(collect(p.a, p.b), b"hello world");
954 }
955
956 #[test]
957 fn multipart_force_cancel_drops_are_permanent() {
958 let mut buf = BytearrayRingbuffer::<24>::new();
960 buf.push(b"AA").unwrap();
961 buf.push(b"BB").unwrap();
962 let count_before = buf.count(); let mut mp = buf.push_multipart_force();
965 mp.push(b"hello world").unwrap(); mp.cancel(); assert!(buf.count() < count_before);
970 assert_eq!(buf.count(), 0);
971 }
972
973 #[test]
974 fn multipart_push_after_multipart() {
975 let mut buf = BytearrayRingbuffer::<64>::new();
976 {
977 let mut mp = buf.push_multipart().unwrap();
978 mp.push(b"first").unwrap();
979 }
980 buf.push(b"second").unwrap();
981
982 assert_eq!(buf.count(), 2);
983 let p = buf.nth(0).unwrap();
984 assert_eq!(collect(p.a, p.b), b"first");
985 let p = buf.nth(1).unwrap();
986 assert_eq!(collect(p.a, p.b), b"second");
987 }
988
989 #[test]
990 fn multipart_force_max_payload() {
991 const N: usize = 32;
993 let mut buf = BytearrayRingbuffer::<N>::new();
994 buf.push(b"old").unwrap(); let payload: Vec<u8> = (0..((N - 8) as u8)).collect();
997 let mut mp = buf.push_multipart_force();
998 mp.push(&payload).unwrap();
999 drop(mp);
1000
1001 assert_eq!(buf.count(), 1);
1002 let p = buf.pop_front().unwrap();
1003 assert_eq!(collect(p.a, p.b), payload);
1004 }
1005
1006 #[test]
1007 fn multipart_wraparound_all_offsets() {
1008 const N: usize = 48;
1009 for offset in 0..N {
1010 let mut buf = BytearrayRingbuffer::<N>::new();
1011 buf.head = offset;
1012 buf.tail = offset;
1013
1014 buf.push(b"prefix").unwrap();
1016
1017 let mut mp = buf.push_multipart().unwrap();
1019 mp.push(b"foo").unwrap();
1020 mp.push(b"bar").unwrap();
1021 drop(mp);
1022
1023 buf.push(b"suffix").unwrap();
1025
1026 assert_eq!(buf.count(), 3);
1027 let p = buf.nth(0).unwrap();
1028 assert_eq!(collect(p.a, p.b), b"prefix");
1029 let p = buf.nth(1).unwrap();
1030 assert_eq!(collect(p.a, p.b), b"foobar");
1031 let p = buf.nth(2).unwrap();
1032 assert_eq!(collect(p.a, p.b), b"suffix");
1033 }
1034 }
1035
1036 #[test]
1039 fn pop_front_empty_returns_none() {
1040 let mut buf = BytearrayRingbuffer::<32>::new();
1041 assert_eq!(buf.pop_front(), None);
1042 }
1043
1044 #[test]
1045 fn empty_and_count_lifecycle() {
1046 let mut buf = BytearrayRingbuffer::<32>::new();
1047
1048 assert!(buf.empty());
1050 assert_eq!(buf.count(), 0);
1051
1052 buf.push(b"a").unwrap();
1053 assert!(!buf.empty());
1054 assert_eq!(buf.count(), 1);
1055
1056 buf.push(b"b").unwrap();
1057 assert!(!buf.empty());
1058 assert_eq!(buf.count(), 2);
1059
1060 buf.pop_front().unwrap();
1061 assert!(!buf.empty());
1062 assert_eq!(buf.count(), 1);
1063
1064 buf.pop_front().unwrap();
1065 assert!(buf.empty());
1066 assert_eq!(buf.count(), 0);
1067
1068 assert_eq!(buf.pop_front(), None);
1070 }
1071
1072 #[test]
1073 fn default_creates_empty_buffer() {
1074 let buf = BytearrayRingbuffer::<32>::default();
1075 assert!(buf.empty());
1076 assert_eq!(buf.count(), 0);
1077 assert_eq!(buf.free(), 32 - 8);
1078 }
1079
1080 #[test]
1083 fn push_oversized_returns_error() {
1084 let mut buf = BytearrayRingbuffer::<16>::new();
1085 let oversized = [0u8; 9];
1087 assert!(buf.push(&oversized).is_err());
1088 assert!(buf.empty());
1090 }
1091
1092 #[test]
1093 fn push_force_oversized_returns_error() {
1094 let mut buf = BytearrayRingbuffer::<16>::new();
1095 let oversized = [0u8; 9];
1097 assert!(buf.push_force(&oversized).is_err());
1098 assert!(buf.empty());
1099 }
1100
1101 #[test]
1104 fn iter_empty_buffer() {
1105 let buf = BytearrayRingbuffer::<32>::new();
1106 assert_eq!(buf.iter().next(), None);
1107 }
1108
1109 #[test]
1110 fn iter_backwards_empty_buffer() {
1111 let buf = BytearrayRingbuffer::<32>::new();
1112 assert_eq!(buf.iter_backwards().next(), None);
1113 }
1114
1115 #[test]
1118 fn nth_empty_returns_none() {
1119 let buf = BytearrayRingbuffer::<32>::new();
1120 assert_eq!(buf.nth(0), None);
1121 }
1122
1123 #[test]
1124 fn nth_out_of_bounds_returns_none() {
1125 let buf = {
1126 let mut b = BytearrayRingbuffer::<64>::new();
1127 b.push(b"x").unwrap();
1128 b.push(b"y").unwrap();
1129 b
1130 };
1131 assert_eq!(buf.nth(2), None);
1132 assert_eq!(buf.nth(100), None);
1133 }
1134
1135 #[test]
1136 fn nth_reverse_basic() {
1137 let mut buf = BytearrayRingbuffer::<64>::new();
1138 buf.push(b"oldest").unwrap();
1139 buf.push(b"middle").unwrap();
1140 buf.push(b"newest").unwrap();
1141
1142 let p = buf.nth_reverse(0).unwrap();
1143 assert_eq!(collect(p.a, p.b), b"newest");
1144 let p = buf.nth_reverse(1).unwrap();
1145 assert_eq!(collect(p.a, p.b), b"middle");
1146 let p = buf.nth_reverse(2).unwrap();
1147 assert_eq!(collect(p.a, p.b), b"oldest");
1148 }
1149
1150 #[test]
1151 fn nth_reverse_empty_returns_none() {
1152 let buf = BytearrayRingbuffer::<32>::new();
1153 assert_eq!(buf.nth_reverse(0), None);
1154 }
1155
1156 #[test]
1157 fn nth_reverse_out_of_bounds_returns_none() {
1158 let buf = {
1159 let mut b = BytearrayRingbuffer::<64>::new();
1160 b.push(b"only").unwrap();
1161 b
1162 };
1163 assert_eq!(buf.nth_reverse(1), None);
1164 assert_eq!(buf.nth_reverse(99), None);
1165 }
1166
1167 #[test]
1170 fn nth_contiguous_empty_returns_none() {
1171 let mut buf = BytearrayRingbuffer::<32>::new();
1172 assert_eq!(buf.nth_contiguous(0), None);
1173 }
1174
1175 #[test]
1176 fn nth_contiguous_n0_no_rotation() {
1177 let mut buf = BytearrayRingbuffer::<64>::new();
1179 buf.push(b"hello").unwrap();
1180 buf.push(b"world").unwrap();
1181 let slice = buf.nth_contiguous(0).unwrap();
1184 assert_eq!(slice, b"hello");
1185 let slice = buf.nth_contiguous(1).unwrap();
1187 assert_eq!(slice, b"world");
1188 }
1189
1190 #[test]
1191 fn nth_contiguous_called_twice() {
1192 const N: usize = 48;
1195 for offset in 0..N {
1196 let mut buf = BytearrayRingbuffer::<N>::new();
1197 buf.head = offset;
1198 buf.tail = offset;
1199
1200 buf.push(b"alpha").unwrap();
1201 buf.push(b"beta").unwrap();
1202 buf.push(b"gamma").unwrap();
1203
1204 let slice = buf.nth_contiguous(1).unwrap();
1206 assert_eq!(slice, b"beta");
1207
1208 let slice = buf.nth_contiguous(2).unwrap();
1210 assert_eq!(slice, b"gamma");
1211
1212 let payloads: Vec<Vec<u8>> = buf
1214 .iter()
1215 .map(|p| {
1216 let mut v = p.a.to_vec();
1217 v.extend_from_slice(p.b);
1218 v
1219 })
1220 .collect();
1221 assert_eq!(payloads[0], b"alpha");
1222 assert_eq!(payloads[1], b"beta");
1223 assert_eq!(payloads[2], b"gamma");
1224 }
1225 }
1226
1227 #[test]
1230 fn free_returns_zero_when_full() {
1231 let mut buf = BytearrayRingbuffer::<32>::new();
1233 buf.push(b"01234567").unwrap();
1234 buf.push(b"01234567").unwrap();
1235 assert_eq!(buf.free(), 0);
1236 assert!(buf.push(b"x").is_err());
1238 }
1239
1240 #[test]
1243 fn push_force_drops_multiple_packets() {
1244 let mut buf = BytearrayRingbuffer::<32>::new();
1249 buf.push(b"a").unwrap();
1250 buf.push(b"b").unwrap();
1251 buf.push(b"c").unwrap();
1252 assert_eq!(buf.count(), 3);
1253
1254 let payload = b"0123456789abcdef"; buf.push_force(payload).unwrap();
1256
1257 assert_eq!(buf.count(), 1);
1259 let p = buf.pop_front().unwrap();
1260 assert_eq!(collect(p.a, p.b), payload);
1261 }
1262
1263 #[test]
1266 fn multipart_push_total_exceeds_max_returns_error() {
1267 let mut buf = BytearrayRingbuffer::<16>::new();
1270 let mut mp = buf.push_multipart().unwrap();
1271 mp.push(b"abcde").unwrap(); let err = mp.push(b"wxyz"); assert!(err.is_err());
1274 drop(mp); assert_eq!(buf.count(), 1);
1276 let p = buf.pop_front().unwrap();
1277 assert_eq!(collect(p.a, p.b), b"abcde");
1278 }
1279
1280 #[test]
1283 fn multipart_force_full_buffer_start() {
1284 let mut buf = BytearrayRingbuffer::<16>::new();
1287 buf.push(&[0u8; 8]).unwrap(); assert_eq!(buf.bytes_unused(), 0);
1289
1290 let mut mp = buf.push_multipart_force();
1291 mp.push(b"hi").unwrap();
1292 drop(mp);
1293
1294 assert_eq!(buf.count(), 1);
1295 let p = buf.pop_front().unwrap();
1296 assert_eq!(collect(p.a, p.b), b"hi");
1297 }
1298
1299 #[test]
1302 fn copy_into_contiguous() {
1303 let mut buf = BytearrayRingbuffer::<64>::new();
1305 buf.push(b"hello").unwrap();
1306 let p = buf.pop_front().unwrap();
1307 assert!(p.b.is_empty());
1308 let mut out = [0u8; 5];
1309 p.copy_into(&mut out);
1310 assert_eq!(&out, b"hello");
1311 }
1312
1313 #[test]
1314 fn copy_into_wrapped() {
1315 const N: usize = 16;
1317 let mut buf = BytearrayRingbuffer::<N>::new();
1318 buf.head = 9;
1319 buf.tail = 9;
1320 buf.push(b"abcde").unwrap();
1321 let p = buf.pop_front().unwrap();
1322 assert!(!p.b.is_empty(), "expected a wrapped packet");
1323 let mut out = [0u8; 5];
1324 p.copy_into(&mut out);
1325 assert_eq!(&out, b"abcde");
1326 }
1327
1328 #[test]
1329 #[should_panic(expected = "buffer length must equal packet length")]
1330 fn copy_into_wrong_length_panics() {
1331 let mut buf = BytearrayRingbuffer::<64>::new();
1332 buf.push(b"hello").unwrap();
1333 let p = buf.pop_front().unwrap();
1334 let mut out = [0u8; 4]; p.copy_into(&mut out);
1336 }
1337
1338 #[test]
1341 fn copy_part_into_in_a() {
1342 const N: usize = 16;
1345 let mut buf = BytearrayRingbuffer::<N>::new();
1346 buf.head = 9;
1347 buf.tail = 9;
1348 buf.push(b"abcde").unwrap();
1349 let p = buf.pop_front().unwrap();
1350 assert!(!p.b.is_empty(), "expected a wrapped packet");
1351 let mut out = [0u8; 2];
1352 p.copy_part_into(0..2, &mut out);
1353 assert_eq!(&out, b"ab");
1354 }
1355
1356 #[test]
1357 fn copy_part_into_in_b() {
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 let mut out = [0u8; 1];
1367 p.copy_part_into(3..4, &mut out);
1368 assert_eq!(&out, b"d");
1369 }
1370
1371 #[test]
1372 fn copy_part_into_spanning() {
1373 const N: usize = 16;
1376 let mut buf = BytearrayRingbuffer::<N>::new();
1377 buf.head = 9;
1378 buf.tail = 9;
1379 buf.push(b"abcde").unwrap();
1380 let p = buf.pop_front().unwrap();
1381 let mut out = [0u8; 3];
1382 p.copy_part_into(1..4, &mut out);
1383 assert_eq!(&out, b"bcd");
1384 }
1385
1386 #[test]
1387 #[should_panic(expected = "buffer length must equal range length")]
1388 fn copy_part_into_wrong_buffer_length_panics() {
1389 let mut buf = BytearrayRingbuffer::<64>::new();
1390 buf.push(b"hello").unwrap();
1391 let p = buf.pop_front().unwrap();
1392 let mut out = [0u8; 3]; p.copy_part_into(0..2, &mut out);
1394 }
1395
1396 #[test]
1397 #[should_panic(expected = "range out of bounds")]
1398 fn copy_part_into_out_of_bounds_panics() {
1399 let mut buf = BytearrayRingbuffer::<64>::new();
1400 buf.push(b"hello").unwrap(); let p = buf.pop_front().unwrap();
1402 let mut out = [0u8; 2];
1403 p.copy_part_into(4..6, &mut out); }
1405
1406 #[test]
1409 fn packet_len_contiguous() {
1410 let mut buf = BytearrayRingbuffer::<64>::new();
1411 buf.push(b"hello").unwrap();
1412 let p = buf.pop_front().unwrap();
1413 assert_eq!(p.len(), 5);
1414 assert!(!p.is_empty());
1415 }
1416
1417 #[test]
1418 fn packet_len_wrapped() {
1419 const N: usize = 16;
1420 let mut buf = BytearrayRingbuffer::<N>::new();
1421 buf.head = 9;
1422 buf.tail = 9;
1423 buf.push(b"abcde").unwrap();
1424 let p = buf.pop_front().unwrap();
1425 assert!(!p.b.is_empty(), "expected a wrapped packet");
1426 assert_eq!(p.len(), 5);
1427 assert!(!p.is_empty());
1428 }
1429
1430 #[test]
1431 fn packet_len_empty_payload() {
1432 let mut buf = BytearrayRingbuffer::<64>::new();
1433 buf.push(b"").unwrap();
1434 let p = buf.pop_front().unwrap();
1435 assert_eq!(p.len(), 0);
1436 assert!(p.is_empty());
1437 }
1438}