low_latency_data_structures/spsc/
producer.rs1use std::marker::PhantomData;
2
3use crate::mem::Allocation;
4use crate::shim::cell::Cell;
5use crate::shim::sync::Arc;
6use crate::shim::sync::atomic::AtomicUsize;
7use crate::spsc::queue::Queue;
8
9#[repr(C, align(128))]
10pub(super) struct ProducerState {
11 pub tail: AtomicUsize,
12 pub cached_head: Cell<usize>,
13}
14
15pub struct Producer<T, const CAPACITY: usize, AllocT: Allocation<T>> {
22 inner: Arc<Queue<T, CAPACITY, AllocT>>,
23 _not_sync: PhantomData<*const ()>,
24}
25
26impl<T, const CAPACITY: usize, AllocT: Allocation<T>> std::fmt::Debug
27 for Producer<T, CAPACITY, AllocT>
28{
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.debug_struct("Producer")
31 .field("capacity", &CAPACITY)
32 .finish_non_exhaustive()
33 }
34}
35
36unsafe impl<T: Send, const CAPACITY: usize, AllocT: Allocation<T> + Send> Send
39 for Producer<T, CAPACITY, AllocT>
40{
41}
42
43impl<T, const CAPACITY: usize, AllocT: Allocation<T>> Producer<T, CAPACITY, AllocT> {
44 pub(super) fn new(queue: Arc<Queue<T, CAPACITY, AllocT>>) -> Self {
45 Self {
46 inner: queue,
47 _not_sync: PhantomData,
48 }
49 }
50
51 #[inline]
70 #[must_use = "if the queue is full, the returned item must be handled (e.g. retried) or it is silently dropped"]
71 pub fn push(&self, item: T) -> Option<T> {
72 self.inner.push(item)
73 }
74}
75
76#[cfg(test)]
77mod tests {
78
79 use super::*;
80 use crate::shim::cell::UnsafeCell;
81
82 struct NeverAlloc;
83 impl<T> Allocation<T> for NeverAlloc {
84 fn ptr(&self) -> *mut UnsafeCell<std::mem::MaybeUninit<T>> {
85 unreachable!("it's just a stub")
86 }
87 }
88
89 static_assertions::assert_not_impl_any!(Producer<u32, 0, NeverAlloc>: Sync);
92}