1use std::cell::UnsafeCell;
40use std::mem::MaybeUninit;
41use std::sync::atomic::{AtomicUsize, Ordering};
42
43#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
49pub enum RingBufferError {
50 #[error("ring buffer is full (capacity {capacity})")]
52 Full {
53 capacity: usize,
55 },
56 #[error("ring buffer capacity must be at least 1")]
58 ZeroCapacity,
59}
60
61pub struct LockFreeRingBuffer<T: Copy + Send + 'static> {
92 buffer: Box<[UnsafeCell<MaybeUninit<T>>]>,
93 capacity: usize,
94 mask: usize,
95 head: AtomicUsize,
97 tail: AtomicUsize,
99}
100
101unsafe impl<T: Copy + Send + 'static> Send for LockFreeRingBuffer<T> {}
105unsafe impl<T: Copy + Send + 'static> Sync for LockFreeRingBuffer<T> {}
108
109impl<T: Copy + Send + 'static> LockFreeRingBuffer<T> {
110 pub fn new(capacity: usize) -> Self {
125 assert!(
126 capacity > 0,
127 "LockFreeRingBuffer capacity must be at least 1"
128 );
129 let actual = capacity.next_power_of_two();
130 let buffer: Box<[UnsafeCell<MaybeUninit<T>>]> =
132 (0..actual).map(|_| UnsafeCell::new(MaybeUninit::uninit())).collect();
133 Self {
134 buffer,
135 capacity: actual,
136 mask: actual - 1,
137 head: AtomicUsize::new(0),
138 tail: AtomicUsize::new(0),
139 }
140 }
141
142 pub fn push(&self, item: T) -> Result<(), RingBufferError> {
158 let head = self.head.load(Ordering::Relaxed);
159 let tail = self.tail.load(Ordering::Acquire);
160
161 if head.wrapping_sub(tail) >= self.capacity {
162 return Err(RingBufferError::Full {
163 capacity: self.capacity,
164 });
165 }
166
167 let slot = head & self.mask;
168 unsafe {
172 (*self.buffer[slot].get()).write(item);
173 }
174
175 self.head.store(head.wrapping_add(1), Ordering::Release);
178 Ok(())
179 }
180
181 pub fn pop(&self) -> Option<T> {
197 let tail = self.tail.load(Ordering::Relaxed);
198 let head = self.head.load(Ordering::Acquire);
199
200 if tail == head {
201 return None;
202 }
203
204 let slot = tail & self.mask;
205 let item = unsafe { (*self.buffer[slot].get()).assume_init_read() };
209
210 self.tail.store(tail.wrapping_add(1), Ordering::Release);
213 Some(item)
214 }
215
216 pub fn len(&self) -> usize {
221 let head = self.head.load(Ordering::Acquire);
222 let tail = self.tail.load(Ordering::Acquire);
223 head.wrapping_sub(tail)
224 }
225
226 pub fn is_empty(&self) -> bool {
228 self.len() == 0
229 }
230
231 pub fn capacity(&self) -> usize {
233 self.capacity
234 }
235}
236
237pub struct StatisticsWindow<T: Copy + Into<f64>> {
262 buf: Vec<T>,
263 capacity: usize,
264 head: usize,
266 len: usize,
267}
268
269impl<T: Copy + Into<f64>> StatisticsWindow<T> {
270 pub fn new(capacity: usize) -> Self {
274 assert!(capacity > 0, "StatisticsWindow capacity must be >= 1");
275 Self {
276 buf: Vec::with_capacity(capacity),
277 capacity,
278 head: 0,
279 len: 0,
280 }
281 }
282
283 pub fn push(&mut self, value: T) {
285 if self.len < self.capacity {
286 self.buf.push(value);
287 self.len += 1;
288 } else {
289 self.buf[self.head] = value;
290 self.head = (self.head + 1) % self.capacity;
291 }
292 }
293
294 pub fn len(&self) -> usize {
296 self.len
297 }
298
299 pub fn is_empty(&self) -> bool {
301 self.len == 0
302 }
303
304 pub fn iter_ordered(&self) -> impl Iterator<Item = T> + '_ {
306 let (start, count) = if self.len < self.capacity {
309 (0, self.len)
310 } else {
311 (self.head, self.capacity)
312 };
313 (0..count).map(move |i| self.buf[(start + i) % self.capacity])
314 }
315
316 fn as_f64_vec(&self) -> Vec<f64> {
318 self.iter_ordered().map(|v| v.into()).collect()
319 }
320
321 pub fn mean(&self) -> Option<f64> {
323 if self.is_empty() {
324 return None;
325 }
326 let vals = self.as_f64_vec();
327 Some(vals.iter().sum::<f64>() / vals.len() as f64)
328 }
329
330 pub fn std_dev(&self) -> Option<f64> {
334 if self.len < 2 {
335 return None;
336 }
337 let mean = self.mean()?;
338 let vals = self.as_f64_vec();
339 let variance =
340 vals.iter().map(|&v| (v - mean).powi(2)).sum::<f64>() / (vals.len() - 1) as f64;
341 Some(variance.sqrt())
342 }
343
344 pub fn min(&self) -> Option<T> {
346 if self.is_empty() {
347 return None;
348 }
349 let mut best = self.buf[0];
351 let mut best_f: f64 = best.into();
352 for v in self.iter_ordered() {
353 let vf: f64 = v.into();
354 if vf < best_f {
355 best = v;
356 best_f = vf;
357 }
358 }
359 Some(best)
360 }
361
362 pub fn max(&self) -> Option<T> {
364 if self.is_empty() {
365 return None;
366 }
367 let mut best = self.buf[0];
368 let mut best_f: f64 = best.into();
369 for v in self.iter_ordered() {
370 let vf: f64 = v.into();
371 if vf > best_f {
372 best = v;
373 best_f = vf;
374 }
375 }
376 Some(best)
377 }
378
379 pub fn percentile(&self, p: f64) -> Option<f64> {
383 if self.is_empty() {
384 return None;
385 }
386 let mut sorted = self.as_f64_vec();
387 sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
388 let p_clamped = p.clamp(0.0, 100.0);
389 let rank = (p_clamped / 100.0 * (sorted.len() - 1) as f64).round() as usize;
390 Some(sorted[rank.min(sorted.len() - 1)])
391 }
392
393 pub fn windowed_mean(&self, window: usize) -> Option<f64> {
395 if self.is_empty() || window == 0 {
396 return None;
397 }
398 let total = self.len;
399 let n = window.min(total);
400 let vals: Vec<f64> = self.iter_ordered().skip(total - n).map(|v| v.into()).collect();
402 if vals.is_empty() {
403 return None;
404 }
405 Some(vals.iter().sum::<f64>() / vals.len() as f64)
406 }
407}
408
409#[derive(Debug, Clone, Copy)]
415pub struct TimestampedValue<T: Copy> {
416 pub value: T,
417 pub timestamp_ns: u64,
419}
420
421#[derive(Debug)]
427pub struct TimestampedRingBuffer<T: Copy> {
428 buf: Vec<TimestampedValue<T>>,
430 capacity: usize,
431 head: usize,
432 len: usize,
433}
434
435impl<T: Copy> TimestampedRingBuffer<T> {
436 pub fn new(capacity: usize) -> Self {
440 assert!(capacity > 0, "TimestampedRingBuffer capacity must be >= 1");
441 Self {
445 buf: Vec::with_capacity(capacity),
446 capacity,
447 head: 0,
448 len: 0,
449 }
450 }
451
452 pub fn push_now(&mut self, value: T, time_ns: u64) {
456 let entry = TimestampedValue {
457 value,
458 timestamp_ns: time_ns,
459 };
460 if self.len < self.capacity {
461 self.buf.push(entry);
462 self.len += 1;
463 } else {
464 self.buf[self.head] = entry;
465 self.head = (self.head + 1) % self.capacity;
466 }
467 }
468
469 pub fn len(&self) -> usize {
471 self.len
472 }
473
474 pub fn is_empty(&self) -> bool {
476 self.len == 0
477 }
478
479 pub fn iter_ordered(&self) -> impl Iterator<Item = TimestampedValue<T>> + '_ {
481 let (start, count) = if self.len < self.capacity {
482 (0, self.len)
483 } else {
484 (self.head, self.capacity)
485 };
486 (0..count).map(move |i| self.buf[(start + i) % self.capacity])
487 }
488
489 pub fn rate_per_sec(&self) -> f64 {
494 if self.len < 2 {
495 return 0.0;
496 }
497 let oldest = self.oldest_timestamp().unwrap_or(0);
498 let newest = self.newest_timestamp().unwrap_or(0);
499 let span_ns = newest.saturating_sub(oldest);
500 if span_ns == 0 {
501 return 0.0;
502 }
503 (self.len as f64 - 1.0) / (span_ns as f64 * 1e-9)
504 }
505
506 pub fn values_in_range(&self, start_ns: u64, end_ns: u64) -> Vec<T> {
509 self.iter_ordered()
510 .filter(|e| e.timestamp_ns >= start_ns && e.timestamp_ns <= end_ns)
511 .map(|e| e.value)
512 .collect()
513 }
514
515 pub fn oldest_timestamp(&self) -> Option<u64> {
517 self.iter_ordered().next().map(|e| e.timestamp_ns)
518 }
519
520 pub fn newest_timestamp(&self) -> Option<u64> {
522 self.iter_ordered().last().map(|e| e.timestamp_ns)
523 }
524}
525
526#[cfg(test)]
531mod tests {
532 use super::*;
533 use std::sync::Arc;
534 use std::thread;
535
536 #[test]
537 fn test_capacity_rounds_up_to_power_of_two() {
538 let buf = LockFreeRingBuffer::<u8>::new(5);
539 assert_eq!(buf.capacity(), 8);
540
541 let buf2 = LockFreeRingBuffer::<u8>::new(8);
542 assert_eq!(buf2.capacity(), 8);
543
544 let buf3 = LockFreeRingBuffer::<u8>::new(9);
545 assert_eq!(buf3.capacity(), 16);
546 }
547
548 #[test]
549 fn test_push_and_pop_basic() {
550 let buf = LockFreeRingBuffer::<u32>::new(4);
551 assert_eq!(buf.pop(), None);
552 buf.push(1).unwrap();
553 buf.push(2).unwrap();
554 buf.push(3).unwrap();
555 assert_eq!(buf.pop(), Some(1));
556 assert_eq!(buf.pop(), Some(2));
557 assert_eq!(buf.pop(), Some(3));
558 assert_eq!(buf.pop(), None);
559 }
560
561 #[test]
562 fn test_full_buffer_returns_error() {
563 let buf = LockFreeRingBuffer::<u32>::new(2);
564 buf.push(10).unwrap();
565 buf.push(20).unwrap();
566 let err = buf.push(30).unwrap_err();
567 assert!(matches!(err, RingBufferError::Full { capacity: 2 }));
568 }
569
570 #[test]
571 fn test_len_and_is_empty() {
572 let buf = LockFreeRingBuffer::<u8>::new(4);
573 assert!(buf.is_empty());
574 assert_eq!(buf.len(), 0);
575 buf.push(1).unwrap();
576 assert!(!buf.is_empty());
577 assert_eq!(buf.len(), 1);
578 buf.push(2).unwrap();
579 assert_eq!(buf.len(), 2);
580 buf.pop();
581 assert_eq!(buf.len(), 1);
582 }
583
584 #[test]
585 fn test_wrap_around() {
586 let buf = LockFreeRingBuffer::<u32>::new(4);
587 buf.push(1).unwrap();
589 buf.push(2).unwrap();
590 buf.push(3).unwrap();
591 buf.push(4).unwrap();
592 assert_eq!(buf.pop(), Some(1));
594 assert_eq!(buf.pop(), Some(2));
595 buf.push(5).unwrap();
597 buf.push(6).unwrap();
598 assert_eq!(buf.pop(), Some(3));
599 assert_eq!(buf.pop(), Some(4));
600 assert_eq!(buf.pop(), Some(5));
601 assert_eq!(buf.pop(), Some(6));
602 assert_eq!(buf.pop(), None);
603 }
604
605 #[test]
606 fn test_concurrent_spsc() {
607 let buf: Arc<LockFreeRingBuffer<u64>> = Arc::new(LockFreeRingBuffer::new(64));
608 let producer = Arc::clone(&buf);
609 let consumer = Arc::clone(&buf);
610
611 const N: u64 = 1000;
612
613 let producer_thread = thread::spawn(move || {
614 let mut sent = 0u64;
615 while sent < N {
616 if producer.push(sent).is_ok() {
617 sent += 1;
618 }
619 }
620 });
621
622 let consumer_thread = thread::spawn(move || {
623 let mut received = Vec::with_capacity(N as usize);
624 while received.len() < N as usize {
625 if let Some(v) = consumer.pop() {
626 received.push(v);
627 }
628 }
629 received
630 });
631
632 producer_thread.join().unwrap();
633 let received = consumer_thread.join().unwrap();
634
635 assert_eq!(received.len(), N as usize);
636 for (i, &v) in received.iter().enumerate() {
637 assert_eq!(v, i as u64);
638 }
639 }
640
641 #[test]
642 fn test_capacity_one() {
643 let buf = LockFreeRingBuffer::<u8>::new(1);
644 assert_eq!(buf.capacity(), 1);
645 buf.push(42).unwrap();
646 assert!(buf.push(99).is_err());
647 assert_eq!(buf.pop(), Some(42));
648 assert_eq!(buf.pop(), None);
649 }
650
651 #[test]
652 fn test_f32_elements() {
653 let buf = LockFreeRingBuffer::<f32>::new(8);
654 buf.push(1.5_f32).unwrap();
655 buf.push(2.5_f32).unwrap();
656 assert!((buf.pop().unwrap() - 1.5).abs() < 1e-6);
657 assert!((buf.pop().unwrap() - 2.5).abs() < 1e-6);
658 }
659
660 #[test]
661 fn test_concurrent_ping_pong() {
662 let buf: Arc<LockFreeRingBuffer<u32>> = Arc::new(LockFreeRingBuffer::new(32));
664 let p = Arc::clone(&buf);
665 let c = Arc::clone(&buf);
666
667 const ITERS: u32 = 2_000;
668
669 let prod = thread::spawn(move || {
670 for i in 0..ITERS {
671 while p.push(i).is_err() {
672 thread::yield_now();
673 }
674 }
675 });
676
677 let cons = thread::spawn(move || {
678 let mut count = 0u32;
679 while count < ITERS {
680 if c.pop().is_some() {
681 count += 1;
682 }
683 }
684 count
685 });
686
687 prod.join().unwrap();
688 assert_eq!(cons.join().unwrap(), ITERS);
689 }
690
691 #[test]
692 fn test_multiple_wrap_arounds() {
693 let buf = LockFreeRingBuffer::<u64>::new(4);
694 for round in 0..10u64 {
695 for i in 0..4u64 {
696 buf.push(round * 4 + i).unwrap();
697 }
698 for i in 0..4u64 {
699 assert_eq!(buf.pop(), Some(round * 4 + i));
700 }
701 }
702 }
703
704 #[test]
707 fn test_statistics_window_mean_basic() {
708 let mut w = StatisticsWindow::new(8);
709 w.push(1u32);
710 w.push(2u32);
711 w.push(3u32);
712 let m = w.mean().unwrap();
713 assert!((m - 2.0).abs() < 1e-9, "mean={}", m);
714 }
715
716 #[test]
717 fn test_statistics_window_empty_mean_returns_none() {
718 let w: StatisticsWindow<u32> = StatisticsWindow::new(4);
719 assert!(w.mean().is_none());
720 }
721
722 #[test]
723 fn test_statistics_window_eviction() {
724 let mut w = StatisticsWindow::new(3);
726 w.push(1u32);
727 w.push(2u32);
728 w.push(3u32);
729 w.push(4u32); assert_eq!(w.len(), 3);
731 let vals: Vec<u32> = w.iter_ordered().collect();
732 assert_eq!(vals, vec![2, 3, 4]);
733 }
734
735 #[test]
736 fn test_statistics_window_std_dev_constant() {
737 let mut w = StatisticsWindow::new(5);
738 for _ in 0..5 {
739 w.push(7u32);
740 }
741 let s = w.std_dev().unwrap();
742 assert!(s < 1e-9, "std of constant values should be 0, got {}", s);
743 }
744
745 #[test]
746 fn test_statistics_window_std_dev_two_values() {
747 let mut w = StatisticsWindow::new(4);
748 w.push(0u32);
749 w.push(4u32);
750 let s = w.std_dev().unwrap();
752 assert!((s - (8.0_f64).sqrt()).abs() < 1e-6, "std={}", s);
753 }
754
755 #[test]
756 fn test_statistics_window_min_max() {
757 let mut w = StatisticsWindow::new(8);
758 w.push(5u32);
759 w.push(2u32);
760 w.push(9u32);
761 w.push(1u32);
762 assert_eq!(w.min(), Some(1u32));
763 assert_eq!(w.max(), Some(9u32));
764 }
765
766 #[test]
767 fn test_statistics_window_min_max_empty() {
768 let w: StatisticsWindow<u32> = StatisticsWindow::new(4);
769 assert!(w.min().is_none());
770 assert!(w.max().is_none());
771 }
772
773 #[test]
774 fn test_statistics_window_percentile_median() {
775 let mut w = StatisticsWindow::new(10);
776 for i in 1u32..=9 {
777 w.push(i);
778 }
779 let p50 = w.percentile(50.0).unwrap();
781 assert!((p50 - 5.0).abs() < 1.5, "p50={}", p50);
782 }
783
784 #[test]
785 fn test_statistics_window_windowed_mean_last_n() {
786 let mut w = StatisticsWindow::new(10);
787 for i in 1u32..=10 {
788 w.push(i);
789 }
790 let wm = w.windowed_mean(3).unwrap();
792 assert!((wm - 9.0).abs() < 1e-9, "windowed_mean={}", wm);
793 }
794
795 #[test]
796 fn test_statistics_window_windowed_mean_larger_than_len() {
797 let mut w = StatisticsWindow::new(10);
798 w.push(2u32);
799 w.push(4u32);
800 let wm = w.windowed_mean(5).unwrap();
802 assert!((wm - 3.0).abs() < 1e-9, "windowed_mean={}", wm);
803 }
804
805 #[test]
806 fn test_statistics_window_windowed_mean_zero_window() {
807 let mut w = StatisticsWindow::new(4);
808 w.push(1u32);
809 assert!(w.windowed_mean(0).is_none());
810 }
811
812 #[test]
815 fn test_timestamped_ring_buffer_basic_push_and_len() {
816 let mut tb = TimestampedRingBuffer::<u32>::new(4);
817 assert!(tb.is_empty());
818 tb.push_now(10, 1_000_000);
819 tb.push_now(20, 2_000_000);
820 assert_eq!(tb.len(), 2);
821 }
822
823 #[test]
824 fn test_timestamped_ring_buffer_eviction() {
825 let mut tb = TimestampedRingBuffer::<u32>::new(2);
826 tb.push_now(1, 100);
827 tb.push_now(2, 200);
828 tb.push_now(3, 300); assert_eq!(tb.len(), 2);
830 let vals: Vec<u32> = tb.iter_ordered().map(|e| e.value).collect();
831 assert_eq!(vals, vec![2, 3]);
832 }
833
834 #[test]
835 fn test_timestamped_oldest_newest() {
836 let mut tb = TimestampedRingBuffer::<u32>::new(4);
837 tb.push_now(0u32, 100);
838 tb.push_now(1u32, 200);
839 tb.push_now(2u32, 300);
840 assert_eq!(tb.oldest_timestamp(), Some(100));
841 assert_eq!(tb.newest_timestamp(), Some(300));
842 }
843
844 #[test]
845 fn test_timestamped_oldest_newest_empty() {
846 let tb: TimestampedRingBuffer<u32> = TimestampedRingBuffer::new(4);
847 assert!(tb.oldest_timestamp().is_none());
848 assert!(tb.newest_timestamp().is_none());
849 }
850
851 #[test]
852 fn test_timestamped_rate_per_sec() {
853 let mut tb = TimestampedRingBuffer::<u32>::new(4);
854 tb.push_now(0, 0);
857 tb.push_now(1, 1_000_000_000); tb.push_now(2, 2_000_000_000); let rate = tb.rate_per_sec();
860 assert!((rate - 1.0).abs() < 0.01, "rate={}", rate);
861 }
862
863 #[test]
864 fn test_timestamped_rate_single_entry_is_zero() {
865 let mut tb = TimestampedRingBuffer::<u32>::new(4);
866 tb.push_now(1, 1_000_000_000);
867 assert_eq!(tb.rate_per_sec(), 0.0);
868 }
869
870 #[test]
871 fn test_timestamped_values_in_range() {
872 let mut tb = TimestampedRingBuffer::<u32>::new(8);
873 for i in 0..8u32 {
874 tb.push_now(i, i as u64 * 100);
875 }
876 let vals = tb.values_in_range(200, 500);
878 assert_eq!(vals, vec![2, 3, 4, 5]);
879 }
880
881 #[test]
882 fn test_timestamped_values_in_range_empty_result() {
883 let mut tb = TimestampedRingBuffer::<u32>::new(4);
884 tb.push_now(1, 100);
885 tb.push_now(2, 200);
886 let vals = tb.values_in_range(500, 600);
887 assert!(vals.is_empty());
888 }
889}