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 let head = self.head.load(Ordering::Acquire);
255 let tail = self.tail.load(Ordering::Acquire);
256 if tail == head {
257 return None;
258 }
259 let slot = tail.wrapping_sub(1) & (N - 1);
260 Some(unsafe { *(*self.buf[slot].get()).assume_init_ref() })
262 }
263
264 pub fn peek_oldest(&self) -> Option<T>
269 where
270 T: Copy,
271 {
272 let head = self.head.load(Ordering::Acquire);
273 let tail = self.tail.load(Ordering::Acquire);
274 if tail == head {
275 return None;
276 }
277 let slot = head & (N - 1);
278 Some(unsafe { *(*self.buf[slot].get()).assume_init_ref() })
280 }
281
282 pub fn fill_ratio(&self) -> f64 {
286 let cap = self.capacity();
287 if cap == 0 {
288 return 0.0;
289 }
290 self.len() as f64 / cap as f64
291 }
292
293 pub fn has_capacity(&self, n: usize) -> bool {
297 self.len() + n <= self.capacity()
298 }
299
300 pub fn utilization_pct(&self) -> f64 {
304 self.fill_ratio() * 100.0
305 }
306
307 #[inline]
309 pub fn remaining_capacity(&self) -> usize {
310 self.capacity().saturating_sub(self.len())
311 }
312
313 pub fn is_nearly_full(&self, threshold: f64) -> bool {
317 self.fill_ratio() >= threshold
318 }
319
320 pub fn first(&self) -> Option<T>
324 where
325 T: Copy,
326 {
327 self.peek_front().copied()
328 }
329
330 pub fn peek_front(&self) -> Option<&T> {
334 let head = self.head.load(Ordering::Acquire);
335 let tail = self.tail.load(Ordering::Acquire);
336 if head == tail {
337 return None;
338 }
339 Some(unsafe { (*self.buf[head % N].get()).assume_init_ref() })
341 }
342
343 pub fn peek_back(&self) -> Option<&T> {
347 let head = self.head.load(Ordering::Acquire);
348 let tail = self.tail.load(Ordering::Acquire);
349 if head == tail {
350 return None;
351 }
352 let back = tail.wrapping_sub(1);
353 Some(unsafe { (*self.buf[back % N].get()).assume_init_ref() })
355 }
356
357 pub fn drain(&self) -> Vec<T> {
364 let mut out = Vec::with_capacity(self.len());
365 while let Ok(item) = self.pop() {
366 out.push(item);
367 }
368 out
369 }
370
371 pub fn drain_into(&self, buf: &mut Vec<T>) {
380 while let Ok(item) = self.pop() {
381 buf.push(item);
382 }
383 }
384
385 pub fn to_vec_cloned(&self) -> Vec<T>
391 where
392 T: Clone,
393 {
394 let head = self.head.load(Ordering::Acquire);
395 let tail = self.tail.load(Ordering::Acquire);
396 let len = tail.wrapping_sub(head);
397 let mut out = Vec::with_capacity(len);
398 for i in 0..len {
399 let slot = (head.wrapping_add(i)) % N;
400 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
402 out.push(item.clone());
403 }
404 out
405 }
406
407 pub fn to_vec_sorted(&self) -> Vec<T>
413 where
414 T: Clone + Ord,
415 {
416 let mut v = self.to_vec_cloned();
417 v.sort();
418 v
419 }
420
421 pub fn min_cloned(&self) -> Option<T>
427 where
428 T: Clone + Ord,
429 {
430 let head = self.head.load(Ordering::Acquire);
431 let tail = self.tail.load(Ordering::Acquire);
432 let len = tail.wrapping_sub(head);
433 if len == 0 {
434 return None;
435 }
436 let mut min_val = unsafe { (*self.buf[head % N].get()).assume_init_ref() }.clone();
437 for i in 1..len {
438 let slot = head.wrapping_add(i) % N;
439 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
440 if item < &min_val {
441 min_val = item.clone();
442 }
443 }
444 Some(min_val)
445 }
446
447 pub fn max_cloned(&self) -> Option<T>
453 where
454 T: Clone + Ord,
455 {
456 let head = self.head.load(Ordering::Acquire);
457 let tail = self.tail.load(Ordering::Acquire);
458 let len = tail.wrapping_sub(head);
459 if len == 0 {
460 return None;
461 }
462 let mut max_val = unsafe { (*self.buf[head % N].get()).assume_init_ref() }.clone();
463 for i in 1..len {
464 let slot = head.wrapping_add(i) % N;
465 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
466 if item > &max_val {
467 max_val = item.clone();
468 }
469 }
470 Some(max_val)
471 }
472
473 pub fn count_if<F>(&self, predicate: F) -> usize
479 where
480 F: Fn(&T) -> bool,
481 {
482 let head = self.head.load(Ordering::Acquire);
483 let tail = self.tail.load(Ordering::Acquire);
484 let len = tail.wrapping_sub(head);
485 let mut count = 0;
486 for i in 0..len {
487 let slot = head.wrapping_add(i) % N;
488 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
490 if predicate(item) {
491 count += 1;
492 }
493 }
494 count
495 }
496
497 pub fn peek_nth(&self, n: usize) -> Option<T>
503 where
504 T: Clone,
505 {
506 let head = self.head.load(Ordering::Acquire);
507 let tail = self.tail.load(Ordering::Acquire);
508 let len = tail.wrapping_sub(head);
509 if n >= len {
510 return None;
511 }
512 let slot = head.wrapping_add(n) % N;
513 Some(unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone())
515 }
516
517 pub fn min_cloned_by<F, K>(&self, key: F) -> Option<T>
524 where
525 T: Clone,
526 F: Fn(&T) -> K,
527 K: Ord,
528 {
529 let head = self.head.load(Ordering::Acquire);
530 let tail = self.tail.load(Ordering::Acquire);
531 let len = tail.wrapping_sub(head);
532 if len == 0 {
533 return None;
534 }
535 let mut best: Option<T> = None;
536 let mut best_key: Option<K> = None;
537 for i in 0..len {
538 let slot = head.wrapping_add(i) % N;
539 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone();
541 let k = key(&item);
542 if best_key.as_ref().map_or(true, |bk| &k < bk) {
543 best_key = Some(k);
544 best = Some(item);
545 }
546 }
547 best
548 }
549
550 pub fn max_cloned_by<F, K>(&self, key: F) -> Option<T>
556 where
557 T: Clone,
558 F: Fn(&T) -> K,
559 K: Ord,
560 {
561 let head = self.head.load(Ordering::Acquire);
562 let tail = self.tail.load(Ordering::Acquire);
563 let len = tail.wrapping_sub(head);
564 if len == 0 {
565 return None;
566 }
567 let mut best: Option<T> = None;
568 let mut best_key: Option<K> = None;
569 for i in 0..len {
570 let slot = head.wrapping_add(i) % N;
571 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone();
573 let k = key(&item);
574 if best_key.as_ref().map_or(true, |bk| &k > bk) {
575 best_key = Some(k);
576 best = Some(item);
577 }
578 }
579 best
580 }
581
582 pub fn contains_cloned(&self, value: &T) -> bool
586 where
587 T: Clone + PartialEq,
588 {
589 let head = self.head.load(Ordering::Acquire);
590 let tail = self.tail.load(Ordering::Acquire);
591 let len = tail.wrapping_sub(head);
592 for i in 0..len {
593 let slot = head.wrapping_add(i) % N;
594 let item = unsafe { (*self.buf[slot].get()).assume_init_ref() };
596 if item == value {
597 return true;
598 }
599 }
600 false
601 }
602
603 pub fn average_cloned(&self) -> Option<f64>
608 where
609 T: Clone + Into<f64>,
610 {
611 let head = self.head.load(Ordering::Acquire);
612 let tail = self.tail.load(Ordering::Acquire);
613 let len = tail.wrapping_sub(head);
614 if len == 0 {
615 return None;
616 }
617 let sum: f64 = (0..len)
618 .map(|i| {
619 let slot = head.wrapping_add(i) % N;
620 unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone().into()
622 })
623 .sum();
624 Some(sum / len as f64)
625 }
626
627 pub fn sum_cloned(&self) -> T
633 where
634 T: Clone + std::iter::Sum + Default,
635 {
636 let head = self.head.load(Ordering::Acquire);
637 let tail = self.tail.load(Ordering::Acquire);
638 let len = tail.wrapping_sub(head);
639 if len == 0 {
640 return T::default();
641 }
642 (0..len)
643 .map(|i| {
644 let slot = head.wrapping_add(i) % N;
645 unsafe { (*self.buf[slot].get()).assume_init_ref() }.clone()
647 })
648 .sum()
649 }
650
651 pub fn split(self) -> (SpscProducer<T, N>, SpscConsumer<T, N>) {
672 let shared = Arc::new(self);
673 (
674 SpscProducer {
675 inner: Arc::clone(&shared),
676 },
677 SpscConsumer { inner: shared },
678 )
679 }
680}
681
682impl<T, const N: usize> Drop for SpscRing<T, N> {
683 fn drop(&mut self) {
684 let head = self.head.load(Ordering::Relaxed);
688 let tail = self.tail.load(Ordering::Relaxed);
689 let mut idx = head;
690 while idx != tail {
691 let slot = idx & (N - 1);
692 unsafe {
694 (*self.buf[slot].get()).assume_init_drop();
695 }
696 idx = idx.wrapping_add(1);
697 }
698 }
699}
700
701impl<T, const N: usize> Default for SpscRing<T, N> {
702 fn default() -> Self {
703 Self::new()
704 }
705}
706
707pub struct SpscProducer<T, const N: usize> {
709 inner: Arc<SpscRing<T, N>>,
710}
711
712unsafe impl<T: Send, const N: usize> Send for SpscProducer<T, N> {}
715
716impl<T, const N: usize> SpscProducer<T, N> {
717 #[inline]
719 pub fn push(&self, item: T) -> Result<(), StreamError> {
720 self.inner.push(item)
721 }
722
723 #[inline]
727 pub fn try_push_or_drop(&self, item: T) -> bool {
728 self.inner.try_push_or_drop(item)
729 }
730
731 #[inline]
733 pub fn is_full(&self) -> bool {
734 self.inner.is_full()
735 }
736
737 #[inline]
739 pub fn is_empty(&self) -> bool {
740 self.inner.is_empty()
741 }
742
743 #[inline]
745 pub fn len(&self) -> usize {
746 self.inner.len()
747 }
748
749 #[inline]
751 pub fn available(&self) -> usize {
752 self.inner.capacity() - self.inner.len()
753 }
754
755 #[inline]
757 pub fn capacity(&self) -> usize {
758 self.inner.capacity()
759 }
760
761 #[inline]
766 pub fn fill_ratio(&self) -> f64 {
767 self.inner.len() as f64 / self.inner.capacity() as f64
768 }
769}
770
771pub struct SpscConsumer<T, const N: usize> {
773 inner: Arc<SpscRing<T, N>>,
774}
775
776unsafe impl<T: Send, const N: usize> Send for SpscConsumer<T, N> {}
779
780impl<T, const N: usize> SpscConsumer<T, N> {
781 #[inline]
783 pub fn pop(&self) -> Result<T, StreamError> {
784 self.inner.pop()
785 }
786
787 pub fn drain(&self) -> Vec<T> {
794 let mut out = Vec::with_capacity(self.inner.len());
795 while let Ok(item) = self.inner.pop() {
796 out.push(item);
797 }
798 out
799 }
800
801 #[inline]
803 pub fn is_empty(&self) -> bool {
804 self.inner.is_empty()
805 }
806
807 #[inline]
809 pub fn len(&self) -> usize {
810 self.inner.len()
811 }
812
813 #[inline]
815 pub fn capacity(&self) -> usize {
816 self.inner.capacity()
817 }
818
819 #[inline]
823 pub fn fill_ratio(&self) -> f64 {
824 self.inner.len() as f64 / self.inner.capacity() as f64
825 }
826
827 pub fn peek_clone(&self) -> Option<T>
833 where
834 T: Clone,
835 {
836 self.inner.peek_clone()
837 }
838
839 pub fn try_pop_n(&self, max: usize) -> Vec<T> {
847 let mut out = Vec::with_capacity(max.min(self.inner.len()));
848 while out.len() < max {
849 match self.inner.pop() {
850 Ok(item) => out.push(item),
851 Err(_) => break,
852 }
853 }
854 out
855 }
856
857 pub fn into_iter_drain(self) -> SpscDrainIter<T, N> {
862 SpscDrainIter { consumer: self }
863 }
864}
865
866pub struct SpscDrainIter<T, const N: usize> {
868 consumer: SpscConsumer<T, N>,
869}
870
871impl<T, const N: usize> Iterator for SpscDrainIter<T, N> {
872 type Item = T;
873
874 fn next(&mut self) -> Option<Self::Item> {
875 self.consumer.pop().ok()
876 }
877}
878
879#[cfg(test)]
880mod tests {
881 use super::*;
882 use std::thread;
883
884 #[test]
887 fn test_new_ring_is_empty() {
888 let r: SpscRing<u32, 8> = SpscRing::new();
889 assert!(r.is_empty());
890 assert_eq!(r.len(), 0);
891 }
892
893 #[test]
894 fn test_push_pop_single_item() {
895 let r: SpscRing<u32, 8> = SpscRing::new();
896 r.push(42).unwrap();
897 assert_eq!(r.pop().unwrap(), 42);
898 }
899
900 #[test]
901 fn test_pop_empty_returns_ring_buffer_empty() {
902 let r: SpscRing<u32, 8> = SpscRing::new();
903 let err = r.pop().unwrap_err();
904 assert!(matches!(err, StreamError::RingBufferEmpty));
905 }
906
907 #[test]
909 fn test_capacity_is_n_minus_1() {
910 let r: SpscRing<u32, 8> = SpscRing::new();
911 assert_eq!(r.capacity(), 7);
912 }
913
914 #[test]
918 fn test_fill_to_exact_capacity_then_overflow() {
919 let r: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
921 r.push(i).unwrap();
922 }
923 assert!(r.is_full());
924 let err = r.push(99).unwrap_err();
925 assert!(matches!(err, StreamError::RingBufferFull { capacity: 7 }));
926 }
927
928 #[test]
929 fn test_push_n_minus_1_pop_one_push_one() {
930 let r: SpscRing<u32, 8> = SpscRing::new();
931 for i in 0..7u32 {
932 r.push(i).unwrap();
933 }
934 assert_eq!(r.pop().unwrap(), 0);
935 r.push(100).unwrap();
936 assert_eq!(r.len(), 7);
937 }
938
939 #[test]
940 fn test_push_n_plus_1_returns_full_error() {
941 let r: SpscRing<u32, 4> = SpscRing::new(); r.push(1).unwrap();
943 r.push(2).unwrap();
944 r.push(3).unwrap();
945 assert!(r.is_full());
946 let e1 = r.push(4).unwrap_err();
947 let e2 = r.push(5).unwrap_err();
948 assert!(matches!(e1, StreamError::RingBufferFull { .. }));
949 assert!(matches!(e2, StreamError::RingBufferFull { .. }));
950 }
951
952 #[test]
955 fn test_fifo_ordering() {
956 let r: SpscRing<u32, 16> = SpscRing::new();
957 for i in 0..10u32 {
958 r.push(i).unwrap();
959 }
960 for i in 0..10u32 {
961 assert_eq!(r.pop().unwrap(), i);
962 }
963 }
964
965 #[test]
969 fn test_wraparound_correctness() {
970 let r: SpscRing<u32, 4> = SpscRing::new(); r.push(1).unwrap();
972 r.push(2).unwrap();
973 r.push(3).unwrap();
974 assert_eq!(r.pop().unwrap(), 1);
975 assert_eq!(r.pop().unwrap(), 2);
976 assert_eq!(r.pop().unwrap(), 3);
977 r.push(10).unwrap();
978 r.push(20).unwrap();
979 r.push(30).unwrap();
980 assert_eq!(r.pop().unwrap(), 10);
981 assert_eq!(r.pop().unwrap(), 20);
982 assert_eq!(r.pop().unwrap(), 30);
983 }
984
985 #[test]
986 fn test_wraparound_many_cycles() {
987 let r: SpscRing<u64, 8> = SpscRing::new(); for cycle in 0u64..20 {
989 for i in 0..5 {
990 r.push(cycle * 100 + i).unwrap();
991 }
992 for i in 0..5 {
993 let v = r.pop().unwrap();
994 assert_eq!(v, cycle * 100 + i);
995 }
996 }
997 }
998
999 #[test]
1002 fn test_is_full_false_when_one_slot_free() {
1003 let r: SpscRing<u32, 4> = SpscRing::new(); r.push(1).unwrap();
1005 r.push(2).unwrap();
1006 assert!(!r.is_full());
1007 r.push(3).unwrap();
1008 assert!(r.is_full());
1009 }
1010
1011 #[test]
1012 fn test_is_empty_after_drain() {
1013 let r: SpscRing<u32, 4> = SpscRing::new();
1014 r.push(1).unwrap();
1015 r.push(2).unwrap();
1016 r.pop().unwrap();
1017 r.pop().unwrap();
1018 assert!(r.is_empty());
1019 }
1020
1021 #[test]
1025 fn test_drop_drains_remaining_items() {
1026 use std::sync::atomic::{AtomicUsize, Ordering};
1027 use std::sync::Arc;
1028
1029 let drop_count = Arc::new(AtomicUsize::new(0));
1030
1031 struct Counted(Arc<AtomicUsize>);
1032 impl Drop for Counted {
1033 fn drop(&mut self) {
1034 self.0.fetch_add(1, Ordering::Relaxed);
1035 }
1036 }
1037
1038 let ring: SpscRing<Counted, 8> = SpscRing::new();
1039 ring.push(Counted(Arc::clone(&drop_count))).unwrap();
1040 ring.push(Counted(Arc::clone(&drop_count))).unwrap();
1041 ring.push(Counted(Arc::clone(&drop_count))).unwrap();
1042 drop(ring);
1043 assert_eq!(drop_count.load(Ordering::Relaxed), 3);
1044 }
1045
1046 #[test]
1051 fn test_concurrent_producer_consumer() {
1052 const ITEMS: u64 = 10_000;
1053 let ring: SpscRing<u64, 256> = SpscRing::new();
1054 let (prod, cons) = ring.split();
1055
1056 let producer = thread::spawn(move || {
1057 let mut sent = 0u64;
1058 while sent < ITEMS {
1059 if prod.push(sent).is_ok() {
1060 sent += 1;
1061 }
1062 }
1063 });
1064
1065 let consumer = thread::spawn(move || {
1066 let mut received = Vec::with_capacity(ITEMS as usize);
1067 while received.len() < ITEMS as usize {
1068 if let Ok(v) = cons.pop() {
1069 received.push(v);
1070 }
1071 }
1072 received
1073 });
1074
1075 producer.join().unwrap();
1076 let received = consumer.join().unwrap();
1077 assert_eq!(received.len(), ITEMS as usize);
1078 for (i, &v) in received.iter().enumerate() {
1079 assert_eq!(v, i as u64, "FIFO ordering violated at index {i}");
1080 }
1081 }
1082
1083 #[test]
1086 fn test_throughput_100k_round_trips() {
1087 const ITEMS: usize = 100_000;
1088 let ring: SpscRing<u64, 1024> = SpscRing::new();
1089 let (prod, cons) = ring.split();
1090
1091 let producer = thread::spawn(move || {
1092 let mut sent = 0usize;
1093 while sent < ITEMS {
1094 if prod.push(sent as u64).is_ok() {
1095 sent += 1;
1096 }
1097 }
1098 });
1099
1100 let consumer = thread::spawn(move || {
1101 let mut count = 0usize;
1102 while count < ITEMS {
1103 if cons.pop().is_ok() {
1104 count += 1;
1105 }
1106 }
1107 count
1108 });
1109
1110 producer.join().unwrap();
1111 let count = consumer.join().unwrap();
1112 assert_eq!(count, ITEMS);
1113 }
1114
1115 #[test]
1118 fn test_split_producer_push_consumer_pop() {
1119 let ring: SpscRing<u32, 16> = SpscRing::new();
1120 let (prod, cons) = ring.split();
1121 prod.push(7).unwrap();
1122 assert_eq!(cons.pop().unwrap(), 7);
1123 }
1124
1125 #[test]
1126 fn test_producer_is_full_matches_ring() {
1127 let ring: SpscRing<u32, 4> = SpscRing::new();
1128 let (prod, cons) = ring.split();
1129 prod.push(1).unwrap();
1130 prod.push(2).unwrap();
1131 prod.push(3).unwrap();
1132 assert!(prod.is_full());
1133 cons.pop().unwrap();
1134 assert!(!prod.is_full());
1135 }
1136
1137 #[test]
1138 fn test_consumer_len_and_is_empty() {
1139 let ring: SpscRing<u32, 8> = SpscRing::new();
1140 let (prod, cons) = ring.split();
1141 assert!(cons.is_empty());
1142 prod.push(1).unwrap();
1143 prod.push(2).unwrap();
1144 assert_eq!(cons.len(), 2);
1145 assert!(!cons.is_empty());
1146 }
1147
1148 #[test]
1149 fn test_producer_is_empty_initially_true() {
1150 let ring: SpscRing<u32, 8> = SpscRing::new();
1151 let (prod, _cons) = ring.split();
1152 assert!(prod.is_empty());
1153 }
1154
1155 #[test]
1156 fn test_producer_is_empty_false_after_push() {
1157 let ring: SpscRing<u32, 8> = SpscRing::new();
1158 let (prod, _cons) = ring.split();
1159 prod.push(1).unwrap();
1160 assert!(!prod.is_empty());
1161 }
1162
1163 #[test]
1164 fn test_producer_len_matches_consumer_len() {
1165 let ring: SpscRing<u32, 8> = SpscRing::new();
1166 let (prod, cons) = ring.split();
1167 assert_eq!(prod.len(), 0);
1168 prod.push(10).unwrap();
1169 prod.push(20).unwrap();
1170 assert_eq!(prod.len(), 2);
1171 assert_eq!(cons.len(), 2);
1172 }
1173
1174 #[test]
1178 fn test_minimum_power_of_two_size() {
1179 let ring: SpscRing<u32, 2> = SpscRing::new(); assert_eq!(ring.capacity(), 1);
1181 ring.push(99).unwrap();
1182 assert!(ring.is_full());
1183 assert_eq!(ring.pop().unwrap(), 99);
1184 assert!(ring.is_empty());
1185 }
1186
1187 #[test]
1189 fn test_large_power_of_two_size() {
1190 let ring: SpscRing<u64, 1024> = SpscRing::new();
1191 assert_eq!(ring.capacity(), 1023);
1192 }
1193
1194 #[test]
1197 fn test_drain_iter_yields_fifo_order() {
1198 let ring: SpscRing<u32, 8> = SpscRing::new();
1199 let (prod, cons) = ring.split();
1200 prod.push(1).unwrap();
1201 prod.push(2).unwrap();
1202 prod.push(3).unwrap();
1203 let items: Vec<u32> = cons.into_iter_drain().collect();
1204 assert_eq!(items, vec![1, 2, 3]);
1205 }
1206
1207 #[test]
1208 fn test_drain_iter_empty_ring_yields_nothing() {
1209 let ring: SpscRing<u32, 8> = SpscRing::new();
1210 let (_, cons) = ring.split();
1211 let items: Vec<u32> = cons.into_iter_drain().collect();
1212 assert!(items.is_empty());
1213 }
1214
1215 #[test]
1220 fn test_peek_clone_empty_returns_none() {
1221 let r: SpscRing<u32, 8> = SpscRing::new();
1222 assert!(r.peek_clone().is_none());
1223 }
1224
1225 #[test]
1226 fn test_peek_clone_does_not_consume() {
1227 let r: SpscRing<u32, 8> = SpscRing::new();
1228 r.push(42).unwrap();
1229 assert_eq!(r.peek_clone(), Some(42));
1230 assert_eq!(r.peek_clone(), Some(42)); assert_eq!(r.pop().unwrap(), 42);
1232 assert!(r.is_empty());
1233 }
1234
1235 #[test]
1236 fn test_peek_clone_via_consumer() {
1237 let ring: SpscRing<u32, 8> = SpscRing::new();
1238 let (prod, cons) = ring.split();
1239 prod.push(7).unwrap();
1240 prod.push(8).unwrap();
1241 assert_eq!(cons.peek_clone(), Some(7)); assert_eq!(cons.pop().unwrap(), 7); assert_eq!(cons.peek_clone(), Some(8)); }
1245
1246 proptest::proptest! {
1247 #[test]
1250 fn prop_fifo_ordering_with_wraparound(
1251 batches in proptest::collection::vec(
1253 proptest::collection::vec(0u32..=u32::MAX, 1..=7),
1254 1..=20,
1255 )
1256 ) {
1257 let ring: SpscRing<u32, 8> = SpscRing::new();
1259 let mut oracle: std::collections::VecDeque<u32> = std::collections::VecDeque::new();
1260
1261 for batch in &batches {
1262 for &item in batch {
1264 if ring.push(item).is_ok() {
1265 oracle.push_back(item);
1266 }
1267 }
1268 while let Ok(popped) = ring.pop() {
1270 let expected = oracle.pop_front().expect("oracle must have matching item");
1271 proptest::prop_assert_eq!(popped, expected);
1272 }
1273 }
1274 }
1275 }
1276
1277 #[test]
1280 fn test_try_pop_n_empty_returns_empty_vec() {
1281 let ring: SpscRing<u32, 8> = SpscRing::new();
1282 let (_, consumer) = ring.split();
1283 assert!(consumer.try_pop_n(5).is_empty());
1284 }
1285
1286 #[test]
1287 fn test_try_pop_n_bounded_by_max() {
1288 let ring: SpscRing<u32, 8> = SpscRing::new();
1289 let (producer, consumer) = ring.split();
1290 for i in 0..5 {
1291 producer.push(i).unwrap();
1292 }
1293 let batch = consumer.try_pop_n(3);
1294 assert_eq!(batch.len(), 3);
1295 assert_eq!(batch, vec![0, 1, 2]);
1296 assert_eq!(consumer.len(), 2);
1298 }
1299
1300 #[test]
1301 fn test_try_pop_n_larger_than_available_returns_all() {
1302 let ring: SpscRing<u32, 8> = SpscRing::new();
1303 let (producer, consumer) = ring.split();
1304 for i in 0..3 {
1305 producer.push(i).unwrap();
1306 }
1307 let batch = consumer.try_pop_n(100);
1308 assert_eq!(batch.len(), 3);
1309 assert!(consumer.is_empty());
1310 }
1311
1312 #[test]
1315 fn test_producer_capacity_equals_ring_capacity() {
1316 let ring: SpscRing<u32, 8> = SpscRing::new(); let (producer, consumer) = ring.split();
1318 assert_eq!(producer.capacity(), 7);
1319 assert_eq!(consumer.capacity(), 7);
1320 }
1321
1322 #[test]
1323 fn test_capacity_consistent_with_max_items() {
1324 let ring: SpscRing<u32, 4> = SpscRing::new(); let (producer, consumer) = ring.split();
1326 for i in 0..3 {
1327 producer.push(i).unwrap();
1328 }
1329 assert_eq!(consumer.capacity(), 3);
1331 assert_eq!(consumer.len(), 3);
1332 }
1333
1334 #[test]
1337 fn test_fill_ratio_empty_is_zero() {
1338 let ring: SpscRing<u32, 8> = SpscRing::new();
1339 let (_, consumer) = ring.split();
1340 assert!((consumer.fill_ratio() - 0.0).abs() < 1e-9);
1341 }
1342
1343 #[test]
1344 fn test_fill_ratio_full_is_one() {
1345 let ring: SpscRing<u32, 4> = SpscRing::new(); let (producer, consumer) = ring.split();
1347 for i in 0..3 {
1348 producer.push(i).unwrap();
1349 }
1350 assert!((consumer.fill_ratio() - 1.0).abs() < 1e-9);
1351 }
1352
1353 #[test]
1354 fn test_fill_ratio_partial() {
1355 let ring: SpscRing<u32, 8> = SpscRing::new(); let (producer, consumer) = ring.split();
1357 for i in 0..7 {
1359 producer.push(i).unwrap();
1360 }
1361 consumer.pop().unwrap();
1363 consumer.pop().unwrap();
1364 consumer.pop().unwrap();
1365 consumer.pop().unwrap();
1366 let ratio = consumer.fill_ratio();
1367 assert!((ratio - 3.0 / 7.0).abs() < 1e-9, "got {ratio}");
1368 }
1369
1370 #[test]
1373 fn test_producer_fill_ratio_empty_is_zero() {
1374 let ring: SpscRing<u32, 8> = SpscRing::new();
1375 let (producer, _) = ring.split();
1376 assert!((producer.fill_ratio() - 0.0).abs() < 1e-9);
1377 }
1378
1379 #[test]
1380 fn test_producer_fill_ratio_full_is_one() {
1381 let ring: SpscRing<u32, 4> = SpscRing::new(); let (producer, _) = ring.split();
1383 for i in 0..3 {
1384 producer.push(i).unwrap();
1385 }
1386 assert!((producer.fill_ratio() - 1.0).abs() < 1e-9);
1387 }
1388
1389 #[test]
1390 fn test_producer_and_consumer_fill_ratio_agree() {
1391 let ring: SpscRing<u32, 8> = SpscRing::new();
1392 let (producer, consumer) = ring.split();
1393 producer.push(1).unwrap();
1394 producer.push(2).unwrap();
1395 assert!((producer.fill_ratio() - consumer.fill_ratio()).abs() < 1e-9);
1396 }
1397
1398 #[test]
1399 fn test_peek_all_empty_returns_empty_vec() {
1400 let ring: SpscRing<u32, 8> = SpscRing::new();
1401 assert!(ring.peek_all().is_empty());
1402 }
1403
1404 #[test]
1405 fn test_peek_all_does_not_consume() {
1406 let ring: SpscRing<u32, 8> = SpscRing::new();
1407 ring.push(1).unwrap();
1408 ring.push(2).unwrap();
1409 ring.push(3).unwrap();
1410 let snapshot = ring.peek_all();
1411 assert_eq!(snapshot, vec![1, 2, 3]);
1412 assert_eq!(ring.len(), 3);
1414 }
1415
1416 #[test]
1417 fn test_peek_all_fifo_order_after_pop() {
1418 let ring: SpscRing<u32, 16> = SpscRing::new();
1419 for i in 0..5u32 {
1420 ring.push(i).unwrap();
1421 }
1422 ring.pop().unwrap(); let snapshot = ring.peek_all();
1424 assert_eq!(snapshot, vec![1, 2, 3, 4]);
1425 }
1426
1427 #[test]
1428 fn test_drain_into_appends_to_buf() {
1429 let ring: SpscRing<u32, 8> = SpscRing::new();
1430 ring.push(10).unwrap();
1431 ring.push(20).unwrap();
1432 let mut buf = vec![1u32, 2];
1433 ring.drain_into(&mut buf);
1434 assert_eq!(buf, vec![1, 2, 10, 20]);
1435 assert!(ring.is_empty());
1436 }
1437
1438 #[test]
1439 fn test_drain_into_empty_ring_leaves_buf_unchanged() {
1440 let ring: SpscRing<u32, 8> = SpscRing::new();
1441 let mut buf = vec![42u32];
1442 ring.drain_into(&mut buf);
1443 assert_eq!(buf, vec![42]);
1444 }
1445
1446 #[test]
1449 fn test_peek_newest_none_when_empty() {
1450 let ring: SpscRing<u32, 8> = SpscRing::new();
1451 assert!(ring.peek_newest().is_none());
1452 }
1453
1454 #[test]
1455 fn test_peek_newest_returns_last_pushed() {
1456 let ring: SpscRing<u32, 8> = SpscRing::new();
1457 ring.push(10).unwrap();
1458 ring.push(20).unwrap();
1459 ring.push(30).unwrap();
1460 assert_eq!(ring.peek_newest(), Some(30));
1461 }
1462
1463 #[test]
1464 fn test_peek_newest_does_not_consume() {
1465 let ring: SpscRing<u32, 8> = SpscRing::new();
1466 ring.push(42).unwrap();
1467 let _ = ring.peek_newest();
1468 assert_eq!(ring.len(), 1);
1469 }
1470
1471 #[test]
1474 fn test_fill_ratio_zero_when_empty() {
1475 let ring: SpscRing<u32, 8> = SpscRing::new();
1476 assert_eq!(ring.fill_ratio(), 0.0);
1477 }
1478
1479 #[test]
1480 fn test_fill_ratio_one_when_full() {
1481 let ring: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
1483 ring.push(i).unwrap();
1484 }
1485 assert!((ring.fill_ratio() - 1.0).abs() < 1e-10);
1486 }
1487
1488 #[test]
1489 fn test_fill_ratio_half_when_half_full() {
1490 let ring: SpscRing<u32, 8> = SpscRing::new(); ring.push(1).unwrap();
1493 ring.push(2).unwrap();
1494 ring.push(3).unwrap();
1495 let ratio = ring.fill_ratio();
1496 assert!((ratio - 3.0 / 7.0).abs() < 1e-10);
1497 }
1498
1499 #[test]
1502 fn test_utilization_pct_zero_when_empty() {
1503 let ring: SpscRing<u32, 8> = SpscRing::new();
1504 assert_eq!(ring.utilization_pct(), 0.0);
1505 }
1506
1507 #[test]
1508 fn test_utilization_pct_100_when_full() {
1509 let ring: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
1511 ring.push(i).unwrap();
1512 }
1513 assert!((ring.utilization_pct() - 100.0).abs() < 1e-10);
1514 }
1515
1516 #[test]
1517 fn test_utilization_pct_equals_fill_ratio_times_100() {
1518 let ring: SpscRing<u32, 8> = SpscRing::new();
1519 ring.push(1u32).unwrap();
1520 ring.push(2u32).unwrap();
1521 let ratio = ring.fill_ratio();
1522 assert!((ring.utilization_pct() - ratio * 100.0).abs() < 1e-10);
1523 }
1524
1525 #[test]
1528 fn test_remaining_capacity_full_when_empty() {
1529 let ring: SpscRing<u32, 8> = SpscRing::new(); assert_eq!(ring.remaining_capacity(), 7);
1531 }
1532
1533 #[test]
1534 fn test_remaining_capacity_decreases_on_push() {
1535 let ring: SpscRing<u32, 8> = SpscRing::new();
1536 ring.push(1u32).unwrap();
1537 ring.push(2u32).unwrap();
1538 assert_eq!(ring.remaining_capacity(), 5);
1539 }
1540
1541 #[test]
1542 fn test_remaining_capacity_zero_when_full() {
1543 let ring: SpscRing<u32, 8> = SpscRing::new();
1544 for i in 0..7u32 {
1545 ring.push(i).unwrap();
1546 }
1547 assert_eq!(ring.remaining_capacity(), 0);
1548 }
1549
1550 #[test]
1553 fn test_is_nearly_full_false_when_empty() {
1554 let ring: SpscRing<u32, 8> = SpscRing::new();
1555 assert!(!ring.is_nearly_full(0.5));
1556 }
1557
1558 #[test]
1559 fn test_is_nearly_full_true_when_at_threshold() {
1560 let ring: SpscRing<u32, 8> = SpscRing::new(); for i in 0..7u32 {
1563 ring.push(i).unwrap();
1564 }
1565 assert!(ring.is_nearly_full(0.9));
1566 }
1567
1568 #[test]
1569 fn test_is_nearly_full_false_when_below_threshold() {
1570 let ring: SpscRing<u32, 8> = SpscRing::new(); ring.push(1u32).unwrap(); assert!(!ring.is_nearly_full(0.9));
1573 }
1574
1575 #[test]
1578 fn test_first_none_when_empty() {
1579 let ring: SpscRing<u32, 8> = SpscRing::new();
1580 assert!(ring.first().is_none());
1581 }
1582
1583 #[test]
1584 fn test_first_returns_oldest_copy() {
1585 let ring: SpscRing<u32, 8> = SpscRing::new();
1586 ring.push(42u32).unwrap();
1587 ring.push(99u32).unwrap();
1588 assert_eq!(ring.first(), Some(42u32));
1589 }
1590
1591 #[test]
1592 fn test_first_does_not_remove() {
1593 let ring: SpscRing<u32, 8> = SpscRing::new();
1594 ring.push(7u32).unwrap();
1595 let _ = ring.first();
1596 assert_eq!(ring.len(), 1);
1597 }
1598
1599 #[test]
1602 fn test_peek_front_none_when_empty() {
1603 let ring: SpscRing<u32, 8> = SpscRing::new();
1604 assert!(ring.peek_front().is_none());
1605 }
1606
1607 #[test]
1608 fn test_peek_front_returns_oldest_item() {
1609 let ring: SpscRing<u32, 8> = SpscRing::new();
1610 ring.push(10u32).unwrap();
1611 ring.push(20u32).unwrap();
1612 assert_eq!(ring.peek_front(), Some(&10u32));
1613 }
1614
1615 #[test]
1616 fn test_peek_front_does_not_remove_item() {
1617 let ring: SpscRing<u32, 8> = SpscRing::new();
1618 ring.push(42u32).unwrap();
1619 let _ = ring.peek_front();
1620 assert_eq!(ring.len(), 1);
1621 }
1622
1623 #[test]
1624 fn test_peek_back_none_when_empty() {
1625 let ring: SpscRing<u32, 8> = SpscRing::new();
1626 assert!(ring.peek_back().is_none());
1627 }
1628
1629 #[test]
1630 fn test_peek_back_returns_newest_item() {
1631 let ring: SpscRing<u32, 8> = SpscRing::new();
1632 ring.push(10u32).unwrap();
1633 ring.push(20u32).unwrap();
1634 assert_eq!(ring.peek_back(), Some(&20u32));
1635 }
1636
1637 #[test]
1640 fn test_to_vec_cloned_empty() {
1641 let ring: SpscRing<u32, 8> = SpscRing::new();
1642 assert_eq!(ring.to_vec_cloned(), Vec::<u32>::new());
1643 }
1644
1645 #[test]
1646 fn test_to_vec_cloned_preserves_fifo_order() {
1647 let ring: SpscRing<u32, 8> = SpscRing::new();
1648 ring.push(1u32).unwrap();
1649 ring.push(2u32).unwrap();
1650 ring.push(3u32).unwrap();
1651 assert_eq!(ring.to_vec_cloned(), vec![1u32, 2, 3]);
1652 }
1653
1654 #[test]
1655 fn test_to_vec_cloned_does_not_drain() {
1656 let ring: SpscRing<u32, 8> = SpscRing::new();
1657 ring.push(42u32).unwrap();
1658 let _ = ring.to_vec_cloned();
1659 assert_eq!(ring.len(), 1);
1660 }
1661
1662 #[test]
1665 fn test_min_cloned_none_when_empty() {
1666 let ring: SpscRing<u32, 8> = SpscRing::new();
1667 assert!(ring.min_cloned().is_none());
1668 }
1669
1670 #[test]
1671 fn test_min_cloned_returns_minimum() {
1672 let ring: SpscRing<u32, 8> = SpscRing::new();
1673 ring.push(3u32).unwrap();
1674 ring.push(1u32).unwrap();
1675 ring.push(4u32).unwrap();
1676 ring.push(2u32).unwrap();
1677 assert_eq!(ring.min_cloned(), Some(1u32));
1678 }
1679
1680 #[test]
1681 fn test_min_cloned_does_not_drain() {
1682 let ring: SpscRing<u32, 8> = SpscRing::new();
1683 ring.push(10u32).unwrap();
1684 let _ = ring.min_cloned();
1685 assert_eq!(ring.len(), 1);
1686 }
1687
1688 #[test]
1691 fn test_max_cloned_none_when_empty() {
1692 let ring: SpscRing<u32, 8> = SpscRing::new();
1693 assert!(ring.max_cloned().is_none());
1694 }
1695
1696 #[test]
1697 fn test_max_cloned_returns_maximum() {
1698 let ring: SpscRing<u32, 8> = SpscRing::new();
1699 ring.push(3u32).unwrap();
1700 ring.push(1u32).unwrap();
1701 ring.push(4u32).unwrap();
1702 ring.push(2u32).unwrap();
1703 assert_eq!(ring.max_cloned(), Some(4u32));
1704 }
1705
1706 #[test]
1707 fn test_max_cloned_does_not_drain() {
1708 let ring: SpscRing<u32, 8> = SpscRing::new();
1709 ring.push(10u32).unwrap();
1710 let _ = ring.max_cloned();
1711 assert_eq!(ring.len(), 1);
1712 }
1713
1714 #[test]
1717 fn test_count_if_zero_when_empty() {
1718 let ring: SpscRing<u32, 8> = SpscRing::new();
1719 assert_eq!(ring.count_if(|_| true), 0);
1720 }
1721
1722 #[test]
1723 fn test_count_if_counts_matching_items() {
1724 let ring: SpscRing<u32, 8> = SpscRing::new();
1725 for i in 1u32..=6 {
1726 ring.push(i).unwrap();
1727 }
1728 assert_eq!(ring.count_if(|x| x % 2 == 0), 3);
1730 }
1731
1732 #[test]
1733 fn test_count_if_all_match() {
1734 let ring: SpscRing<u32, 8> = SpscRing::new();
1735 ring.push(10u32).unwrap();
1736 ring.push(20u32).unwrap();
1737 assert_eq!(ring.count_if(|_| true), 2);
1738 }
1739
1740 #[test]
1742 fn test_has_capacity_true_on_empty_ring() {
1743 let ring: SpscRing<u32, 8> = SpscRing::new(); assert!(ring.has_capacity(7));
1745 }
1746
1747 #[test]
1748 fn test_has_capacity_false_when_full() {
1749 let ring: SpscRing<u32, 8> = SpscRing::new();
1750 for i in 0..7u32 {
1751 ring.push(i).unwrap();
1752 }
1753 assert!(!ring.has_capacity(1));
1754 }
1755
1756 #[test]
1757 fn test_has_capacity_false_for_zero_capacity_needed() {
1758 let ring: SpscRing<u32, 4> = SpscRing::new();
1759 assert!(ring.has_capacity(0));
1761 }
1762
1763 #[test]
1764 fn test_has_capacity_partial_fill() {
1765 let ring: SpscRing<u32, 8> = SpscRing::new(); ring.push(1u32).unwrap();
1767 ring.push(2u32).unwrap();
1768 assert!(ring.has_capacity(5));
1770 assert!(!ring.has_capacity(6));
1771 }
1772
1773 #[test]
1775 fn test_is_empty_true_for_new_ring() {
1776 let ring: SpscRing<u32, 8> = SpscRing::new();
1777 assert!(ring.is_empty());
1778 }
1779
1780 #[test]
1781 fn test_is_empty_false_after_push() {
1782 let ring: SpscRing<u32, 8> = SpscRing::new();
1783 ring.push(42u32).unwrap();
1784 assert!(!ring.is_empty());
1785 }
1786
1787 #[test]
1788 fn test_is_empty_true_after_push_and_pop() {
1789 let ring: SpscRing<u32, 4> = SpscRing::new();
1790 ring.push(1u32).unwrap();
1791 let _ = ring.pop();
1792 assert!(ring.is_empty());
1793 }
1794
1795 #[test]
1797 fn test_peek_oldest_none_on_empty_ring() {
1798 let ring: SpscRing<u32, 8> = SpscRing::new();
1799 assert!(ring.peek_oldest().is_none());
1800 }
1801
1802 #[test]
1803 fn test_peek_oldest_returns_first_pushed_item() {
1804 let ring: SpscRing<u32, 8> = SpscRing::new();
1805 ring.push(10u32).unwrap();
1806 ring.push(20u32).unwrap();
1807 ring.push(30u32).unwrap();
1808 assert_eq!(ring.peek_oldest(), Some(10));
1810 }
1811
1812 #[test]
1813 fn test_peek_oldest_does_not_remove_item() {
1814 let ring: SpscRing<u32, 4> = SpscRing::new();
1815 ring.push(5u32).unwrap();
1816 let _ = ring.peek_oldest();
1817 assert_eq!(ring.pop().unwrap(), 5);
1819 }
1820
1821 #[test]
1822 fn test_peek_oldest_different_from_peek_newest_when_multiple_items() {
1823 let ring: SpscRing<u32, 8> = SpscRing::new();
1824 ring.push(1u32).unwrap();
1825 ring.push(2u32).unwrap();
1826 ring.push(3u32).unwrap();
1827 assert_eq!(ring.peek_oldest(), Some(1));
1828 assert_eq!(ring.peek_newest(), Some(3));
1829 }
1830
1831 #[test]
1834 fn test_sum_cloned_empty_returns_default() {
1835 let ring: SpscRing<u32, 4> = SpscRing::new();
1836 assert_eq!(ring.sum_cloned(), 0u32);
1837 }
1838
1839 #[test]
1840 fn test_sum_cloned_single_element() {
1841 let ring: SpscRing<u32, 4> = SpscRing::new();
1842 ring.push(42u32).unwrap();
1843 assert_eq!(ring.sum_cloned(), 42u32);
1844 }
1845
1846 #[test]
1847 fn test_sum_cloned_multiple_elements() {
1848 let ring: SpscRing<u32, 8> = SpscRing::new();
1849 for v in [1u32, 2, 3, 4, 5] { ring.push(v).unwrap(); }
1850 assert_eq!(ring.sum_cloned(), 15u32);
1851 }
1852
1853 #[test]
1854 fn test_sum_cloned_after_pop_reflects_remaining() {
1855 let ring: SpscRing<u32, 4> = SpscRing::new();
1856 ring.push(10u32).unwrap();
1857 ring.push(20u32).unwrap();
1858 ring.pop().unwrap(); assert_eq!(ring.sum_cloned(), 20u32);
1860 }
1861
1862 #[test]
1865 fn test_average_cloned_none_when_empty() {
1866 let ring: SpscRing<f64, 4> = SpscRing::new();
1867 assert!(ring.average_cloned().is_none());
1868 }
1869
1870 #[test]
1871 fn test_average_cloned_single_element() {
1872 let ring: SpscRing<f64, 4> = SpscRing::new();
1873 ring.push(6.0f64).unwrap();
1874 assert_eq!(ring.average_cloned(), Some(6.0));
1875 }
1876
1877 #[test]
1878 fn test_average_cloned_multiple_elements() {
1879 let ring: SpscRing<f64, 8> = SpscRing::new();
1880 for v in [2.0f64, 4.0, 6.0, 8.0] { ring.push(v).unwrap(); }
1881 assert_eq!(ring.average_cloned(), Some(5.0));
1882 }
1883
1884 #[test]
1887 fn test_peek_nth_returns_oldest_at_index_zero() {
1888 let ring: SpscRing<u32, 8> = SpscRing::new();
1889 ring.push(10u32).unwrap();
1890 ring.push(20u32).unwrap();
1891 ring.push(30u32).unwrap();
1892 assert_eq!(ring.peek_nth(0), Some(10));
1893 }
1894
1895 #[test]
1896 fn test_peek_nth_returns_correct_element() {
1897 let ring: SpscRing<u32, 8> = SpscRing::new();
1898 ring.push(10u32).unwrap();
1899 ring.push(20u32).unwrap();
1900 ring.push(30u32).unwrap();
1901 assert_eq!(ring.peek_nth(1), Some(20));
1902 assert_eq!(ring.peek_nth(2), Some(30));
1903 }
1904
1905 #[test]
1906 fn test_peek_nth_returns_none_when_out_of_bounds() {
1907 let ring: SpscRing<u32, 4> = SpscRing::new();
1908 ring.push(5u32).unwrap();
1909 assert!(ring.peek_nth(1).is_none());
1910 }
1911
1912 #[test]
1915 fn test_contains_cloned_false_when_empty() {
1916 let ring: SpscRing<u32, 4> = SpscRing::new();
1917 assert!(!ring.contains_cloned(&42u32));
1918 }
1919
1920 #[test]
1921 fn test_contains_cloned_true_when_value_present() {
1922 let ring: SpscRing<u32, 8> = SpscRing::new();
1923 ring.push(10u32).unwrap();
1924 ring.push(20u32).unwrap();
1925 assert!(ring.contains_cloned(&10u32));
1926 assert!(ring.contains_cloned(&20u32));
1927 }
1928
1929 #[test]
1930 fn test_contains_cloned_false_when_value_absent() {
1931 let ring: SpscRing<u32, 4> = SpscRing::new();
1932 ring.push(5u32).unwrap();
1933 assert!(!ring.contains_cloned(&99u32));
1934 }
1935
1936 #[test]
1939 fn test_max_cloned_by_none_when_empty() {
1940 let ring: SpscRing<u32, 4> = SpscRing::new();
1941 assert!(ring.max_cloned_by(|&x| x).is_none());
1942 }
1943
1944 #[test]
1945 fn test_max_cloned_by_returns_max_element() {
1946 let ring: SpscRing<u32, 8> = SpscRing::new();
1947 ring.push(3u32).unwrap();
1948 ring.push(1u32).unwrap();
1949 ring.push(7u32).unwrap();
1950 ring.push(2u32).unwrap();
1951 assert_eq!(ring.max_cloned_by(|&x| x), Some(7));
1952 }
1953
1954 #[test]
1955 fn test_max_cloned_by_custom_key() {
1956 let ring: SpscRing<i32, 8> = SpscRing::new();
1957 ring.push(-5i32).unwrap();
1958 ring.push(3i32).unwrap();
1959 ring.push(-10i32).unwrap();
1960 assert_eq!(ring.max_cloned_by(|&x| x.abs()), Some(-10));
1962 }
1963
1964 #[test]
1967 fn test_min_cloned_by_none_when_empty() {
1968 let ring: SpscRing<u32, 4> = SpscRing::new();
1969 assert!(ring.min_cloned_by(|&x| x).is_none());
1970 }
1971
1972 #[test]
1973 fn test_min_cloned_by_returns_min_element() {
1974 let ring: SpscRing<u32, 8> = SpscRing::new();
1975 ring.push(3u32).unwrap();
1976 ring.push(1u32).unwrap();
1977 ring.push(7u32).unwrap();
1978 assert_eq!(ring.min_cloned_by(|&x| x), Some(1));
1979 }
1980
1981 #[test]
1982 fn test_min_cloned_by_custom_key() {
1983 let ring: SpscRing<i32, 8> = SpscRing::new();
1984 ring.push(-5i32).unwrap();
1985 ring.push(3i32).unwrap();
1986 ring.push(-1i32).unwrap();
1987 assert_eq!(ring.min_cloned_by(|&x| x.abs()), Some(-1));
1989 }
1990
1991 #[test]
1994 fn test_to_vec_sorted_empty() {
1995 let ring: SpscRing<u32, 4> = SpscRing::new();
1996 assert_eq!(ring.to_vec_sorted(), Vec::<u32>::new());
1997 }
1998
1999 #[test]
2000 fn test_to_vec_sorted_returns_sorted_elements() {
2001 let ring: SpscRing<u32, 8> = SpscRing::new();
2002 ring.push(5u32).unwrap();
2003 ring.push(1u32).unwrap();
2004 ring.push(3u32).unwrap();
2005 assert_eq!(ring.to_vec_sorted(), vec![1u32, 3, 5]);
2006 }
2007}