1use crate::error::StreamError;
44use std::cell::UnsafeCell;
45use std::mem::MaybeUninit;
46use std::sync::atomic::{AtomicUsize, Ordering};
47use std::sync::Arc;
48
49pub struct SpscRing<T, const N: usize> {
64 buf: Box<[UnsafeCell<MaybeUninit<T>>; N]>,
65 head: AtomicUsize,
66 tail: AtomicUsize,
67}
68
69unsafe impl<T: Send, const N: usize> Send for SpscRing<T, N> {}
72
73impl<T, const N: usize> SpscRing<T, N> {
74 const _ASSERT_N_GE_2: () = assert!(N >= 2, "SpscRing: N must be >= 2 (capacity = N-1)");
80
81 const _ASSERT_N_POW2: () = assert!(
86 N.is_power_of_two(),
87 "SpscRing: N must be a power of two (e.g. 4, 8, 16, 32, 64, 128, 256, 512, 1024)"
88 );
89
90 pub fn new() -> Self {
92 let _ = Self::_ASSERT_N_GE_2;
94 let _ = Self::_ASSERT_N_POW2;
95 let buf: Vec<UnsafeCell<MaybeUninit<T>>> =
96 (0..N).map(|_| UnsafeCell::new(MaybeUninit::uninit())).collect();
97 let buf: Box<[UnsafeCell<MaybeUninit<T>>; N]> = buf
98 .try_into()
99 .unwrap_or_else(|_| unreachable!("length is exactly N"));
100 Self {
101 buf,
102 head: AtomicUsize::new(0),
103 tail: AtomicUsize::new(0),
104 }
105 }
106
107 #[inline]
109 pub fn is_empty(&self) -> bool {
110 self.head.load(Ordering::Acquire) == self.tail.load(Ordering::Acquire)
111 }
112
113 #[inline]
115 pub fn is_full(&self) -> bool {
116 let head = self.head.load(Ordering::Acquire);
117 let tail = self.tail.load(Ordering::Acquire);
118 tail.wrapping_sub(head) >= N - 1
119 }
120
121 #[inline]
123 pub fn len(&self) -> usize {
124 let head = self.head.load(Ordering::Acquire);
125 let tail = self.tail.load(Ordering::Acquire);
126 tail.wrapping_sub(head)
127 }
128
129 #[inline]
131 pub fn capacity(&self) -> usize {
132 N - 1
133 }
134
135 #[inline]
142 #[must_use = "dropping a push result silently discards the item when full"]
143 pub fn push(&self, item: T) -> Result<(), StreamError> {
144 let head = self.head.load(Ordering::Acquire);
145 let tail = self.tail.load(Ordering::Relaxed);
146 if tail.wrapping_sub(head) >= N - 1 {
147 return Err(StreamError::RingBufferFull { capacity: N - 1 });
148 }
149 let slot = tail & (N - 1);
152 unsafe {
155 (*self.buf[slot].get()).write(item);
156 }
157 self.tail.store(tail.wrapping_add(1), Ordering::Release);
158 Ok(())
159 }
160
161 #[inline]
168 #[must_use = "dropping a pop result discards the dequeued item"]
169 pub fn pop(&self) -> Result<T, StreamError> {
170 let tail = self.tail.load(Ordering::Acquire);
171 let head = self.head.load(Ordering::Relaxed);
172 if head == tail {
173 return Err(StreamError::RingBufferEmpty);
174 }
175 let slot = head & (N - 1);
176 let item = unsafe { (*self.buf[slot].get()).assume_init_read() };
180 self.head.store(head.wrapping_add(1), Ordering::Release);
181 Ok(item)
182 }
183
184 #[inline]
194 pub fn try_push_or_drop(&self, item: T) -> bool {
195 self.push(item).is_ok()
196 }
197
198 pub fn peek_clone(&self) -> Option<T>
205 where
206 T: Clone,
207 {
208 let tail = self.tail.load(Ordering::Acquire);
209 let head = self.head.load(Ordering::Relaxed);
210 if head == tail {
211 return None;
212 }
213 let slot = head & (N - 1);
214 Some(unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone())
218 }
219
220 pub fn peek_all(&self) -> Vec<T>
228 where
229 T: Clone,
230 {
231 let head = self.head.load(Ordering::Acquire);
232 let tail = self.tail.load(Ordering::Acquire);
233 let count = tail.wrapping_sub(head);
234 let mut out = Vec::with_capacity(count);
235 for i in 0..count {
236 let slot = head.wrapping_add(i) & (N - 1);
237 out.push(unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone());
240 }
241 out
242 }
243
244 pub fn peek_newest(&self) -> Option<T>
251 where
252 T: Copy,
253 {
254 self.peek_back().copied()
255 }
256
257 pub fn peek_oldest(&self) -> Option<T>
262 where
263 T: Copy,
264 {
265 self.first()
266 }
267
268 pub fn fill_ratio(&self) -> f64 {
272 let cap = self.capacity();
273 if cap == 0 {
274 return 0.0;
275 }
276 self.len() as f64 / cap as f64
277 }
278
279 pub fn has_capacity(&self, n: usize) -> bool {
283 n <= self.remaining_capacity()
284 }
285
286 pub fn utilization_pct(&self) -> f64 {
290 self.fill_ratio() * 100.0
291 }
292
293 #[inline]
295 pub fn remaining_capacity(&self) -> usize {
296 self.capacity().saturating_sub(self.len())
297 }
298
299 pub fn is_nearly_full(&self, threshold: f64) -> bool {
303 self.fill_ratio() >= threshold
304 }
305
306 pub fn first(&self) -> Option<T>
310 where
311 T: Copy,
312 {
313 self.peek_front().copied()
314 }
315
316 pub fn peek_front(&self) -> Option<&T> {
320 let head = self.head.load(Ordering::Acquire);
321 let tail = self.tail.load(Ordering::Acquire);
322 if head == tail {
323 return None;
324 }
325 Some(unsafe { (*self.buf[head & (N - 1)].get()).assume_init_ref() })
327 }
328
329 pub fn peek_back(&self) -> Option<&T> {
333 let head = self.head.load(Ordering::Acquire);
334 let tail = self.tail.load(Ordering::Acquire);
335 if head == tail {
336 return None;
337 }
338 let back = tail.wrapping_sub(1);
339 Some(unsafe { (*self.buf[back & (N - 1)].get()).assume_init_ref() })
341 }
342
343 pub fn drain(&self) -> Vec<T> {
350 let mut out = Vec::with_capacity(self.len());
351 while let Ok(item) = self.pop() {
352 out.push(item);
353 }
354 out
355 }
356
357 pub fn drain_into(&self, buf: &mut Vec<T>) {
366 while let Ok(item) = self.pop() {
367 buf.push(item);
368 }
369 }
370
371 pub fn to_vec_cloned(&self) -> Vec<T>
377 where
378 T: Clone,
379 {
380 let head = self.head.load(Ordering::Acquire);
381 let tail = self.tail.load(Ordering::Acquire);
382 let len = tail.wrapping_sub(head);
383 let mut out = Vec::with_capacity(len);
384 for i in 0..len {
385 let slot = head.wrapping_add(i) & (N - 1);
386 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
388 out.push(item.clone());
389 }
390 out
391 }
392
393 pub fn to_vec_sorted(&self) -> Vec<T>
399 where
400 T: Clone + Ord,
401 {
402 let mut v = self.to_vec_cloned();
403 v.sort();
404 v
405 }
406
407 pub fn min_cloned(&self) -> Option<T>
413 where
414 T: Clone + Ord,
415 {
416 let head = self.head.load(Ordering::Acquire);
417 let tail = self.tail.load(Ordering::Acquire);
418 let len = tail.wrapping_sub(head);
419 if len == 0 {
420 return None;
421 }
422 let mut min_val = unsafe { (*self.buf[head & (N - 1)].get()).assume_init_ref() }.clone();
423 for i in 1..len {
424 let slot = head.wrapping_add(i) & (N - 1);
425 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
426 if item < &min_val {
427 min_val = item.clone();
428 }
429 }
430 Some(min_val)
431 }
432
433 pub fn max_cloned(&self) -> Option<T>
439 where
440 T: Clone + Ord,
441 {
442 let head = self.head.load(Ordering::Acquire);
443 let tail = self.tail.load(Ordering::Acquire);
444 let len = tail.wrapping_sub(head);
445 if len == 0 {
446 return None;
447 }
448 let mut max_val = unsafe { (*self.buf[head & (N - 1)].get()).assume_init_ref() }.clone();
449 for i in 1..len {
450 let slot = head.wrapping_add(i) & (N - 1);
451 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
452 if item > &max_val {
453 max_val = item.clone();
454 }
455 }
456 Some(max_val)
457 }
458
459 pub fn count_if<F>(&self, predicate: F) -> usize
465 where
466 F: Fn(&T) -> bool,
467 {
468 let head = self.head.load(Ordering::Acquire);
469 let tail = self.tail.load(Ordering::Acquire);
470 let len = tail.wrapping_sub(head);
471 let mut count = 0;
472 for i in 0..len {
473 let slot = head.wrapping_add(i) & (N - 1);
474 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
476 if predicate(item) {
477 count += 1;
478 }
479 }
480 count
481 }
482
483 pub fn peek_nth(&self, n: usize) -> Option<T>
489 where
490 T: Clone,
491 {
492 let head = self.head.load(Ordering::Acquire);
493 let tail = self.tail.load(Ordering::Acquire);
494 let len = tail.wrapping_sub(head);
495 if n >= len {
496 return None;
497 }
498 let slot = head.wrapping_add(n) & (N - 1);
499 Some(unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone())
501 }
502
503 pub fn min_cloned_by<F, K>(&self, key: F) -> Option<T>
509 where
510 T: Clone,
511 F: Fn(&T) -> K,
512 K: Ord,
513 {
514 let head = self.head.load(Ordering::Acquire);
515 let tail = self.tail.load(Ordering::Acquire);
516 let len = tail.wrapping_sub(head);
517 if len == 0 {
518 return None;
519 }
520 let first = unsafe { (*self.buf[head & (N - 1)].get()).assume_init_ref() }.clone();
522 let mut best_key = key(&first);
523 let mut best = first;
524 for i in 1..len {
525 let slot = head.wrapping_add(i) & (N - 1);
526 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone();
528 let k = key(&item);
529 if k < best_key {
530 best_key = k;
531 best = item;
532 }
533 }
534 Some(best)
535 }
536
537 pub fn max_cloned_by<F, K>(&self, key: F) -> Option<T>
543 where
544 T: Clone,
545 F: Fn(&T) -> K,
546 K: Ord,
547 {
548 let head = self.head.load(Ordering::Acquire);
549 let tail = self.tail.load(Ordering::Acquire);
550 let len = tail.wrapping_sub(head);
551 if len == 0 {
552 return None;
553 }
554 let first = unsafe { (*self.buf[head & (N - 1)].get()).assume_init_ref() }.clone();
556 let mut best_key = key(&first);
557 let mut best = first;
558 for i in 1..len {
559 let slot = head.wrapping_add(i) & (N - 1);
560 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone();
562 let k = key(&item);
563 if k > best_key {
564 best_key = k;
565 best = item;
566 }
567 }
568 Some(best)
569 }
570
571 pub fn contains_cloned(&self, value: &T) -> bool
575 where
576 T: Clone + PartialEq,
577 {
578 let head = self.head.load(Ordering::Acquire);
579 let tail = self.tail.load(Ordering::Acquire);
580 let len = tail.wrapping_sub(head);
581 for i in 0..len {
582 let slot = head.wrapping_add(i) & (N - 1);
583 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
585 if item == value {
586 return true;
587 }
588 }
589 false
590 }
591
592 pub fn average_cloned(&self) -> Option<f64>
598 where
599 T: Clone + Into<f64>,
600 {
601 let head = self.head.load(Ordering::Acquire);
602 let tail = self.tail.load(Ordering::Acquire);
603 let len = tail.wrapping_sub(head);
604 if len == 0 {
605 return None;
606 }
607 let sum: f64 = (0..len)
608 .map(|i| {
609 let slot = head.wrapping_add(i) & (N - 1);
610 unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone().into()
612 })
613 .sum();
614 Some(sum / len as f64)
615 }
616
617 pub fn sum_cloned(&self) -> T
623 where
624 T: Clone + std::iter::Sum + Default,
625 {
626 let head = self.head.load(Ordering::Acquire);
627 let tail = self.tail.load(Ordering::Acquire);
628 let len = tail.wrapping_sub(head);
629 if len == 0 {
630 return T::default();
631 }
632 (0..len)
633 .map(|i| {
634 let slot = head.wrapping_add(i) & (N - 1);
635 unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone()
637 })
638 .sum()
639 }
640
641 pub fn split(self) -> (SpscProducer<T, N>, SpscConsumer<T, N>) {
662 let shared = Arc::new(self);
663 (
664 SpscProducer {
665 inner: Arc::clone(&shared),
666 },
667 SpscConsumer { inner: shared },
668 )
669 }
670}
671
672impl<T, const N: usize> Drop for SpscRing<T, N> {
673 fn drop(&mut self) {
674 let head = self.head.load(Ordering::Relaxed);
678 let tail = self.tail.load(Ordering::Relaxed);
679 let mut idx = head;
680 while idx != tail {
681 let slot = idx & (N - 1);
682 unsafe {
684 (*self.buf[slot].get()).assume_init_drop();
685 }
686 idx = idx.wrapping_add(1);
687 }
688 }
689}
690
691impl<T, const N: usize> Default for SpscRing<T, N> {
692 fn default() -> Self {
693 Self::new()
694 }
695}
696
697pub struct SpscProducer<T, const N: usize> {
699 inner: Arc<SpscRing<T, N>>,
700}
701
702unsafe impl<T: Send, const N: usize> Send for SpscProducer<T, N> {}
705
706impl<T, const N: usize> SpscProducer<T, N> {
707 #[inline]
709 pub fn push(&self, item: T) -> Result<(), StreamError> {
710 self.inner.push(item)
711 }
712
713 #[inline]
717 pub fn try_push_or_drop(&self, item: T) -> bool {
718 self.inner.try_push_or_drop(item)
719 }
720
721 #[inline]
723 pub fn is_full(&self) -> bool {
724 self.inner.is_full()
725 }
726
727 #[inline]
729 pub fn is_empty(&self) -> bool {
730 self.inner.is_empty()
731 }
732
733 #[inline]
735 pub fn len(&self) -> usize {
736 self.inner.len()
737 }
738
739 #[inline]
741 pub fn available(&self) -> usize {
742 self.inner.remaining_capacity()
743 }
744
745 #[inline]
747 pub fn capacity(&self) -> usize {
748 self.inner.capacity()
749 }
750
751 #[inline]
756 pub fn fill_ratio(&self) -> f64 {
757 self.inner.fill_ratio()
758 }
759}
760
761pub struct SpscConsumer<T, const N: usize> {
763 inner: Arc<SpscRing<T, N>>,
764}
765
766unsafe impl<T: Send, const N: usize> Send for SpscConsumer<T, N> {}
769
770impl<T, const N: usize> SpscConsumer<T, N> {
771 #[inline]
773 pub fn pop(&self) -> Result<T, StreamError> {
774 self.inner.pop()
775 }
776
777 pub fn drain(&self) -> Vec<T> {
784 let mut out = Vec::with_capacity(self.inner.len());
785 while let Ok(item) = self.inner.pop() {
786 out.push(item);
787 }
788 out
789 }
790
791 #[inline]
793 pub fn is_empty(&self) -> bool {
794 self.inner.is_empty()
795 }
796
797 #[inline]
799 pub fn len(&self) -> usize {
800 self.inner.len()
801 }
802
803 #[inline]
805 pub fn capacity(&self) -> usize {
806 self.inner.capacity()
807 }
808
809 #[inline]
813 pub fn fill_ratio(&self) -> f64 {
814 self.inner.fill_ratio()
815 }
816
817 pub fn peek_clone(&self) -> Option<T>
823 where
824 T: Clone,
825 {
826 self.inner.peek_clone()
827 }
828
829 pub fn try_pop_n(&self, max: usize) -> Vec<T> {
837 let mut out = Vec::with_capacity(max.min(self.inner.len()));
838 while out.len() < max {
839 match self.inner.pop() {
840 Ok(item) => out.push(item),
841 Err(_) => break,
842 }
843 }
844 out
845 }
846
847 pub fn into_iter_drain(self) -> SpscDrainIter<T, N> {
852 SpscDrainIter { consumer: self }
853 }
854}
855
856pub struct SpscDrainIter<T, const N: usize> {
858 consumer: SpscConsumer<T, N>,
859}
860
861impl<T, const N: usize> Iterator for SpscDrainIter<T, N> {
862 type Item = T;
863
864 fn next(&mut self) -> Option<Self::Item> {
865 self.consumer.pop().ok()
866 }
867}
868
869#[cfg(test)]
870mod tests {
871 use super::*;
872 use std::thread;
873
874 #[test]
877 fn test_new_ring_is_empty() {
878 let r: SpscRing<u32, 8> = SpscRing::new();
879 assert!(r.is_empty());
880 assert_eq!(r.len(), 0);
881 }
882
883 #[test]
884 fn test_push_pop_single_item() {
885 let r: SpscRing<u32, 8> = SpscRing::new();
886 r.push(42).unwrap();
887 assert_eq!(r.pop().unwrap(), 42);
888 }
889
890 #[test]
891 fn test_pop_empty_returns_ring_buffer_empty() {
892 let r: SpscRing<u32, 8> = SpscRing::new();
893 let err = r.pop().unwrap_err();
894 assert!(matches!(err, StreamError::RingBufferEmpty));
895 }
896
897 #[test]
899 fn test_capacity_is_n_minus_1() {
900 let r: SpscRing<u32, 8> = SpscRing::new();
901 assert_eq!(r.capacity(), 7);
902 }
903
904 #[test]
908 fn test_fill_to_exact_capacity_then_overflow() {
909 let r: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
911 r.push(i).unwrap();
912 }
913 assert!(r.is_full());
914 let err = r.push(99).unwrap_err();
915 assert!(matches!(err, StreamError::RingBufferFull { capacity: 7 }));
916 }
917
918 #[test]
919 fn test_push_n_minus_1_pop_one_push_one() {
920 let r: SpscRing<u32, 8> = SpscRing::new();
921 for i in 0..7u32 {
922 r.push(i).unwrap();
923 }
924 assert_eq!(r.pop().unwrap(), 0);
925 r.push(100).unwrap();
926 assert_eq!(r.len(), 7);
927 }
928
929 #[test]
930 fn test_push_n_plus_1_returns_full_error() {
931 let r: SpscRing<u32, 4> = SpscRing::new(); r.push(1).unwrap();
933 r.push(2).unwrap();
934 r.push(3).unwrap();
935 assert!(r.is_full());
936 let e1 = r.push(4).unwrap_err();
937 let e2 = r.push(5).unwrap_err();
938 assert!(matches!(e1, StreamError::RingBufferFull { .. }));
939 assert!(matches!(e2, StreamError::RingBufferFull { .. }));
940 }
941
942 #[test]
945 fn test_fifo_ordering() {
946 let r: SpscRing<u32, 16> = SpscRing::new();
947 for i in 0..10u32 {
948 r.push(i).unwrap();
949 }
950 for i in 0..10u32 {
951 assert_eq!(r.pop().unwrap(), i);
952 }
953 }
954
955 #[test]
959 fn test_wraparound_correctness() {
960 let r: SpscRing<u32, 4> = SpscRing::new(); r.push(1).unwrap();
962 r.push(2).unwrap();
963 r.push(3).unwrap();
964 assert_eq!(r.pop().unwrap(), 1);
965 assert_eq!(r.pop().unwrap(), 2);
966 assert_eq!(r.pop().unwrap(), 3);
967 r.push(10).unwrap();
968 r.push(20).unwrap();
969 r.push(30).unwrap();
970 assert_eq!(r.pop().unwrap(), 10);
971 assert_eq!(r.pop().unwrap(), 20);
972 assert_eq!(r.pop().unwrap(), 30);
973 }
974
975 #[test]
976 fn test_wraparound_many_cycles() {
977 let r: SpscRing<u64, 8> = SpscRing::new(); for cycle in 0u64..20 {
979 for i in 0..5 {
980 r.push(cycle * 100 + i).unwrap();
981 }
982 for i in 0..5 {
983 let v = r.pop().unwrap();
984 assert_eq!(v, cycle * 100 + i);
985 }
986 }
987 }
988
989 #[test]
992 fn test_is_full_false_when_one_slot_free() {
993 let r: SpscRing<u32, 4> = SpscRing::new(); r.push(1).unwrap();
995 r.push(2).unwrap();
996 assert!(!r.is_full());
997 r.push(3).unwrap();
998 assert!(r.is_full());
999 }
1000
1001 #[test]
1002 fn test_is_empty_after_drain() {
1003 let r: SpscRing<u32, 4> = SpscRing::new();
1004 r.push(1).unwrap();
1005 r.push(2).unwrap();
1006 r.pop().unwrap();
1007 r.pop().unwrap();
1008 assert!(r.is_empty());
1009 }
1010
1011 #[test]
1015 fn test_drop_drains_remaining_items() {
1016 use std::sync::atomic::{AtomicUsize, Ordering};
1017 use std::sync::Arc;
1018
1019 let drop_count = Arc::new(AtomicUsize::new(0));
1020
1021 struct Counted(Arc<AtomicUsize>);
1022 impl Drop for Counted {
1023 fn drop(&mut self) {
1024 self.0.fetch_add(1, Ordering::Relaxed);
1025 }
1026 }
1027
1028 let ring: SpscRing<Counted, 8> = SpscRing::new();
1029 ring.push(Counted(Arc::clone(&drop_count))).unwrap();
1030 ring.push(Counted(Arc::clone(&drop_count))).unwrap();
1031 ring.push(Counted(Arc::clone(&drop_count))).unwrap();
1032 drop(ring);
1033 assert_eq!(drop_count.load(Ordering::Relaxed), 3);
1034 }
1035
1036 #[test]
1041 fn test_concurrent_producer_consumer() {
1042 const ITEMS: u64 = 10_000;
1043 let ring: SpscRing<u64, 256> = SpscRing::new();
1044 let (prod, cons) = ring.split();
1045
1046 let producer = thread::spawn(move || {
1047 let mut sent = 0u64;
1048 while sent < ITEMS {
1049 if prod.push(sent).is_ok() {
1050 sent += 1;
1051 }
1052 }
1053 });
1054
1055 let consumer = thread::spawn(move || {
1056 let mut received = Vec::with_capacity(ITEMS as usize);
1057 while received.len() < ITEMS as usize {
1058 if let Ok(v) = cons.pop() {
1059 received.push(v);
1060 }
1061 }
1062 received
1063 });
1064
1065 producer.join().unwrap();
1066 let received = consumer.join().unwrap();
1067 assert_eq!(received.len(), ITEMS as usize);
1068 for (i, &v) in received.iter().enumerate() {
1069 assert_eq!(v, i as u64, "FIFO ordering violated at index {i}");
1070 }
1071 }
1072
1073 #[test]
1076 fn test_throughput_100k_round_trips() {
1077 const ITEMS: usize = 100_000;
1078 let ring: SpscRing<u64, 1024> = SpscRing::new();
1079 let (prod, cons) = ring.split();
1080
1081 let producer = thread::spawn(move || {
1082 let mut sent = 0usize;
1083 while sent < ITEMS {
1084 if prod.push(sent as u64).is_ok() {
1085 sent += 1;
1086 }
1087 }
1088 });
1089
1090 let consumer = thread::spawn(move || {
1091 let mut count = 0usize;
1092 while count < ITEMS {
1093 if cons.pop().is_ok() {
1094 count += 1;
1095 }
1096 }
1097 count
1098 });
1099
1100 producer.join().unwrap();
1101 let count = consumer.join().unwrap();
1102 assert_eq!(count, ITEMS);
1103 }
1104
1105 #[test]
1108 fn test_split_producer_push_consumer_pop() {
1109 let ring: SpscRing<u32, 16> = SpscRing::new();
1110 let (prod, cons) = ring.split();
1111 prod.push(7).unwrap();
1112 assert_eq!(cons.pop().unwrap(), 7);
1113 }
1114
1115 #[test]
1116 fn test_producer_is_full_matches_ring() {
1117 let ring: SpscRing<u32, 4> = SpscRing::new();
1118 let (prod, cons) = ring.split();
1119 prod.push(1).unwrap();
1120 prod.push(2).unwrap();
1121 prod.push(3).unwrap();
1122 assert!(prod.is_full());
1123 cons.pop().unwrap();
1124 assert!(!prod.is_full());
1125 }
1126
1127 #[test]
1128 fn test_consumer_len_and_is_empty() {
1129 let ring: SpscRing<u32, 8> = SpscRing::new();
1130 let (prod, cons) = ring.split();
1131 assert!(cons.is_empty());
1132 prod.push(1).unwrap();
1133 prod.push(2).unwrap();
1134 assert_eq!(cons.len(), 2);
1135 assert!(!cons.is_empty());
1136 }
1137
1138 #[test]
1139 fn test_producer_is_empty_initially_true() {
1140 let ring: SpscRing<u32, 8> = SpscRing::new();
1141 let (prod, _cons) = ring.split();
1142 assert!(prod.is_empty());
1143 }
1144
1145 #[test]
1146 fn test_producer_is_empty_false_after_push() {
1147 let ring: SpscRing<u32, 8> = SpscRing::new();
1148 let (prod, _cons) = ring.split();
1149 prod.push(1).unwrap();
1150 assert!(!prod.is_empty());
1151 }
1152
1153 #[test]
1154 fn test_producer_len_matches_consumer_len() {
1155 let ring: SpscRing<u32, 8> = SpscRing::new();
1156 let (prod, cons) = ring.split();
1157 assert_eq!(prod.len(), 0);
1158 prod.push(10).unwrap();
1159 prod.push(20).unwrap();
1160 assert_eq!(prod.len(), 2);
1161 assert_eq!(cons.len(), 2);
1162 }
1163
1164 #[test]
1168 fn test_minimum_power_of_two_size() {
1169 let ring: SpscRing<u32, 2> = SpscRing::new(); assert_eq!(ring.capacity(), 1);
1171 ring.push(99).unwrap();
1172 assert!(ring.is_full());
1173 assert_eq!(ring.pop().unwrap(), 99);
1174 assert!(ring.is_empty());
1175 }
1176
1177 #[test]
1179 fn test_large_power_of_two_size() {
1180 let ring: SpscRing<u64, 1024> = SpscRing::new();
1181 assert_eq!(ring.capacity(), 1023);
1182 }
1183
1184 #[test]
1187 fn test_drain_iter_yields_fifo_order() {
1188 let ring: SpscRing<u32, 8> = SpscRing::new();
1189 let (prod, cons) = ring.split();
1190 prod.push(1).unwrap();
1191 prod.push(2).unwrap();
1192 prod.push(3).unwrap();
1193 let items: Vec<u32> = cons.into_iter_drain().collect();
1194 assert_eq!(items, vec![1, 2, 3]);
1195 }
1196
1197 #[test]
1198 fn test_drain_iter_empty_ring_yields_nothing() {
1199 let ring: SpscRing<u32, 8> = SpscRing::new();
1200 let (_, cons) = ring.split();
1201 let items: Vec<u32> = cons.into_iter_drain().collect();
1202 assert!(items.is_empty());
1203 }
1204
1205 #[test]
1210 fn test_peek_clone_empty_returns_none() {
1211 let r: SpscRing<u32, 8> = SpscRing::new();
1212 assert!(r.peek_clone().is_none());
1213 }
1214
1215 #[test]
1216 fn test_peek_clone_does_not_consume() {
1217 let r: SpscRing<u32, 8> = SpscRing::new();
1218 r.push(42).unwrap();
1219 assert_eq!(r.peek_clone(), Some(42));
1220 assert_eq!(r.peek_clone(), Some(42)); assert_eq!(r.pop().unwrap(), 42);
1222 assert!(r.is_empty());
1223 }
1224
1225 #[test]
1226 fn test_peek_clone_via_consumer() {
1227 let ring: SpscRing<u32, 8> = SpscRing::new();
1228 let (prod, cons) = ring.split();
1229 prod.push(7).unwrap();
1230 prod.push(8).unwrap();
1231 assert_eq!(cons.peek_clone(), Some(7)); assert_eq!(cons.pop().unwrap(), 7); assert_eq!(cons.peek_clone(), Some(8)); }
1235
1236 proptest::proptest! {
1237 #[test]
1240 fn prop_fifo_ordering_with_wraparound(
1241 batches in proptest::collection::vec(
1243 proptest::collection::vec(0u32..=u32::MAX, 1..=7),
1244 1..=20,
1245 )
1246 ) {
1247 let ring: SpscRing<u32, 8> = SpscRing::new();
1249 let mut oracle: std::collections::VecDeque<u32> = std::collections::VecDeque::new();
1250
1251 for batch in &batches {
1252 for &item in batch {
1254 if ring.push(item).is_ok() {
1255 oracle.push_back(item);
1256 }
1257 }
1258 while let Ok(popped) = ring.pop() {
1260 let expected = oracle.pop_front().expect("oracle must have matching item");
1261 proptest::prop_assert_eq!(popped, expected);
1262 }
1263 }
1264 }
1265 }
1266
1267 #[test]
1270 fn test_try_pop_n_empty_returns_empty_vec() {
1271 let ring: SpscRing<u32, 8> = SpscRing::new();
1272 let (_, consumer) = ring.split();
1273 assert!(consumer.try_pop_n(5).is_empty());
1274 }
1275
1276 #[test]
1277 fn test_try_pop_n_bounded_by_max() {
1278 let ring: SpscRing<u32, 8> = SpscRing::new();
1279 let (producer, consumer) = ring.split();
1280 for i in 0..5 {
1281 producer.push(i).unwrap();
1282 }
1283 let batch = consumer.try_pop_n(3);
1284 assert_eq!(batch.len(), 3);
1285 assert_eq!(batch, vec![0, 1, 2]);
1286 assert_eq!(consumer.len(), 2);
1288 }
1289
1290 #[test]
1291 fn test_try_pop_n_larger_than_available_returns_all() {
1292 let ring: SpscRing<u32, 8> = SpscRing::new();
1293 let (producer, consumer) = ring.split();
1294 for i in 0..3 {
1295 producer.push(i).unwrap();
1296 }
1297 let batch = consumer.try_pop_n(100);
1298 assert_eq!(batch.len(), 3);
1299 assert!(consumer.is_empty());
1300 }
1301
1302 #[test]
1305 fn test_producer_capacity_equals_ring_capacity() {
1306 let ring: SpscRing<u32, 8> = SpscRing::new(); let (producer, consumer) = ring.split();
1308 assert_eq!(producer.capacity(), 7);
1309 assert_eq!(consumer.capacity(), 7);
1310 }
1311
1312 #[test]
1313 fn test_capacity_consistent_with_max_items() {
1314 let ring: SpscRing<u32, 4> = SpscRing::new(); let (producer, consumer) = ring.split();
1316 for i in 0..3 {
1317 producer.push(i).unwrap();
1318 }
1319 assert_eq!(consumer.capacity(), 3);
1321 assert_eq!(consumer.len(), 3);
1322 }
1323
1324 #[test]
1327 fn test_fill_ratio_empty_is_zero() {
1328 let ring: SpscRing<u32, 8> = SpscRing::new();
1329 let (_, consumer) = ring.split();
1330 assert!((consumer.fill_ratio() - 0.0).abs() < 1e-9);
1331 }
1332
1333 #[test]
1334 fn test_fill_ratio_full_is_one() {
1335 let ring: SpscRing<u32, 4> = SpscRing::new(); let (producer, consumer) = ring.split();
1337 for i in 0..3 {
1338 producer.push(i).unwrap();
1339 }
1340 assert!((consumer.fill_ratio() - 1.0).abs() < 1e-9);
1341 }
1342
1343 #[test]
1344 fn test_fill_ratio_partial() {
1345 let ring: SpscRing<u32, 8> = SpscRing::new(); let (producer, consumer) = ring.split();
1347 for i in 0..7 {
1349 producer.push(i).unwrap();
1350 }
1351 consumer.pop().unwrap();
1353 consumer.pop().unwrap();
1354 consumer.pop().unwrap();
1355 consumer.pop().unwrap();
1356 let ratio = consumer.fill_ratio();
1357 assert!((ratio - 3.0 / 7.0).abs() < 1e-9, "got {ratio}");
1358 }
1359
1360 #[test]
1363 fn test_producer_fill_ratio_empty_is_zero() {
1364 let ring: SpscRing<u32, 8> = SpscRing::new();
1365 let (producer, _) = ring.split();
1366 assert!((producer.fill_ratio() - 0.0).abs() < 1e-9);
1367 }
1368
1369 #[test]
1370 fn test_producer_fill_ratio_full_is_one() {
1371 let ring: SpscRing<u32, 4> = SpscRing::new(); let (producer, _) = ring.split();
1373 for i in 0..3 {
1374 producer.push(i).unwrap();
1375 }
1376 assert!((producer.fill_ratio() - 1.0).abs() < 1e-9);
1377 }
1378
1379 #[test]
1380 fn test_producer_and_consumer_fill_ratio_agree() {
1381 let ring: SpscRing<u32, 8> = SpscRing::new();
1382 let (producer, consumer) = ring.split();
1383 producer.push(1).unwrap();
1384 producer.push(2).unwrap();
1385 assert!((producer.fill_ratio() - consumer.fill_ratio()).abs() < 1e-9);
1386 }
1387
1388 #[test]
1389 fn test_peek_all_empty_returns_empty_vec() {
1390 let ring: SpscRing<u32, 8> = SpscRing::new();
1391 assert!(ring.peek_all().is_empty());
1392 }
1393
1394 #[test]
1395 fn test_peek_all_does_not_consume() {
1396 let ring: SpscRing<u32, 8> = SpscRing::new();
1397 ring.push(1).unwrap();
1398 ring.push(2).unwrap();
1399 ring.push(3).unwrap();
1400 let snapshot = ring.peek_all();
1401 assert_eq!(snapshot, vec![1, 2, 3]);
1402 assert_eq!(ring.len(), 3);
1404 }
1405
1406 #[test]
1407 fn test_peek_all_fifo_order_after_pop() {
1408 let ring: SpscRing<u32, 16> = SpscRing::new();
1409 for i in 0..5u32 {
1410 ring.push(i).unwrap();
1411 }
1412 ring.pop().unwrap(); let snapshot = ring.peek_all();
1414 assert_eq!(snapshot, vec![1, 2, 3, 4]);
1415 }
1416
1417 #[test]
1418 fn test_drain_into_appends_to_buf() {
1419 let ring: SpscRing<u32, 8> = SpscRing::new();
1420 ring.push(10).unwrap();
1421 ring.push(20).unwrap();
1422 let mut buf = vec![1u32, 2];
1423 ring.drain_into(&mut buf);
1424 assert_eq!(buf, vec![1, 2, 10, 20]);
1425 assert!(ring.is_empty());
1426 }
1427
1428 #[test]
1429 fn test_drain_into_empty_ring_leaves_buf_unchanged() {
1430 let ring: SpscRing<u32, 8> = SpscRing::new();
1431 let mut buf = vec![42u32];
1432 ring.drain_into(&mut buf);
1433 assert_eq!(buf, vec![42]);
1434 }
1435
1436 #[test]
1439 fn test_peek_newest_none_when_empty() {
1440 let ring: SpscRing<u32, 8> = SpscRing::new();
1441 assert!(ring.peek_newest().is_none());
1442 }
1443
1444 #[test]
1445 fn test_peek_newest_returns_last_pushed() {
1446 let ring: SpscRing<u32, 8> = SpscRing::new();
1447 ring.push(10).unwrap();
1448 ring.push(20).unwrap();
1449 ring.push(30).unwrap();
1450 assert_eq!(ring.peek_newest(), Some(30));
1451 }
1452
1453 #[test]
1454 fn test_peek_newest_does_not_consume() {
1455 let ring: SpscRing<u32, 8> = SpscRing::new();
1456 ring.push(42).unwrap();
1457 let _ = ring.peek_newest();
1458 assert_eq!(ring.len(), 1);
1459 }
1460
1461 #[test]
1464 fn test_fill_ratio_zero_when_empty() {
1465 let ring: SpscRing<u32, 8> = SpscRing::new();
1466 assert_eq!(ring.fill_ratio(), 0.0);
1467 }
1468
1469 #[test]
1470 fn test_fill_ratio_one_when_full() {
1471 let ring: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
1473 ring.push(i).unwrap();
1474 }
1475 assert!((ring.fill_ratio() - 1.0).abs() < 1e-10);
1476 }
1477
1478 #[test]
1479 fn test_fill_ratio_half_when_half_full() {
1480 let ring: SpscRing<u32, 8> = SpscRing::new(); ring.push(1).unwrap();
1483 ring.push(2).unwrap();
1484 ring.push(3).unwrap();
1485 let ratio = ring.fill_ratio();
1486 assert!((ratio - 3.0 / 7.0).abs() < 1e-10);
1487 }
1488
1489 #[test]
1492 fn test_utilization_pct_zero_when_empty() {
1493 let ring: SpscRing<u32, 8> = SpscRing::new();
1494 assert_eq!(ring.utilization_pct(), 0.0);
1495 }
1496
1497 #[test]
1498 fn test_utilization_pct_100_when_full() {
1499 let ring: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
1501 ring.push(i).unwrap();
1502 }
1503 assert!((ring.utilization_pct() - 100.0).abs() < 1e-10);
1504 }
1505
1506 #[test]
1507 fn test_utilization_pct_equals_fill_ratio_times_100() {
1508 let ring: SpscRing<u32, 8> = SpscRing::new();
1509 ring.push(1u32).unwrap();
1510 ring.push(2u32).unwrap();
1511 let ratio = ring.fill_ratio();
1512 assert!((ring.utilization_pct() - ratio * 100.0).abs() < 1e-10);
1513 }
1514
1515 #[test]
1518 fn test_remaining_capacity_full_when_empty() {
1519 let ring: SpscRing<u32, 8> = SpscRing::new(); assert_eq!(ring.remaining_capacity(), 7);
1521 }
1522
1523 #[test]
1524 fn test_remaining_capacity_decreases_on_push() {
1525 let ring: SpscRing<u32, 8> = SpscRing::new();
1526 ring.push(1u32).unwrap();
1527 ring.push(2u32).unwrap();
1528 assert_eq!(ring.remaining_capacity(), 5);
1529 }
1530
1531 #[test]
1532 fn test_remaining_capacity_zero_when_full() {
1533 let ring: SpscRing<u32, 8> = SpscRing::new();
1534 for i in 0..7u32 {
1535 ring.push(i).unwrap();
1536 }
1537 assert_eq!(ring.remaining_capacity(), 0);
1538 }
1539
1540 #[test]
1543 fn test_is_nearly_full_false_when_empty() {
1544 let ring: SpscRing<u32, 8> = SpscRing::new();
1545 assert!(!ring.is_nearly_full(0.5));
1546 }
1547
1548 #[test]
1549 fn test_is_nearly_full_true_when_at_threshold() {
1550 let ring: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
1553 ring.push(i).unwrap();
1554 }
1555 assert!(ring.is_nearly_full(0.9));
1556 }
1557
1558 #[test]
1559 fn test_is_nearly_full_false_when_below_threshold() {
1560 let ring: SpscRing<u32, 8> = SpscRing::new(); ring.push(1u32).unwrap(); assert!(!ring.is_nearly_full(0.9));
1563 }
1564
1565 #[test]
1568 fn test_first_none_when_empty() {
1569 let ring: SpscRing<u32, 8> = SpscRing::new();
1570 assert!(ring.first().is_none());
1571 }
1572
1573 #[test]
1574 fn test_first_returns_oldest_copy() {
1575 let ring: SpscRing<u32, 8> = SpscRing::new();
1576 ring.push(42u32).unwrap();
1577 ring.push(99u32).unwrap();
1578 assert_eq!(ring.first(), Some(42u32));
1579 }
1580
1581 #[test]
1582 fn test_first_does_not_remove() {
1583 let ring: SpscRing<u32, 8> = SpscRing::new();
1584 ring.push(7u32).unwrap();
1585 let _ = ring.first();
1586 assert_eq!(ring.len(), 1);
1587 }
1588
1589 #[test]
1592 fn test_peek_front_none_when_empty() {
1593 let ring: SpscRing<u32, 8> = SpscRing::new();
1594 assert!(ring.peek_front().is_none());
1595 }
1596
1597 #[test]
1598 fn test_peek_front_returns_oldest_item() {
1599 let ring: SpscRing<u32, 8> = SpscRing::new();
1600 ring.push(10u32).unwrap();
1601 ring.push(20u32).unwrap();
1602 assert_eq!(ring.peek_front(), Some(&10u32));
1603 }
1604
1605 #[test]
1606 fn test_peek_front_does_not_remove_item() {
1607 let ring: SpscRing<u32, 8> = SpscRing::new();
1608 ring.push(42u32).unwrap();
1609 let _ = ring.peek_front();
1610 assert_eq!(ring.len(), 1);
1611 }
1612
1613 #[test]
1614 fn test_peek_back_none_when_empty() {
1615 let ring: SpscRing<u32, 8> = SpscRing::new();
1616 assert!(ring.peek_back().is_none());
1617 }
1618
1619 #[test]
1620 fn test_peek_back_returns_newest_item() {
1621 let ring: SpscRing<u32, 8> = SpscRing::new();
1622 ring.push(10u32).unwrap();
1623 ring.push(20u32).unwrap();
1624 assert_eq!(ring.peek_back(), Some(&20u32));
1625 }
1626
1627 #[test]
1630 fn test_to_vec_cloned_empty() {
1631 let ring: SpscRing<u32, 8> = SpscRing::new();
1632 assert_eq!(ring.to_vec_cloned(), Vec::<u32>::new());
1633 }
1634
1635 #[test]
1636 fn test_to_vec_cloned_preserves_fifo_order() {
1637 let ring: SpscRing<u32, 8> = SpscRing::new();
1638 ring.push(1u32).unwrap();
1639 ring.push(2u32).unwrap();
1640 ring.push(3u32).unwrap();
1641 assert_eq!(ring.to_vec_cloned(), vec![1u32, 2, 3]);
1642 }
1643
1644 #[test]
1645 fn test_to_vec_cloned_does_not_drain() {
1646 let ring: SpscRing<u32, 8> = SpscRing::new();
1647 ring.push(42u32).unwrap();
1648 let _ = ring.to_vec_cloned();
1649 assert_eq!(ring.len(), 1);
1650 }
1651
1652 #[test]
1655 fn test_min_cloned_none_when_empty() {
1656 let ring: SpscRing<u32, 8> = SpscRing::new();
1657 assert!(ring.min_cloned().is_none());
1658 }
1659
1660 #[test]
1661 fn test_min_cloned_returns_minimum() {
1662 let ring: SpscRing<u32, 8> = SpscRing::new();
1663 ring.push(3u32).unwrap();
1664 ring.push(1u32).unwrap();
1665 ring.push(4u32).unwrap();
1666 ring.push(2u32).unwrap();
1667 assert_eq!(ring.min_cloned(), Some(1u32));
1668 }
1669
1670 #[test]
1671 fn test_min_cloned_does_not_drain() {
1672 let ring: SpscRing<u32, 8> = SpscRing::new();
1673 ring.push(10u32).unwrap();
1674 let _ = ring.min_cloned();
1675 assert_eq!(ring.len(), 1);
1676 }
1677
1678 #[test]
1681 fn test_max_cloned_none_when_empty() {
1682 let ring: SpscRing<u32, 8> = SpscRing::new();
1683 assert!(ring.max_cloned().is_none());
1684 }
1685
1686 #[test]
1687 fn test_max_cloned_returns_maximum() {
1688 let ring: SpscRing<u32, 8> = SpscRing::new();
1689 ring.push(3u32).unwrap();
1690 ring.push(1u32).unwrap();
1691 ring.push(4u32).unwrap();
1692 ring.push(2u32).unwrap();
1693 assert_eq!(ring.max_cloned(), Some(4u32));
1694 }
1695
1696 #[test]
1697 fn test_max_cloned_does_not_drain() {
1698 let ring: SpscRing<u32, 8> = SpscRing::new();
1699 ring.push(10u32).unwrap();
1700 let _ = ring.max_cloned();
1701 assert_eq!(ring.len(), 1);
1702 }
1703
1704 #[test]
1707 fn test_count_if_zero_when_empty() {
1708 let ring: SpscRing<u32, 8> = SpscRing::new();
1709 assert_eq!(ring.count_if(|_| true), 0);
1710 }
1711
1712 #[test]
1713 fn test_count_if_counts_matching_items() {
1714 let ring: SpscRing<u32, 8> = SpscRing::new();
1715 for i in 1u32..=6 {
1716 ring.push(i).unwrap();
1717 }
1718 assert_eq!(ring.count_if(|x| x % 2 == 0), 3);
1720 }
1721
1722 #[test]
1723 fn test_count_if_all_match() {
1724 let ring: SpscRing<u32, 8> = SpscRing::new();
1725 ring.push(10u32).unwrap();
1726 ring.push(20u32).unwrap();
1727 assert_eq!(ring.count_if(|_| true), 2);
1728 }
1729
1730 #[test]
1732 fn test_has_capacity_true_on_empty_ring() {
1733 let ring: SpscRing<u32, 8> = SpscRing::new(); assert!(ring.has_capacity(7));
1735 }
1736
1737 #[test]
1738 fn test_has_capacity_false_when_full() {
1739 let ring: SpscRing<u32, 8> = SpscRing::new();
1740 for i in 0..7u32 {
1741 ring.push(i).unwrap();
1742 }
1743 assert!(!ring.has_capacity(1));
1744 }
1745
1746 #[test]
1747 fn test_has_capacity_false_for_zero_capacity_needed() {
1748 let ring: SpscRing<u32, 4> = SpscRing::new();
1749 assert!(ring.has_capacity(0));
1751 }
1752
1753 #[test]
1754 fn test_has_capacity_partial_fill() {
1755 let ring: SpscRing<u32, 8> = SpscRing::new(); ring.push(1u32).unwrap();
1757 ring.push(2u32).unwrap();
1758 assert!(ring.has_capacity(5));
1760 assert!(!ring.has_capacity(6));
1761 }
1762
1763 #[test]
1765 fn test_is_empty_true_for_new_ring() {
1766 let ring: SpscRing<u32, 8> = SpscRing::new();
1767 assert!(ring.is_empty());
1768 }
1769
1770 #[test]
1771 fn test_is_empty_false_after_push() {
1772 let ring: SpscRing<u32, 8> = SpscRing::new();
1773 ring.push(42u32).unwrap();
1774 assert!(!ring.is_empty());
1775 }
1776
1777 #[test]
1778 fn test_is_empty_true_after_push_and_pop() {
1779 let ring: SpscRing<u32, 4> = SpscRing::new();
1780 ring.push(1u32).unwrap();
1781 let _ = ring.pop();
1782 assert!(ring.is_empty());
1783 }
1784
1785 #[test]
1787 fn test_peek_oldest_none_on_empty_ring() {
1788 let ring: SpscRing<u32, 8> = SpscRing::new();
1789 assert!(ring.peek_oldest().is_none());
1790 }
1791
1792 #[test]
1793 fn test_peek_oldest_returns_first_pushed_item() {
1794 let ring: SpscRing<u32, 8> = SpscRing::new();
1795 ring.push(10u32).unwrap();
1796 ring.push(20u32).unwrap();
1797 ring.push(30u32).unwrap();
1798 assert_eq!(ring.peek_oldest(), Some(10));
1800 }
1801
1802 #[test]
1803 fn test_peek_oldest_does_not_remove_item() {
1804 let ring: SpscRing<u32, 4> = SpscRing::new();
1805 ring.push(5u32).unwrap();
1806 let _ = ring.peek_oldest();
1807 assert_eq!(ring.pop().unwrap(), 5);
1809 }
1810
1811 #[test]
1812 fn test_peek_oldest_different_from_peek_newest_when_multiple_items() {
1813 let ring: SpscRing<u32, 8> = SpscRing::new();
1814 ring.push(1u32).unwrap();
1815 ring.push(2u32).unwrap();
1816 ring.push(3u32).unwrap();
1817 assert_eq!(ring.peek_oldest(), Some(1));
1818 assert_eq!(ring.peek_newest(), Some(3));
1819 }
1820
1821 #[test]
1824 fn test_sum_cloned_empty_returns_default() {
1825 let ring: SpscRing<u32, 4> = SpscRing::new();
1826 assert_eq!(ring.sum_cloned(), 0u32);
1827 }
1828
1829 #[test]
1830 fn test_sum_cloned_single_element() {
1831 let ring: SpscRing<u32, 4> = SpscRing::new();
1832 ring.push(42u32).unwrap();
1833 assert_eq!(ring.sum_cloned(), 42u32);
1834 }
1835
1836 #[test]
1837 fn test_sum_cloned_multiple_elements() {
1838 let ring: SpscRing<u32, 8> = SpscRing::new();
1839 for v in [1u32, 2, 3, 4, 5] { ring.push(v).unwrap(); }
1840 assert_eq!(ring.sum_cloned(), 15u32);
1841 }
1842
1843 #[test]
1844 fn test_sum_cloned_after_pop_reflects_remaining() {
1845 let ring: SpscRing<u32, 4> = SpscRing::new();
1846 ring.push(10u32).unwrap();
1847 ring.push(20u32).unwrap();
1848 ring.pop().unwrap(); assert_eq!(ring.sum_cloned(), 20u32);
1850 }
1851
1852 #[test]
1855 fn test_average_cloned_none_when_empty() {
1856 let ring: SpscRing<f64, 4> = SpscRing::new();
1857 assert!(ring.average_cloned().is_none());
1858 }
1859
1860 #[test]
1861 fn test_average_cloned_single_element() {
1862 let ring: SpscRing<f64, 4> = SpscRing::new();
1863 ring.push(6.0f64).unwrap();
1864 assert_eq!(ring.average_cloned(), Some(6.0));
1865 }
1866
1867 #[test]
1868 fn test_average_cloned_multiple_elements() {
1869 let ring: SpscRing<f64, 8> = SpscRing::new();
1870 for v in [2.0f64, 4.0, 6.0, 8.0] { ring.push(v).unwrap(); }
1871 assert_eq!(ring.average_cloned(), Some(5.0));
1872 }
1873
1874 #[test]
1877 fn test_peek_nth_returns_oldest_at_index_zero() {
1878 let ring: SpscRing<u32, 8> = SpscRing::new();
1879 ring.push(10u32).unwrap();
1880 ring.push(20u32).unwrap();
1881 ring.push(30u32).unwrap();
1882 assert_eq!(ring.peek_nth(0), Some(10));
1883 }
1884
1885 #[test]
1886 fn test_peek_nth_returns_correct_element() {
1887 let ring: SpscRing<u32, 8> = SpscRing::new();
1888 ring.push(10u32).unwrap();
1889 ring.push(20u32).unwrap();
1890 ring.push(30u32).unwrap();
1891 assert_eq!(ring.peek_nth(1), Some(20));
1892 assert_eq!(ring.peek_nth(2), Some(30));
1893 }
1894
1895 #[test]
1896 fn test_peek_nth_returns_none_when_out_of_bounds() {
1897 let ring: SpscRing<u32, 4> = SpscRing::new();
1898 ring.push(5u32).unwrap();
1899 assert!(ring.peek_nth(1).is_none());
1900 }
1901
1902 #[test]
1905 fn test_contains_cloned_false_when_empty() {
1906 let ring: SpscRing<u32, 4> = SpscRing::new();
1907 assert!(!ring.contains_cloned(&42u32));
1908 }
1909
1910 #[test]
1911 fn test_contains_cloned_true_when_value_present() {
1912 let ring: SpscRing<u32, 8> = SpscRing::new();
1913 ring.push(10u32).unwrap();
1914 ring.push(20u32).unwrap();
1915 assert!(ring.contains_cloned(&10u32));
1916 assert!(ring.contains_cloned(&20u32));
1917 }
1918
1919 #[test]
1920 fn test_contains_cloned_false_when_value_absent() {
1921 let ring: SpscRing<u32, 4> = SpscRing::new();
1922 ring.push(5u32).unwrap();
1923 assert!(!ring.contains_cloned(&99u32));
1924 }
1925
1926 #[test]
1929 fn test_max_cloned_by_none_when_empty() {
1930 let ring: SpscRing<u32, 4> = SpscRing::new();
1931 assert!(ring.max_cloned_by(|&x| x).is_none());
1932 }
1933
1934 #[test]
1935 fn test_max_cloned_by_returns_max_element() {
1936 let ring: SpscRing<u32, 8> = SpscRing::new();
1937 ring.push(3u32).unwrap();
1938 ring.push(1u32).unwrap();
1939 ring.push(7u32).unwrap();
1940 ring.push(2u32).unwrap();
1941 assert_eq!(ring.max_cloned_by(|&x| x), Some(7));
1942 }
1943
1944 #[test]
1945 fn test_max_cloned_by_custom_key() {
1946 let ring: SpscRing<i32, 8> = SpscRing::new();
1947 ring.push(-5i32).unwrap();
1948 ring.push(3i32).unwrap();
1949 ring.push(-10i32).unwrap();
1950 assert_eq!(ring.max_cloned_by(|&x| x.abs()), Some(-10));
1952 }
1953
1954 #[test]
1957 fn test_min_cloned_by_none_when_empty() {
1958 let ring: SpscRing<u32, 4> = SpscRing::new();
1959 assert!(ring.min_cloned_by(|&x| x).is_none());
1960 }
1961
1962 #[test]
1963 fn test_min_cloned_by_returns_min_element() {
1964 let ring: SpscRing<u32, 8> = SpscRing::new();
1965 ring.push(3u32).unwrap();
1966 ring.push(1u32).unwrap();
1967 ring.push(7u32).unwrap();
1968 assert_eq!(ring.min_cloned_by(|&x| x), Some(1));
1969 }
1970
1971 #[test]
1972 fn test_min_cloned_by_custom_key() {
1973 let ring: SpscRing<i32, 8> = SpscRing::new();
1974 ring.push(-5i32).unwrap();
1975 ring.push(3i32).unwrap();
1976 ring.push(-1i32).unwrap();
1977 assert_eq!(ring.min_cloned_by(|&x| x.abs()), Some(-1));
1979 }
1980
1981 #[test]
1984 fn test_to_vec_sorted_empty() {
1985 let ring: SpscRing<u32, 4> = SpscRing::new();
1986 assert_eq!(ring.to_vec_sorted(), Vec::<u32>::new());
1987 }
1988
1989 #[test]
1990 fn test_to_vec_sorted_returns_sorted_elements() {
1991 let ring: SpscRing<u32, 8> = SpscRing::new();
1992 ring.push(5u32).unwrap();
1993 ring.push(1u32).unwrap();
1994 ring.push(3u32).unwrap();
1995 assert_eq!(ring.to_vec_sorted(), vec![1u32, 3, 5]);
1996 }
1997}