use std::sync::Arc;
use crossbeam_queue::SegQueue;
use crate::Timestamp;
use crate::event::FlowSide;
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SlotMessage<M, K> {
pub key: K,
pub side: FlowSide,
pub message: M,
pub ts: Timestamp,
}
pub struct SlotHandle<M, K>
where
M: Send + 'static,
K: Send + 'static,
{
pub(super) inner: Arc<SegQueue<SlotMessage<M, K>>>,
pub(super) parser_kind: &'static str,
}
impl<M, K> SlotHandle<M, K>
where
M: Send + 'static,
K: Send + 'static,
{
pub fn drain(&mut self, out: &mut Vec<SlotMessage<M, K>>) -> usize {
let mut n = 0;
while let Some(msg) = self.inner.pop() {
out.push(msg);
n += 1;
}
n
}
pub fn drain_n(&mut self, out: &mut Vec<SlotMessage<M, K>>, max: usize) -> usize {
let mut n = 0;
while n < max
&& let Some(msg) = self.inner.pop()
{
out.push(msg);
n += 1;
}
n
}
pub fn pending(&self) -> usize {
self.inner.len()
}
pub fn parser_kind(&self) -> &'static str {
self.parser_kind
}
pub fn clear(&mut self) {
while self.inner.pop().is_some() {}
}
}
impl<M, K> Clone for SlotHandle<M, K>
where
M: Send + 'static,
K: Send + 'static,
{
fn clone(&self) -> Self {
Self {
inner: Arc::clone(&self.inner),
parser_kind: self.parser_kind,
}
}
}
impl<M, K> std::fmt::Debug for SlotHandle<M, K>
where
M: Send + 'static,
K: Send + 'static,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SlotHandle")
.field("parser_kind", &self.parser_kind)
.field("pending", &self.pending())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slot_handle_drain_basic() {
let queue = Arc::new(SegQueue::<SlotMessage<u32, u8>>::new());
let mut handle = SlotHandle::<u32, u8> {
inner: Arc::clone(&queue),
parser_kind: "test",
};
assert_eq!(handle.pending(), 0);
queue.push(SlotMessage {
key: 1,
side: FlowSide::Initiator,
message: 100,
ts: Timestamp::default(),
});
queue.push(SlotMessage {
key: 2,
side: FlowSide::Responder,
message: 200,
ts: Timestamp::default(),
});
assert_eq!(handle.pending(), 2);
let mut out = Vec::new();
let n = handle.drain(&mut out);
assert_eq!(n, 2);
assert_eq!(out.len(), 2);
assert_eq!(out[0].message, 100);
assert_eq!(out[1].message, 200);
assert_eq!(handle.pending(), 0);
let mut out2 = Vec::new();
let n2 = handle.drain(&mut out2);
assert_eq!(n2, 0);
assert!(out2.is_empty());
}
#[test]
fn slot_handle_clear_drops_pending() {
let queue = Arc::new(SegQueue::<SlotMessage<&'static str, u8>>::new());
let mut handle = SlotHandle::<&'static str, u8> {
inner: Arc::clone(&queue),
parser_kind: "test",
};
queue.push(SlotMessage {
key: 1,
side: FlowSide::Initiator,
message: "x",
ts: Timestamp::default(),
});
assert_eq!(handle.pending(), 1);
handle.clear();
assert_eq!(handle.pending(), 0);
}
#[test]
fn slot_handle_clone_is_competitive_consumer() {
let queue = Arc::new(SegQueue::<SlotMessage<u32, u8>>::new());
let mut h1 = SlotHandle::<u32, u8> {
inner: Arc::clone(&queue),
parser_kind: "test",
};
let mut h2 = h1.clone();
for i in 0..10 {
queue.push(SlotMessage {
key: 1,
side: FlowSide::Initiator,
message: i,
ts: Timestamp::default(),
});
}
let mut a = Vec::new();
let mut b = Vec::new();
h1.drain(&mut a);
h2.drain(&mut b);
assert_eq!(a.len() + b.len(), 10);
}
#[test]
fn slot_handle_is_send_and_sync() {
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
assert_send::<SlotHandle<u32, u8>>();
assert_sync::<SlotHandle<u32, u8>>();
}
}