use std::cell::RefCell;
use std::rc::Rc;
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(super) struct SlotBuf<M, K> {
pub(super) queue: Vec<SlotMessage<M, K>>,
}
impl<M, K> SlotBuf<M, K> {
pub(super) fn new() -> Self {
Self { queue: Vec::new() }
}
}
pub struct SlotHandle<M, K>
where
M: 'static,
K: 'static,
{
pub(super) inner: Rc<RefCell<SlotBuf<M, K>>>,
pub(super) parser_kind: &'static str,
}
impl<M, K> SlotHandle<M, K>
where
M: 'static,
K: 'static,
{
pub fn drain(&mut self, out: &mut Vec<SlotMessage<M, K>>) -> usize {
let mut buf = self.inner.borrow_mut();
let n = buf.queue.len();
if n == 0 {
return 0;
}
out.append(&mut buf.queue);
n
}
pub fn pending(&self) -> usize {
self.inner.borrow().queue.len()
}
pub fn parser_kind(&self) -> &'static str {
self.parser_kind
}
pub fn clear(&mut self) {
self.inner.borrow_mut().queue.clear();
}
}
impl<M, K> Clone for SlotHandle<M, K>
where
M: 'static,
K: 'static,
{
fn clone(&self) -> Self {
Self {
inner: Rc::clone(&self.inner),
parser_kind: self.parser_kind,
}
}
}
impl<M, K> std::fmt::Debug for SlotHandle<M, K>
where
M: 'static,
K: '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 buf = Rc::new(RefCell::new(SlotBuf::<u32, u8>::new()));
let mut handle = SlotHandle::<u32, u8> {
inner: Rc::clone(&buf),
parser_kind: "test",
};
assert_eq!(handle.pending(), 0);
buf.borrow_mut().queue.push(SlotMessage {
key: 1,
side: FlowSide::Initiator,
message: 100,
ts: Timestamp::default(),
});
buf.borrow_mut().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 buf = Rc::new(RefCell::new(SlotBuf::<&'static str, u8>::new()));
let mut handle = SlotHandle::<&'static str, u8> {
inner: Rc::clone(&buf),
parser_kind: "test",
};
buf.borrow_mut().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_drain_reuses_capacity() {
let buf = Rc::new(RefCell::new(SlotBuf::<u32, u8>::new()));
let mut handle = SlotHandle::<u32, u8> {
inner: Rc::clone(&buf),
parser_kind: "test",
};
let mut out: Vec<SlotMessage<u32, u8>> = Vec::with_capacity(32);
let initial_cap = out.capacity();
for _ in 0..10 {
buf.borrow_mut().queue.push(SlotMessage {
key: 1,
side: FlowSide::Initiator,
message: 0,
ts: Timestamp::default(),
});
}
handle.drain(&mut out);
assert_eq!(out.len(), 10);
out.clear();
assert_eq!(out.capacity(), initial_cap);
}
}