1use std::cell::UnsafeCell;
7use std::mem::MaybeUninit;
8use std::sync::atomic::{AtomicUsize, Ordering};
9
10#[derive(Clone, Copy, Debug)]
12pub struct RingConfig {
13 pub capacity: usize,
15 pub backpressure_threshold: usize,
17}
18
19impl Default for RingConfig {
20 fn default() -> Self {
21 Self {
22 capacity: 1023, backpressure_threshold: 716, }
25 }
26}
27
28const RING_CAPACITY: usize = 1024;
30
31#[derive(Debug)]
39pub struct SpscRingBuffer<T> {
40 buffer: UnsafeCell<[MaybeUninit<T>; RING_CAPACITY]>,
42 head: AtomicUsize,
44 tail: AtomicUsize,
46 overflow_count: AtomicUsize,
48 empty_count: AtomicUsize,
50 config: RingConfig,
52}
53
54impl<T> SpscRingBuffer<T> {
55 const CAPACITY: usize = RING_CAPACITY;
56
57 pub fn new(config: RingConfig) -> Self {
59 assert!(
60 config.capacity < Self::CAPACITY,
61 "capacity must be strictly less than RING_CAPACITY"
62 );
63
64 let buffer = UnsafeCell::new(unsafe {
66 MaybeUninit::<[MaybeUninit<T>; RING_CAPACITY]>::uninit().assume_init()
67 });
68
69 Self {
70 buffer,
71 head: AtomicUsize::new(0),
72 tail: AtomicUsize::new(0),
73 overflow_count: AtomicUsize::new(0),
74 empty_count: AtomicUsize::new(Self::CAPACITY - config.capacity),
75 config,
76 }
77 }
78
79 pub fn push(&self, value: T) -> Result<(), T> {
84 let tail = self.tail.load(Ordering::Acquire);
85 let head = self.head.load(Ordering::Acquire);
86
87 let current_len = if tail >= head {
89 tail - head
90 } else {
91 Self::CAPACITY - head + tail
92 };
93
94 if current_len >= self.config.capacity {
95 self.overflow_count.fetch_add(1, Ordering::Relaxed);
96 return Err(value);
97 }
98
99 let next_tail = Self::increment(tail);
100
101 unsafe {
103 let buf = &mut *self.buffer.get();
104 buf[tail].write(value);
105
106 self.tail.store(next_tail, Ordering::Release);
108 }
109
110 Ok(())
111 }
112
113 pub fn pop(&self) -> Option<T> {
117 let head = self.head.load(Ordering::Acquire);
118 let tail = self.tail.load(Ordering::Acquire);
119
120 let is_empty = if head >= tail { head == tail } else { false };
122
123 if is_empty {
124 return None;
125 }
126
127 let value = unsafe {
129 let buf = &mut *self.buffer.get();
130 let val = buf[head].assume_init_read();
131
132 self.head.store(Self::increment(head), Ordering::Release);
134
135 val
136 };
137
138 Some(value)
139 }
140
141 pub fn len(&self) -> usize {
143 let head = self.head.load(Ordering::Acquire);
144 let tail = self.tail.load(Ordering::Acquire);
145
146 tail.wrapping_sub(head) & (Self::CAPACITY - 1)
147 }
148
149 pub fn is_empty(&self) -> bool {
151 self.head.load(Ordering::Acquire) == self.tail.load(Ordering::Acquire)
152 }
153
154 pub fn capacity(&self) -> usize {
156 self.config.capacity
157 }
158
159 pub fn overflow_count(&self) -> usize {
161 self.overflow_count.load(Ordering::Relaxed)
162 }
163
164 pub fn empty_count(&self) -> usize {
166 self.empty_count.load(Ordering::Relaxed)
167 }
168
169 pub fn should_backpressure(&self) -> bool {
171 let len = self.len();
172 len >= self.config.backpressure_threshold
173 }
174
175 pub fn wait_for_space(&self) {
179 while self.should_backpressure() {
180 std::thread::yield_now();
182 }
183 }
184
185 pub fn wait_for_data(&self) {
189 while self.is_empty() {
190 std::thread::yield_now();
192 }
193 }
194
195 fn increment(index: usize) -> usize {
196 (index + 1) & (Self::CAPACITY - 1)
197 }
198}
199
200unsafe impl<T: Send> Send for SpscRingBuffer<T> {}
204unsafe impl<T: Send> Sync for SpscRingBuffer<T> {}
205
206impl<T> Drop for SpscRingBuffer<T> {
207 fn drop(&mut self) {
208 while self.pop().is_some() {}
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216 use std::sync::Arc;
217 use std::thread;
218
219 #[test]
220 fn supports_fifo_push_and_pop() {
221 let ring = SpscRingBuffer::<i32>::new(RingConfig::default());
222 assert!(ring.push(1).is_ok());
223 assert!(ring.push(2).is_ok());
224 assert_eq!(ring.len(), 2);
225 assert_eq!(ring.pop(), Some(1));
226 assert_eq!(ring.pop(), Some(2));
227 assert!(ring.is_empty());
228 }
229
230 #[test]
231 fn returns_full_when_capacity_is_reached() {
232 let config = RingConfig {
233 capacity: 2,
234 backpressure_threshold: 1,
235 };
236 let ring = SpscRingBuffer::<i32>::new(config);
237 assert!(ring.push(1).is_ok());
238 assert!(ring.push(2).is_ok());
239 assert_eq!(ring.push(3), Err(3));
240 }
241
242 #[test]
243 fn supports_single_producer_single_consumer_threads() {
244 let ring = Arc::new(SpscRingBuffer::<i32>::new(RingConfig::default()));
245 let producer_ring = Arc::clone(&ring);
246 let consumer_ring = Arc::clone(&ring);
247
248 let producer = thread::spawn(move || {
249 for value in 0..1_000 {
250 loop {
251 if producer_ring.push(value).is_ok() {
252 break;
253 }
254 std::thread::yield_now();
255 }
256 }
257 });
258
259 let consumer = thread::spawn(move || {
260 let mut values = Vec::new();
261 while values.len() < 1_000 {
262 if let Some(value) = consumer_ring.pop() {
263 values.push(value);
264 } else {
265 std::thread::yield_now();
266 }
267 }
268 values
269 });
270
271 producer.join().unwrap();
272 let values = consumer.join().unwrap();
273
274 assert_eq!(values.len(), 1_000);
275 assert_eq!(values.first(), Some(&0));
276 assert_eq!(values.last(), Some(&999));
277 }
278
279 #[test]
280 fn handles_wrap_around_correctly() {
281 let ring = SpscRingBuffer::<i32>::new(RingConfig::default());
282
283 for i in 0..1020 {
285 ring.push(i).unwrap();
286 }
287
288 assert_eq!(ring.len(), 1020);
289
290 for i in 0..1020 {
292 assert_eq!(ring.pop(), Some(i));
293 }
294
295 assert!(ring.is_empty());
296 }
297
298 #[test]
299 fn backpressure_threshold_works() {
300 let config = RingConfig {
301 capacity: 100,
302 backpressure_threshold: 70,
303 };
304 let ring = SpscRingBuffer::<i32>::new(config);
305
306 for i in 0..69 {
308 ring.push(i).unwrap();
309 }
310 assert!(!ring.should_backpressure());
311
312 let result = ring.push(70);
314 assert!(result.is_ok()); assert!(ring.should_backpressure());
316 }
317
318 #[test]
319 fn wait_for_space_releases() {
320 let ring = Arc::new(SpscRingBuffer::<i32>::new(RingConfig::default()));
321 let consumer_ring = Arc::clone(&ring);
322
323 for i in 0..1020 {
325 ring.push(i).unwrap();
326 }
327
328 consumer_ring.pop();
330
331 let result = ring.push(1021);
333 assert!(result.is_ok());
334 }
335
336 #[test]
337 fn wait_for_data_releases() {
338 let ring = Arc::new(SpscRingBuffer::<i32>::new(RingConfig::default()));
339 let producer_ring = Arc::clone(&ring);
340
341 producer_ring.push(42).unwrap();
345
346 assert_eq!(ring.pop(), Some(42));
348 }
349}