use std::collections::{HashMap, VecDeque};
pub struct SerializeQueue {
queues: HashMap<String, VecDeque<Vec<u8>>>,
drops: HashMap<String, u64>,
per_queue_cap: usize,
}
impl Default for SerializeQueue {
fn default() -> Self {
Self {
queues: HashMap::new(),
drops: HashMap::new(),
per_queue_cap: Self::DEFAULT_PER_QUEUE_CAP,
}
}
}
impl SerializeQueue {
pub const DEFAULT_PER_QUEUE_CAP: usize = 4096;
pub fn new() -> Self {
Self::default()
}
pub fn with_per_queue_cap(per_queue_cap: usize) -> Self {
Self {
queues: HashMap::new(),
drops: HashMap::new(),
per_queue_cap,
}
}
pub fn enqueue(&mut self, name: &str, bytes: Vec<u8>) {
let queue = self.queues.entry(name.to_string()).or_default();
if queue.len() >= self.per_queue_cap {
queue.pop_front();
*self.drops.entry(name.to_string()).or_default() += 1;
}
queue.push_back(bytes);
}
pub fn dequeue(&mut self, name: &str) -> Option<Vec<u8>> {
self.queues.get_mut(name).and_then(|q| q.pop_front())
}
pub fn len(&self, name: &str) -> usize {
self.queues.get(name).map(|q| q.len()).unwrap_or(0)
}
pub fn drops(&self, name: &str) -> u64 {
self.drops.get(name).copied().unwrap_or(0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn enqueue_dequeue_roundtrip() {
let mut q = SerializeQueue::new();
q.enqueue("foo", b"a".to_vec());
q.enqueue("foo", b"b".to_vec());
assert_eq!(q.len("foo"), 2);
assert_eq!(q.dequeue("foo"), Some(b"a".to_vec()));
assert_eq!(q.dequeue("foo"), Some(b"b".to_vec()));
assert_eq!(q.dequeue("foo"), None);
}
#[test]
fn enqueue_at_cap_drops_oldest_and_ticks_counter() {
let mut q = SerializeQueue::with_per_queue_cap(2);
q.enqueue("foo", b"a".to_vec());
q.enqueue("foo", b"b".to_vec());
assert_eq!(q.len("foo"), 2);
assert_eq!(q.drops("foo"), 0);
q.enqueue("foo", b"c".to_vec());
assert_eq!(q.len("foo"), 2);
assert_eq!(q.drops("foo"), 1);
assert_eq!(q.dequeue("foo"), Some(b"b".to_vec()));
assert_eq!(q.dequeue("foo"), Some(b"c".to_vec()));
}
}