1use anyhow::Result;
3use bytes::Bytes;
4use std::cell::UnsafeCell;
5use std::mem::MaybeUninit;
6use std::ops::{Deref, DerefMut};
7use std::sync::Arc;
8use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
9use tokio::sync::Notify;
10
11#[allow(unused)]
12const CACHE_LINE: usize = 64;
14
15#[repr(C, align(64))]
17struct CachePadded<T>(T);
18
19impl<T> CachePadded<T> {
20 #[inline(always)]
21 const fn pad(val: T) -> Self {
22 Self(val)
23 }
24}
25
26impl<T> Deref for CachePadded<T> {
27 type Target = T;
28 #[inline(always)]
29 fn deref(&self) -> &T {
30 &self.0
31 }
32}
33
34impl<T> DerefMut for CachePadded<T> {
35 #[inline(always)]
36 fn deref_mut(&mut self) -> &mut T {
37 &mut self.0
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct FullError;
44impl std::error::Error for FullError {}
45impl std::fmt::Display for FullError {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(f, "ring buffer full")
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct EmptyError;
54impl std::error::Error for EmptyError {}
55impl std::fmt::Display for EmptyError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 write!(f, "ring buffer empty")
58 }
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct ClosedError;
64impl std::error::Error for ClosedError {}
65impl std::fmt::Display for ClosedError {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 write!(f, "ring buffer peer dropped")
68 }
69}
70
71type Slot = UnsafeCell<MaybeUninit<Bytes>>;
73
74pub struct Ring {
79 slots: Box<[Slot]>,
80 capacity: usize,
81 head: CachePadded<AtomicUsize>,
82 tail: CachePadded<AtomicUsize>,
83 closed: CachePadded<AtomicBool>,
85 data_available: CachePadded<Arc<Notify>>,
87 space_available: CachePadded<Arc<Notify>>,
89}
90
91unsafe impl Send for Ring {}
92unsafe impl Sync for Ring {}
93
94impl Ring {
95 #[inline]
96 pub fn create(mut capacity: usize) -> Result<Self> {
99 if !capacity.is_power_of_two() {
100 capacity = capacity.next_power_of_two();
101 }
102 capacity = capacity.max(2); let slots: Box<[Slot]> = (0..capacity)
105 .map(|_| UnsafeCell::new(MaybeUninit::uninit()))
106 .collect();
107
108 Ok(Self {
109 slots,
110 capacity,
111 head: CachePadded::pad(AtomicUsize::new(0)),
112 tail: CachePadded::pad(AtomicUsize::new(0)),
113 closed: CachePadded::pad(AtomicBool::new(false)),
114 data_available: CachePadded::pad(Arc::new(Notify::new())),
115 space_available: CachePadded::pad(Arc::new(Notify::new())),
116 })
117 }
118
119 #[inline(always)]
120 pub fn space_notify(&self) -> Arc<Notify> {
122 Arc::clone(&self.space_available)
123 }
124
125 #[inline(always)]
126 pub fn data_notify(&self) -> Arc<Notify> {
128 Arc::clone(&self.data_available)
129 }
130
131 #[inline]
132 pub fn into_split(self) -> (Producer, Consumer) {
134 let ring = Arc::new(self);
135 (
136 Producer {
137 ring: Arc::clone(&ring),
138 head_local: 0,
139 tail_cached: 0,
140 },
141 Consumer {
142 ring,
143 tail_local: 0,
144 head_cached: 0,
145 },
146 )
147 }
148
149 #[inline]
150 pub fn len(&self) -> usize {
152 let h = self.head.load(Ordering::Relaxed);
153 let t = self.tail.load(Ordering::Relaxed);
154 (h.wrapping_sub(t)) & (self.capacity - 1)
155 }
156
157 #[inline]
158 pub fn is_full(&self) -> bool {
160 let h = self.head.load(Ordering::Relaxed);
161 let t = self.tail.load(Ordering::Relaxed);
162 ((h + 1) & (self.capacity - 1)) == t
163 }
164
165 #[inline]
166 pub fn is_empty(&self) -> bool {
168 self.head.load(Ordering::Relaxed) == self.tail.load(Ordering::Relaxed)
169 }
170
171 #[inline]
172 pub fn is_closed(&self) -> bool {
174 self.closed.load(Ordering::Acquire)
175 }
176
177 #[inline]
178 pub fn free_slots(&self) -> usize {
180 self.capacity - 1 - self.len()
181 }
182
183 #[inline]
184 pub fn capacity(&self) -> usize {
186 self.capacity
187 }
188
189 #[inline(always)]
190 fn slot_ptr(&self, idx: usize) -> *mut MaybeUninit<Bytes> {
196 unsafe { self.slots.get_unchecked(idx).get() }
197 }
198}
199
200impl Drop for Ring {
201 fn drop(&mut self) {
202 let h = *self.head.get_mut();
203 let t = *self.tail.get_mut();
204 let mut idx = t;
205 while idx != h {
206 unsafe {
207 (*self.slots[idx].get()).assume_init_drop();
208 }
209 idx = (idx + 1) & (self.capacity - 1);
210 }
211 }
212}
213
214pub struct Producer {
216 ring: Arc<Ring>,
218 head_local: usize,
221 tail_cached: usize,
223}
224
225impl Producer {
226 #[inline(always)]
229 pub fn push(&mut self, data: Bytes) -> Result<(), FullError> {
230 let head = self.head_local;
231 let next = (head + 1) & (self.ring.capacity - 1);
232
233 if next == self.tail_cached {
235 self.tail_cached = self.ring.tail.load(Ordering::Acquire);
236 if next == self.tail_cached {
237 return Err(FullError);
238 }
239 }
240
241 unsafe {
243 self.ring.slot_ptr(head).write(MaybeUninit::new(data));
244 }
245
246 self.head_local = next;
249 self.ring.head.store(next, Ordering::Release);
250 self.ring.data_available.notify_one();
252 Ok(())
253 }
254
255 #[inline(always)]
256 pub fn push_bytes(&mut self, data: &[u8]) -> Result<(), FullError> {
258 self.push(Bytes::copy_from_slice(data)) }
260
261 #[inline(always)]
262 pub fn push_batch(&mut self, packets: &[Bytes]) -> usize {
264 if packets.is_empty() {
265 return 0;
266 }
267
268 let head = self.head_local;
269 let cap_mask = self.ring.capacity - 1;
270
271 let mut used = (head.wrapping_sub(self.tail_cached)) & cap_mask;
272 let mut free = (self.ring.capacity - 1) - used;
273
274 if free < packets.len() {
276 self.tail_cached = self.ring.tail.load(Ordering::Acquire);
277 used = (head.wrapping_sub(self.tail_cached)) & cap_mask;
278 free = (self.ring.capacity - 1) - used;
279 }
280
281 let n = packets.len().min(free);
283 if n == 0 {
284 return 0;
285 }
286
287 #[allow(clippy::needless_range_loop)]
289 for i in 0..n {
290 let idx = (head + i) & cap_mask;
291 unsafe {
292 self.ring
293 .slot_ptr(idx)
294 .write(MaybeUninit::new(packets.get_unchecked(i).clone())); }
296 }
297
298 self.head_local = (head + n) & cap_mask;
300 self.ring.head.store(self.head_local, Ordering::Release);
301 n
302 }
303
304 pub async fn push_async(&mut self, data: Bytes) -> Result<(), ClosedError> {
308 loop {
309 if self.try_push_shared(&data) {
310 return Ok(());
311 }
312 if self.ring.closed.load(Ordering::Acquire) {
313 return Err(ClosedError);
314 }
315 self.ring.space_available.notified().await;
316 }
317 }
318
319 #[inline(always)]
320 fn try_push_shared(&mut self, src: &Bytes) -> bool {
322 let head = self.head_local;
323 let next = (head + 1) & (self.ring.capacity - 1);
324
325 if next == self.tail_cached {
326 self.tail_cached = self.ring.tail.load(Ordering::Acquire);
327 if next == self.tail_cached {
328 return false;
329 }
330 }
331
332 unsafe {
333 self.ring
334 .slot_ptr(head)
335 .write(MaybeUninit::new(src.clone()));
336 }
337 self.head_local = next;
341 self.ring.head.store(next, Ordering::Release);
342 self.ring.data_available.notify_one();
344 true
345 }
346
347 #[inline(always)]
348 pub fn len(&self) -> usize {
350 (self.head_local.wrapping_sub(self.tail_cached)) & (self.ring.capacity - 1)
351 }
352
353 #[inline(always)]
354 pub fn is_full(&self) -> bool {
356 self.len() == self.ring.capacity - 1
357 }
358
359 #[inline(always)]
360 pub fn is_empty(&self) -> bool {
362 self.len() == 0
363 }
364
365 #[inline(always)]
366 pub fn is_closed(&self) -> bool {
368 self.ring.is_closed()
369 }
370
371 #[inline(always)]
372 pub fn space_notify(&self) -> Arc<Notify> {
374 self.ring.space_notify()
375 }
376
377 #[inline]
379 pub fn free_slots(&self) -> usize {
380 (self.ring.capacity - 1) - self.len()
381 }
382
383 #[inline]
385 pub fn capacity(&self) -> usize {
386 self.ring.capacity - 1
387 }
388}
389
390impl Drop for Producer {
391 fn drop(&mut self) {
392 self.ring.closed.store(true, Ordering::Release);
393 self.ring.data_available.notify_waiters();
396 }
397}
398
399pub struct Consumer {
401 ring: Arc<Ring>,
403 tail_local: usize,
406 head_cached: usize,
408}
409
410impl Consumer {
411 #[inline(always)]
413 pub fn pop(&mut self) -> Result<Bytes, EmptyError> {
414 let tail = self.tail_local;
415
416 if tail == self.head_cached {
418 self.head_cached = self.ring.head.load(Ordering::Acquire);
419 if tail == self.head_cached {
420 return Err(EmptyError);
421 }
422 }
423
424 let data = unsafe { self.ring.slot_ptr(tail).read().assume_init() };
426
427 let next = (tail + 1) & (self.ring.capacity - 1);
430 self.tail_local = next;
431 self.ring.tail.store(next, Ordering::Release);
432 self.ring.space_available.notify_one();
434 Ok(data)
435 }
436
437 #[inline(always)]
440 pub fn pop_batch(&mut self, buf: &mut [Bytes]) -> usize {
441 if buf.is_empty() {
442 return 0;
443 }
444
445 let tail = self.tail_local;
446 let cap_mask = self.ring.capacity - 1;
447
448 let mut available = (self.head_cached.wrapping_sub(tail)) & cap_mask;
449
450 if available < buf.len() {
452 self.head_cached = self.ring.head.load(Ordering::Acquire);
453 available = (self.head_cached.wrapping_sub(tail)) & cap_mask;
454 }
455
456 let n = buf.len().min(available);
457 if n == 0 {
458 return 0;
459 }
460
461 for i in 0..n {
463 let idx = (tail + i) & cap_mask;
464 unsafe {
465 *buf.get_unchecked_mut(i) = self.ring.slot_ptr(idx).read().assume_init();
467 }
468 }
469
470 self.tail_local = (tail + n) & cap_mask;
472 self.ring.tail.store(self.tail_local, Ordering::Release);
473 n
474 }
475
476 pub async fn pop_async(&mut self) -> Result<Bytes, ClosedError> {
480 loop {
481 if let Ok(data) = self.pop() {
482 return Ok(data);
483 }
484 if self.ring.closed.load(Ordering::Acquire) {
485 return Err(ClosedError);
486 }
487 self.ring.data_available.notified().await;
488 }
489 }
490
491 #[inline(always)]
492 pub fn len(&self) -> usize {
494 (self.head_cached.wrapping_sub(self.tail_local)) & (self.ring.capacity - 1)
495 }
496
497 #[inline]
498 pub fn is_empty(&self) -> bool {
500 self.len() == 0
501 }
502
503 #[inline(always)]
504 pub fn is_closed(&self) -> bool {
506 self.ring.is_closed()
507 }
508
509 #[inline]
510 pub fn available(&self) -> usize {
512 self.len()
513 }
514
515 #[inline]
516 pub fn capacity(&self) -> usize {
518 self.ring.capacity - 1
519 }
520}
521
522impl Drop for Consumer {
523 fn drop(&mut self) {
524 self.ring.closed.store(true, Ordering::Release);
525 self.ring.space_available.notify_waiters();
528 }
529}