1use crate::sync::{AtomicBool, AtomicU32, Ordering, TrackedCell, fence};
47use core::cell::Cell;
48use core::marker::PhantomData;
49use core::mem::MaybeUninit;
50
51fn slot_array<T, const N: usize>() -> [TrackedCell<MaybeUninit<T>>; N] {
52 core::array::from_fn(|_| TrackedCell::new(MaybeUninit::uninit()))
53}
54
55const RETRY_LIMIT: usize = 2;
58
59pub struct EventBuf<T: Copy, const N: usize> {
72 head: AtomicU32,
73 tail: AtomicU32,
74 slots: [TrackedCell<MaybeUninit<T>>; N],
75 producer_taken: AtomicBool,
76 consumer_taken: AtomicBool,
77}
78
79unsafe impl<T: Copy + Send, const N: usize> Sync for EventBuf<T, N> {}
84
85impl<T: Copy, const N: usize> EventBuf<T, N> {
86 pub fn new() -> Self {
91 assert!(N > 0, "EventBuf capacity N must be > 0");
92 Self {
93 head: AtomicU32::new(0),
94 tail: AtomicU32::new(0),
95 slots: slot_array::<T, N>(),
96 producer_taken: AtomicBool::new(false),
97 consumer_taken: AtomicBool::new(false),
98 }
99 }
100
101 #[inline(always)]
102 const fn slot_index(pos: u32) -> usize {
103 (pos as usize) % N
104 }
105
106 #[inline]
108 pub const fn capacity(&self) -> usize {
109 N
110 }
111
112 #[inline]
121 pub fn len(&self) -> usize {
122 for _ in 0..RETRY_LIMIT {
139 let t1 = self.tail.load(Ordering::Acquire);
140 let h = self.head.load(Ordering::Relaxed);
141 fence(Ordering::Acquire);
142 let t2 = self.tail.load(Ordering::Relaxed);
143
144 if t1 == t2 {
145 return h.wrapping_sub(t1) as usize;
146 }
147 }
148
149 let t = self.tail.load(Ordering::Acquire);
153 let h = self.head.load(Ordering::Relaxed);
154 (h.wrapping_sub(t) as usize).min(N)
155 }
156
157 #[inline]
159 pub fn is_empty(&self) -> bool {
160 self.len() == 0
161 }
162
163 #[inline]
165 pub fn is_full(&self) -> bool {
166 self.len() >= N
167 }
168
169 #[inline]
174 pub fn try_producer(&self) -> Option<Producer<'_, T, N>> {
175 if self.producer_taken.swap(true, Ordering::AcqRel) {
176 None
177 } else {
178 Some(Producer {
179 buf: self,
180 _not_sync: PhantomData,
181 })
182 }
183 }
184
185 #[inline]
190 pub fn producer(&self) -> Producer<'_, T, N> {
191 self.try_producer()
192 .expect("EventBuf: only one Producer may be active at a time")
193 }
194
195 #[inline]
200 pub fn try_consumer(&self) -> Option<Consumer<'_, T, N>> {
201 if self.consumer_taken.swap(true, Ordering::AcqRel) {
202 None
203 } else {
204 Some(Consumer {
205 buf: self,
206 _not_sync: PhantomData,
207 })
208 }
209 }
210
211 #[inline]
216 pub fn consumer(&self) -> Consumer<'_, T, N> {
217 self.try_consumer()
218 .expect("EventBuf: only one Consumer may be active at a time")
219 }
220}
221
222impl<T: Copy, const N: usize> Default for EventBuf<T, N> {
223 fn default() -> Self {
224 Self::new()
225 }
226}
227
228impl<T: Copy, const N: usize> core::fmt::Debug for EventBuf<T, N> {
229 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
230 f.debug_struct("EventBuf")
231 .field("len", &self.len())
232 .field("capacity", &N)
233 .finish()
234 }
235}
236
237pub struct Producer<'a, T: Copy, const N: usize> {
241 buf: &'a EventBuf<T, N>,
242 _not_sync: PhantomData<Cell<()>>,
243}
244
245impl<T: Copy, const N: usize> Producer<'_, T, N> {
246 #[inline]
251 pub fn push(&self, val: T) -> Result<(), T> {
252 let head = self.buf.head.load(Ordering::Relaxed);
253 let tail = self.buf.tail.load(Ordering::Acquire);
254 if head.wrapping_sub(tail) as usize >= N {
255 return Err(val);
256 }
257 let idx = EventBuf::<T, N>::slot_index(head);
258 self.buf.slots[idx].with_mut(|slot| unsafe { (*slot).write(val) });
261 self.buf.head.store(head.wrapping_add(1), Ordering::Release);
262 Ok(())
263 }
264}
265
266impl<T: Copy, const N: usize> Drop for Producer<'_, T, N> {
267 fn drop(&mut self) {
268 self.buf.producer_taken.store(false, Ordering::Release);
269 }
270}
271
272impl<T: Copy, const N: usize> core::fmt::Debug for Producer<'_, T, N> {
273 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
274 f.debug_struct("event_buf::Producer")
275 .field("capacity", &N)
276 .finish()
277 }
278}
279
280pub struct Consumer<'a, T: Copy, const N: usize> {
284 buf: &'a EventBuf<T, N>,
285 _not_sync: PhantomData<Cell<()>>,
286}
287
288impl<T: Copy, const N: usize> Consumer<'_, T, N> {
289 #[inline]
293 pub fn pop(&self) -> Option<T> {
294 let tail = self.buf.tail.load(Ordering::Relaxed);
295 let head = self.buf.head.load(Ordering::Acquire);
296 if tail == head {
297 return None;
298 }
299 let idx = EventBuf::<T, N>::slot_index(tail);
300 let val = self.buf.slots[idx].with(|slot| unsafe { (*slot).assume_init_read() });
303 self.buf.tail.store(tail.wrapping_add(1), Ordering::Release);
304 Some(val)
305 }
306
307 #[inline]
312 pub fn peek(&self) -> Option<T> {
313 let tail = self.buf.tail.load(Ordering::Relaxed);
314 let head = self.buf.head.load(Ordering::Acquire);
315 if tail == head {
316 return None;
317 }
318 let idx = EventBuf::<T, N>::slot_index(tail);
319 Some(self.buf.slots[idx].with(|slot| unsafe { (*slot).assume_init_read() }))
323 }
324
325 #[inline]
329 pub fn drain(&self, max: usize, mut hook: impl FnMut(T)) -> usize {
330 let mut count = 0;
331 while count < max {
332 match self.pop() {
333 Some(val) => {
334 hook(val);
335 count += 1;
336 }
337 None => break,
338 }
339 }
340 count
341 }
342}
343
344impl<T: Copy, const N: usize> Drop for Consumer<'_, T, N> {
345 fn drop(&mut self) {
346 self.buf.consumer_taken.store(false, Ordering::Release);
347 }
348}
349
350impl<T: Copy, const N: usize> core::fmt::Debug for Consumer<'_, T, N> {
351 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
352 f.debug_struct("event_buf::Consumer")
353 .field("capacity", &N)
354 .finish()
355 }
356}
357
358impl<T: Copy, const N: usize> crate::traits::Sink<T> for Producer<'_, T, N> {
359 type Error = T;
360
361 #[inline]
362 fn try_push(&mut self, val: T) -> Result<(), T> {
363 self.push(val)
364 }
365}
366
367impl<T: Copy, const N: usize> crate::traits::Source<T> for Consumer<'_, T, N> {
368 #[inline]
369 fn try_pop(&mut self) -> Option<T> {
370 self.pop()
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377
378 #[test]
379 fn new_buf_is_empty() {
380 let buf = EventBuf::<u32, 4>::new();
381 assert!(buf.is_empty());
382 assert!(!buf.is_full());
383 assert_eq!(buf.len(), 0);
384 assert_eq!(buf.capacity(), 4);
385 }
386
387 #[test]
388 fn push_and_pop_fifo() {
389 let buf = EventBuf::<u32, 4>::new();
390 let p = buf.producer();
391 let c = buf.consumer();
392
393 assert!(p.push(10).is_ok());
394 assert!(p.push(20).is_ok());
395 assert!(p.push(30).is_ok());
396
397 assert_eq!(c.pop(), Some(10));
398 assert_eq!(c.pop(), Some(20));
399 assert_eq!(c.pop(), Some(30));
400 assert_eq!(c.pop(), None);
401 }
402
403 #[test]
404 fn push_rejects_when_full() {
405 let buf = EventBuf::<u32, 2>::new();
406 let p = buf.producer();
407 let c = buf.consumer();
408
409 assert!(p.push(1).is_ok());
410 assert!(p.push(2).is_ok());
411 assert_eq!(p.push(3), Err(3)); assert_eq!(c.pop(), Some(1));
415 assert!(p.push(3).is_ok());
416 }
417
418 #[test]
419 fn drain_returns_count() {
420 let buf = EventBuf::<u32, 8>::new();
421 let p = buf.producer();
422 let c = buf.consumer();
423
424 for i in 0..5 {
425 p.push(i).unwrap();
426 }
427
428 let mut out = std::vec::Vec::new();
429 let n = c.drain(3, |v| out.push(v));
430 assert_eq!(n, 3);
431 assert_eq!(out, [0, 1, 2]);
432
433 let n = c.drain(100, |v| out.push(v));
435 assert_eq!(n, 2);
436 assert_eq!(out, [0, 1, 2, 3, 4]);
437 }
438
439 #[test]
440 fn drain_on_empty_returns_zero() {
441 let buf = EventBuf::<u32, 4>::new();
442 let _p = buf.producer();
443 let c = buf.consumer();
444
445 let n = c.drain(10, |_| panic!("should not be called"));
446 assert_eq!(n, 0);
447 }
448
449 #[test]
450 fn producer_consumer_can_be_recreated() {
451 let buf = EventBuf::<u32, 4>::new();
452 {
453 let p = buf.producer();
454 p.push(1).unwrap();
455 }
456 let p = buf.producer();
458 p.push(2).unwrap();
459
460 {
461 let c = buf.consumer();
462 assert_eq!(c.pop(), Some(1));
463 }
464 let c = buf.consumer();
466 assert_eq!(c.pop(), Some(2));
467 assert_eq!(c.pop(), None);
468 }
469
470 #[test]
471 #[should_panic(expected = "only one Producer")]
472 fn double_producer_panics() {
473 let buf = EventBuf::<u32, 4>::new();
474 let _p1 = buf.producer();
475 let _p2 = buf.producer();
476 }
477
478 #[test]
479 #[should_panic(expected = "only one Consumer")]
480 fn double_consumer_panics() {
481 let buf = EventBuf::<u32, 4>::new();
482 let _c1 = buf.consumer();
483 let _c2 = buf.consumer();
484 }
485
486 #[test]
487 fn wraps_around_correctly() {
488 let buf = EventBuf::<u32, 3>::new();
489 let p = buf.producer();
490 let c = buf.consumer();
491
492 for round in 0u32..4 {
494 let base = round * 3;
495 for i in 0..3 {
496 assert!(p.push(base + i).is_ok());
497 }
498 assert_eq!(p.push(99), Err(99)); for i in 0..3 {
500 assert_eq!(c.pop(), Some(base + i));
501 }
502 assert_eq!(c.pop(), None); }
504 }
505
506 #[test]
507 fn default_is_new() {
508 let buf: EventBuf<u8, 4> = EventBuf::default();
509 assert!(buf.is_empty());
510 }
511
512 #[test]
513 fn len_and_full_track_state() {
514 let buf = EventBuf::<u32, 3>::new();
515 let p = buf.producer();
516 let c = buf.consumer();
517
518 assert_eq!(buf.len(), 0);
519 assert!(buf.is_empty());
520
521 p.push(1).unwrap();
522 assert_eq!(buf.len(), 1);
523
524 p.push(2).unwrap();
525 p.push(3).unwrap();
526 assert_eq!(buf.len(), 3);
527 assert!(buf.is_full());
528
529 c.pop();
530 assert_eq!(buf.len(), 2);
531 assert!(!buf.is_full());
532 }
533
534 #[test]
535 fn len_stays_within_capacity_while_consumer_drains() {
536 let buf = EventBuf::<u32, 8>::new();
537 let done = AtomicBool::new(false);
538 let pushes = crate::test_support::iterations(200_000);
539
540 std::thread::scope(|scope| {
541 scope.spawn(|| {
542 let p = buf.producer();
543 for i in 0..pushes {
544 let _ = p.push(i);
545 }
546 done.store(true, Ordering::Release);
547 });
548
549 scope.spawn(|| {
550 let c = buf.consumer();
551 while !done.load(Ordering::Acquire) {
552 c.pop();
553 }
554 });
555
556 while !done.load(Ordering::Acquire) {
559 let observed = buf.len();
560 assert!(
561 observed <= buf.capacity(),
562 "len() reported {observed} for a capacity-{} buffer",
563 buf.capacity()
564 );
565 }
566 });
567 }
568
569 #[test]
570 fn concurrent_spsc_preserves_fifo_and_loses_nothing() {
571 let buf = EventBuf::<u32, 4>::new();
572 let total = crate::test_support::iterations(50_000);
573
574 let received = std::thread::scope(|scope| {
575 scope.spawn(|| {
576 let p = buf.producer();
577 for i in 0..total {
580 let mut val = i;
581 while let Err(rejected) = p.push(val) {
582 val = rejected;
583 std::thread::yield_now();
584 }
585 }
586 });
587
588 let consumer = scope.spawn(|| {
589 let c = buf.consumer();
590 let mut seen = 0u32;
591 while seen < total {
592 match c.pop() {
593 Some(val) => {
595 assert_eq!(val, seen, "out-of-order pop at index {seen}");
596 seen += 1;
597 }
598 None => std::thread::yield_now(),
599 }
600 }
601 seen
602 });
603
604 consumer.join().unwrap()
605 });
606
607 assert_eq!(received, total);
608 assert_eq!(buf.len(), 0);
609 }
610
611 #[test]
612 fn handles_are_send() {
613 fn assert_send<T: Send>() {}
614 assert_send::<super::Producer<'_, u32, 4>>();
615 assert_send::<super::Consumer<'_, u32, 4>>();
616 }
617
618 #[test]
619 fn try_producer_and_try_consumer() {
620 let buf = EventBuf::<u32, 4>::new();
621 let p = buf.try_producer().expect("first producer");
622 assert!(buf.try_producer().is_none());
623 let c = buf.try_consumer().expect("first consumer");
624 assert!(buf.try_consumer().is_none());
625 p.push(1).unwrap();
626 assert_eq!(c.pop(), Some(1));
627 drop(p);
628 drop(c);
629 assert!(buf.try_producer().is_some());
630 assert!(buf.try_consumer().is_some());
631 }
632
633 #[test]
634 fn peek_copies_without_advancing() {
635 let buf = EventBuf::<u32, 4>::new();
636 let p = buf.producer();
637 let c = buf.consumer();
638
639 assert_eq!(c.peek(), None);
640 p.push(10).unwrap();
641 p.push(20).unwrap();
642 assert_eq!(c.peek(), Some(10));
643 assert_eq!(c.peek(), Some(10));
644 assert_eq!(buf.len(), 2);
645 assert_eq!(c.pop(), Some(10));
646 assert_eq!(c.peek(), Some(20));
647 assert_eq!(c.pop(), Some(20));
648 assert_eq!(c.peek(), None);
649 }
650}