subms_spsc_ring_buffer/
lib.rs1use std::cell::UnsafeCell;
19use std::mem::MaybeUninit;
20use std::sync::Arc;
21use std::sync::atomic::{AtomicUsize, Ordering};
22
23#[repr(align(128))]
27pub(crate) struct Padded(pub(crate) AtomicUsize);
28
29pub(crate) struct Inner<T> {
30 pub(crate) head: Padded,
32 pub(crate) tail: Padded,
34 pub(crate) capacity: usize,
36 pub(crate) mask: usize,
38 pub(crate) buf: Box<[UnsafeCell<MaybeUninit<T>>]>,
41}
42
43unsafe impl<T: Send> Sync for Inner<T> {}
46unsafe impl<T: Send> Send for Inner<T> {}
47
48impl<T> Drop for Inner<T> {
49 fn drop(&mut self) {
50 let head = self.head.0.load(Ordering::Relaxed);
52 let tail = self.tail.0.load(Ordering::Relaxed);
53 for i in head..tail {
54 unsafe {
55 (*self.buf[i & self.mask].get()).assume_init_drop();
56 }
57 }
58 }
59}
60
61pub struct Producer<T> {
64 pub(crate) inner: Arc<Inner<T>>,
65 pub(crate) cached_head: usize,
67}
68
69unsafe impl<T: Send> Send for Producer<T> {}
70
71pub struct Consumer<T> {
73 pub(crate) inner: Arc<Inner<T>>,
74 pub(crate) cached_tail: usize,
76}
77
78unsafe impl<T: Send> Send for Consumer<T> {}
79
80pub struct SpscRingBuffer;
82
83impl SpscRingBuffer {
84 pub fn with_capacity<T>(requested_capacity: usize) -> (Producer<T>, Consumer<T>) {
88 let cap = requested_capacity.max(2).next_power_of_two();
89 let mut buf = Vec::with_capacity(cap);
90 for _ in 0..cap {
91 buf.push(UnsafeCell::new(MaybeUninit::<T>::uninit()));
92 }
93 let inner = Arc::new(Inner {
94 head: Padded(AtomicUsize::new(0)),
95 tail: Padded(AtomicUsize::new(0)),
96 capacity: cap,
97 mask: cap - 1,
98 buf: buf.into_boxed_slice(),
99 });
100 (
101 Producer {
102 inner: inner.clone(),
103 cached_head: 0,
104 },
105 Consumer {
106 inner,
107 cached_tail: 0,
108 },
109 )
110 }
111}
112
113impl<T> Producer<T> {
114 pub fn try_push(&mut self, value: T) -> Result<(), T> {
117 let tail = self.inner.tail.0.load(Ordering::Relaxed);
118
119 if tail.wrapping_sub(self.cached_head) == self.inner.capacity {
121 self.cached_head = self.inner.head.0.load(Ordering::Acquire);
123 if tail.wrapping_sub(self.cached_head) == self.inner.capacity {
124 return Err(value);
125 }
126 }
127
128 unsafe {
130 (*self.inner.buf[tail & self.inner.mask].get()).write(value);
131 }
132 self.inner
133 .tail
134 .0
135 .store(tail.wrapping_add(1), Ordering::Release);
136 Ok(())
137 }
138
139 pub fn capacity(&self) -> usize {
141 self.inner.capacity
142 }
143}
144
145impl<T> Consumer<T> {
146 pub fn try_pop(&mut self) -> Option<T> {
148 let head = self.inner.head.0.load(Ordering::Relaxed);
149
150 if head == self.cached_tail {
151 self.cached_tail = self.inner.tail.0.load(Ordering::Acquire);
152 if head == self.cached_tail {
153 return None;
154 }
155 }
156
157 let value = unsafe { (*self.inner.buf[head & self.inner.mask].get()).assume_init_read() };
158 self.inner
159 .head
160 .0
161 .store(head.wrapping_add(1), Ordering::Release);
162 Some(value)
163 }
164
165 pub fn capacity(&self) -> usize {
167 self.inner.capacity
168 }
169}
170
171#[cfg(feature = "harness")]
172pub mod recipe;
173
174#[cfg(any(
177 feature = "bulk",
178 feature = "wait-strategies",
179 feature = "mpsc-fan-in",
180 feature = "mpmc-disruptor",
181 feature = "metrics",
182))]
183pub mod features;
184
185#[cfg(feature = "metrics")]
186pub use features::metrics::{InstrumentedSpsc, RingMetrics, RingMetricsSnapshot};
187#[cfg(feature = "mpmc-disruptor")]
188pub use features::mpmc_disruptor::{DisruptorConsumer, DisruptorProducer, MpmcDisruptor};
189#[cfg(feature = "mpsc-fan-in")]
190pub use features::mpsc_fan_in::{MpscFanIn, MpscFanInConsumer, MpscFanInProducer};
191#[cfg(feature = "wait-strategies")]
192pub use features::wait_strategies::{
193 BlockingSpscConsumer, BlockingSpscProducer, BusySpin, ParkStrategy, WaitStrategy, YieldStrategy,
194};