use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
#[repr(C, align(64))]
pub struct Header {
pub producer: ProducerSection,
pub consumer: ConsumerSection,
pub config: ConfigSection,
pub control: ControlSection,
}
#[repr(C)]
pub struct ProducerSection {
pub write_idx: AtomicU64, pub messages_produced: AtomicU64, _pad: [u8; 48], }
#[repr(C)]
pub struct ConsumerSection {
pub read_idx: AtomicU64, pub messages_consumed: AtomicU64, _pad: [u8; 48], }
#[repr(C)]
pub struct ConfigSection {
pub wrap_mask: u64, pub slot_count: u32, pub payload_size: u32, pub batch_size: u32, _reserved: u32, _pad: [u8; 40], }
#[repr(C)]
pub struct ControlSection {
pub backpressure: AtomicU32, pub stop: AtomicU32, pub epoch: AtomicU32, pub error_count: AtomicU32, _pad: [u8; 48], }
impl Header {
pub fn new(n_slots: usize) -> Self {
assert!(n_slots.is_power_of_two(), "n_slots must be power of 2");
Self {
producer: ProducerSection {
write_idx: AtomicU64::new(0),
messages_produced: AtomicU64::new(0),
_pad: [0; 48],
},
consumer: ConsumerSection {
read_idx: AtomicU64::new(0),
messages_consumed: AtomicU64::new(0),
_pad: [0; 48],
},
config: ConfigSection {
wrap_mask: (n_slots - 1) as u64,
slot_count: n_slots as u32,
payload_size: 192,
batch_size: 32,
_reserved: 0,
_pad: [0; 40],
},
control: ControlSection {
backpressure: AtomicU32::new(0),
stop: AtomicU32::new(0),
epoch: AtomicU32::new(0),
error_count: AtomicU32::new(0),
_pad: [0; 48],
},
}
}
#[inline]
pub fn is_full(&self) -> bool {
let write = self.producer.write_idx.load(Ordering::Acquire);
let read = self.consumer.read_idx.load(Ordering::Acquire);
(write - read) >= self.config.slot_count as u64
}
#[inline]
pub fn is_empty(&self) -> bool {
let write = self.producer.write_idx.load(Ordering::Acquire);
let read = self.consumer.read_idx.load(Ordering::Acquire);
write == read
}
#[inline]
pub fn fill_level(&self) -> u64 {
let write = self.producer.write_idx.load(Ordering::Acquire);
let read = self.consumer.read_idx.load(Ordering::Acquire);
write.saturating_sub(read)
}
}