1use crate::sync::{AtomicBool, AtomicU32, Ordering, TrackedCell, fence};
46use core::cell::Cell;
47use core::marker::PhantomData;
48use core::mem::MaybeUninit;
49
50fn slot_array<T, const N: usize>() -> [TrackedCell<MaybeUninit<T>>; N] {
51 core::array::from_fn(|_| TrackedCell::new(MaybeUninit::uninit()))
52}
53
54const RETRY_LIMIT: usize = 2;
57
58pub struct EventBuf<T: Copy, const N: usize> {
69 head: AtomicU32,
70 tail: AtomicU32,
71 slots: [TrackedCell<MaybeUninit<T>>; N],
72 producer_taken: AtomicBool,
73 consumer_taken: AtomicBool,
74}
75
76unsafe impl<T: Copy + Send, const N: usize> Sync for EventBuf<T, N> {}
81
82impl<T: Copy, const N: usize> EventBuf<T, N> {
83 pub fn new() -> Self {
88 assert!(N > 0, "EventBuf capacity N must be > 0");
89 Self {
90 head: AtomicU32::new(0),
91 tail: AtomicU32::new(0),
92 slots: slot_array::<T, N>(),
93 producer_taken: AtomicBool::new(false),
94 consumer_taken: AtomicBool::new(false),
95 }
96 }
97
98 #[inline(always)]
99 const fn slot_index(pos: u32) -> usize {
100 (pos as usize) % N
101 }
102
103 #[inline]
105 pub const fn capacity(&self) -> usize {
106 N
107 }
108
109 #[inline]
118 pub fn len(&self) -> usize {
119 for _ in 0..RETRY_LIMIT {
136 let t1 = self.tail.load(Ordering::Acquire);
137 let h = self.head.load(Ordering::Relaxed);
138 fence(Ordering::Acquire);
139 let t2 = self.tail.load(Ordering::Relaxed);
140
141 if t1 == t2 {
142 return h.wrapping_sub(t1) as usize;
143 }
144 }
145
146 let t = self.tail.load(Ordering::Acquire);
150 let h = self.head.load(Ordering::Relaxed);
151 (h.wrapping_sub(t) as usize).min(N)
152 }
153
154 #[inline]
156 pub fn is_empty(&self) -> bool {
157 self.len() == 0
158 }
159
160 #[inline]
162 pub fn is_full(&self) -> bool {
163 self.len() >= N
164 }
165
166 #[inline]
171 pub fn producer(&self) -> Producer<'_, T, N> {
172 assert!(
173 !self.producer_taken.swap(true, Ordering::AcqRel),
174 "EventBuf: only one Producer may be active at a time"
175 );
176 Producer {
177 buf: self,
178 _not_sync: PhantomData,
179 }
180 }
181
182 #[inline]
187 pub fn consumer(&self) -> Consumer<'_, T, N> {
188 assert!(
189 !self.consumer_taken.swap(true, Ordering::AcqRel),
190 "EventBuf: only one Consumer may be active at a time"
191 );
192 Consumer {
193 buf: self,
194 _not_sync: PhantomData,
195 }
196 }
197}
198
199impl<T: Copy, const N: usize> Default for EventBuf<T, N> {
200 fn default() -> Self {
201 Self::new()
202 }
203}
204
205impl<T: Copy, const N: usize> core::fmt::Debug for EventBuf<T, N> {
206 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
207 f.debug_struct("EventBuf")
208 .field("len", &self.len())
209 .field("capacity", &N)
210 .finish()
211 }
212}
213
214pub struct Producer<'a, T: Copy, const N: usize> {
218 buf: &'a EventBuf<T, N>,
219 _not_sync: PhantomData<Cell<()>>,
220}
221
222impl<T: Copy, const N: usize> Producer<'_, T, N> {
223 #[inline]
228 pub fn push(&self, val: T) -> Result<(), T> {
229 let head = self.buf.head.load(Ordering::Relaxed);
230 let tail = self.buf.tail.load(Ordering::Acquire);
231 if head.wrapping_sub(tail) as usize >= N {
232 return Err(val);
233 }
234 let idx = EventBuf::<T, N>::slot_index(head);
235 self.buf.slots[idx].with_mut(|slot| unsafe { (*slot).write(val) });
238 self.buf.head.store(head.wrapping_add(1), Ordering::Release);
239 Ok(())
240 }
241}
242
243impl<T: Copy, const N: usize> Drop for Producer<'_, T, N> {
244 fn drop(&mut self) {
245 self.buf.producer_taken.store(false, Ordering::Release);
246 }
247}
248
249impl<T: Copy, const N: usize> core::fmt::Debug for Producer<'_, T, N> {
250 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
251 f.debug_struct("event_buf::Producer")
252 .field("capacity", &N)
253 .finish()
254 }
255}
256
257pub struct Consumer<'a, T: Copy, const N: usize> {
261 buf: &'a EventBuf<T, N>,
262 _not_sync: PhantomData<Cell<()>>,
263}
264
265impl<T: Copy, const N: usize> Consumer<'_, T, N> {
266 #[inline]
270 pub fn pop(&self) -> Option<T> {
271 let tail = self.buf.tail.load(Ordering::Relaxed);
272 let head = self.buf.head.load(Ordering::Acquire);
273 if tail == head {
274 return None;
275 }
276 let idx = EventBuf::<T, N>::slot_index(tail);
277 let val = self.buf.slots[idx].with(|slot| unsafe { (*slot).assume_init_read() });
280 self.buf.tail.store(tail.wrapping_add(1), Ordering::Release);
281 Some(val)
282 }
283
284 #[inline]
288 pub fn drain(&self, max: usize, mut hook: impl FnMut(T)) -> usize {
289 let mut count = 0;
290 while count < max {
291 match self.pop() {
292 Some(val) => {
293 hook(val);
294 count += 1;
295 }
296 None => break,
297 }
298 }
299 count
300 }
301}
302
303impl<T: Copy, const N: usize> Drop for Consumer<'_, T, N> {
304 fn drop(&mut self) {
305 self.buf.consumer_taken.store(false, Ordering::Release);
306 }
307}
308
309impl<T: Copy, const N: usize> core::fmt::Debug for Consumer<'_, T, N> {
310 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
311 f.debug_struct("event_buf::Consumer")
312 .field("capacity", &N)
313 .finish()
314 }
315}
316
317impl<T: Copy, const N: usize> crate::traits::Sink<T> for Producer<'_, T, N> {
318 type Error = T;
319
320 #[inline]
321 fn try_push(&mut self, val: T) -> Result<(), T> {
322 self.push(val)
323 }
324}
325
326impl<T: Copy, const N: usize> crate::traits::Source<T> for Consumer<'_, T, N> {
327 #[inline]
328 fn try_pop(&mut self) -> Option<T> {
329 self.pop()
330 }
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336
337 #[test]
338 fn new_buf_is_empty() {
339 let buf = EventBuf::<u32, 4>::new();
340 assert!(buf.is_empty());
341 assert!(!buf.is_full());
342 assert_eq!(buf.len(), 0);
343 assert_eq!(buf.capacity(), 4);
344 }
345
346 #[test]
347 fn push_and_pop_fifo() {
348 let buf = EventBuf::<u32, 4>::new();
349 let p = buf.producer();
350 let c = buf.consumer();
351
352 assert!(p.push(10).is_ok());
353 assert!(p.push(20).is_ok());
354 assert!(p.push(30).is_ok());
355
356 assert_eq!(c.pop(), Some(10));
357 assert_eq!(c.pop(), Some(20));
358 assert_eq!(c.pop(), Some(30));
359 assert_eq!(c.pop(), None);
360 }
361
362 #[test]
363 fn push_rejects_when_full() {
364 let buf = EventBuf::<u32, 2>::new();
365 let p = buf.producer();
366 let c = buf.consumer();
367
368 assert!(p.push(1).is_ok());
369 assert!(p.push(2).is_ok());
370 assert_eq!(p.push(3), Err(3)); assert_eq!(c.pop(), Some(1));
374 assert!(p.push(3).is_ok());
375 }
376
377 #[test]
378 fn drain_returns_count() {
379 let buf = EventBuf::<u32, 8>::new();
380 let p = buf.producer();
381 let c = buf.consumer();
382
383 for i in 0..5 {
384 p.push(i).unwrap();
385 }
386
387 let mut out = std::vec::Vec::new();
388 let n = c.drain(3, |v| out.push(v));
389 assert_eq!(n, 3);
390 assert_eq!(out, [0, 1, 2]);
391
392 let n = c.drain(100, |v| out.push(v));
394 assert_eq!(n, 2);
395 assert_eq!(out, [0, 1, 2, 3, 4]);
396 }
397
398 #[test]
399 fn drain_on_empty_returns_zero() {
400 let buf = EventBuf::<u32, 4>::new();
401 let _p = buf.producer();
402 let c = buf.consumer();
403
404 let n = c.drain(10, |_| panic!("should not be called"));
405 assert_eq!(n, 0);
406 }
407
408 #[test]
409 fn producer_consumer_can_be_recreated() {
410 let buf = EventBuf::<u32, 4>::new();
411 {
412 let p = buf.producer();
413 p.push(1).unwrap();
414 }
415 let p = buf.producer();
417 p.push(2).unwrap();
418
419 {
420 let c = buf.consumer();
421 assert_eq!(c.pop(), Some(1));
422 }
423 let c = buf.consumer();
425 assert_eq!(c.pop(), Some(2));
426 assert_eq!(c.pop(), None);
427 }
428
429 #[test]
430 #[should_panic(expected = "only one Producer")]
431 fn double_producer_panics() {
432 let buf = EventBuf::<u32, 4>::new();
433 let _p1 = buf.producer();
434 let _p2 = buf.producer();
435 }
436
437 #[test]
438 #[should_panic(expected = "only one Consumer")]
439 fn double_consumer_panics() {
440 let buf = EventBuf::<u32, 4>::new();
441 let _c1 = buf.consumer();
442 let _c2 = buf.consumer();
443 }
444
445 #[test]
446 fn wraps_around_correctly() {
447 let buf = EventBuf::<u32, 3>::new();
448 let p = buf.producer();
449 let c = buf.consumer();
450
451 for round in 0u32..4 {
453 let base = round * 3;
454 for i in 0..3 {
455 assert!(p.push(base + i).is_ok());
456 }
457 assert_eq!(p.push(99), Err(99)); for i in 0..3 {
459 assert_eq!(c.pop(), Some(base + i));
460 }
461 assert_eq!(c.pop(), None); }
463 }
464
465 #[test]
466 fn default_is_new() {
467 let buf: EventBuf<u8, 4> = EventBuf::default();
468 assert!(buf.is_empty());
469 }
470
471 #[test]
472 fn len_and_full_track_state() {
473 let buf = EventBuf::<u32, 3>::new();
474 let p = buf.producer();
475 let c = buf.consumer();
476
477 assert_eq!(buf.len(), 0);
478 assert!(buf.is_empty());
479
480 p.push(1).unwrap();
481 assert_eq!(buf.len(), 1);
482
483 p.push(2).unwrap();
484 p.push(3).unwrap();
485 assert_eq!(buf.len(), 3);
486 assert!(buf.is_full());
487
488 c.pop();
489 assert_eq!(buf.len(), 2);
490 assert!(!buf.is_full());
491 }
492
493 #[test]
494 fn len_stays_within_capacity_while_consumer_drains() {
495 let buf = EventBuf::<u32, 8>::new();
496 let done = AtomicBool::new(false);
497 let pushes = crate::test_support::iterations(200_000);
498
499 std::thread::scope(|scope| {
500 scope.spawn(|| {
501 let p = buf.producer();
502 for i in 0..pushes {
503 let _ = p.push(i);
504 }
505 done.store(true, Ordering::Release);
506 });
507
508 scope.spawn(|| {
509 let c = buf.consumer();
510 while !done.load(Ordering::Acquire) {
511 c.pop();
512 }
513 });
514
515 while !done.load(Ordering::Acquire) {
518 let observed = buf.len();
519 assert!(
520 observed <= buf.capacity(),
521 "len() reported {observed} for a capacity-{} buffer",
522 buf.capacity()
523 );
524 }
525 });
526 }
527
528 #[test]
529 fn concurrent_spsc_preserves_fifo_and_loses_nothing() {
530 let buf = EventBuf::<u32, 4>::new();
531 let total = crate::test_support::iterations(50_000);
532
533 let received = std::thread::scope(|scope| {
534 scope.spawn(|| {
535 let p = buf.producer();
536 for i in 0..total {
539 let mut val = i;
540 while let Err(rejected) = p.push(val) {
541 val = rejected;
542 std::thread::yield_now();
543 }
544 }
545 });
546
547 let consumer = scope.spawn(|| {
548 let c = buf.consumer();
549 let mut seen = 0u32;
550 while seen < total {
551 match c.pop() {
552 Some(val) => {
554 assert_eq!(val, seen, "out-of-order pop at index {seen}");
555 seen += 1;
556 }
557 None => std::thread::yield_now(),
558 }
559 }
560 seen
561 });
562
563 consumer.join().unwrap()
564 });
565
566 assert_eq!(received, total);
567 assert_eq!(buf.len(), 0);
568 }
569
570 #[test]
571 fn handles_are_send() {
572 fn assert_send<T: Send>() {}
573 assert_send::<super::Producer<'_, u32, 4>>();
574 assert_send::<super::Consumer<'_, u32, 4>>();
575 }
576}