use std::collections::VecDeque;
use crate::core::types::MsgId;
use super::message::Msg;
#[derive(Debug, Default)]
pub struct MsgQueue {
inner: VecDeque<Msg>,
}
impl<'a> IntoIterator for &'a MsgQueue {
type Item = &'a Msg;
type IntoIter = std::collections::vec_deque::Iter<'a, Msg>;
fn into_iter(self) -> Self::IntoIter {
self.inner.iter()
}
}
impl MsgQueue {
#[must_use]
pub fn new() -> Self {
Self {
inner: VecDeque::new(),
}
}
#[must_use]
pub fn with_capacity(n: usize) -> Self {
Self {
inner: VecDeque::with_capacity(n),
}
}
pub fn push_back(&mut self, msg: Msg) {
self.inner.push_back(msg);
}
pub fn push_front(&mut self, msg: Msg) {
self.inner.push_front(msg);
}
pub fn pop_front(&mut self) -> Option<Msg> {
self.inner.pop_front()
}
pub fn pop_back(&mut self) -> Option<Msg> {
self.inner.pop_back()
}
#[must_use]
pub fn len(&self) -> usize {
self.inner.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[must_use]
pub fn front(&self) -> Option<&Msg> {
self.inner.front()
}
pub fn front_mut(&mut self) -> Option<&mut Msg> {
self.inner.front_mut()
}
pub fn iter(&self) -> std::collections::vec_deque::Iter<'_, Msg> {
self.inner.iter()
}
#[must_use]
pub fn msg_get_id_lookup(&self, id: MsgId) -> Option<&Msg> {
self.inner.iter().find(|m| m.id() == id)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::msg::{Msg, MsgType};
#[test]
fn fifo_order() {
let mut q = MsgQueue::new();
for i in 1..=3 {
q.push_back(Msg::new(i, MsgType::ReqRedisGet, true));
}
assert_eq!(q.pop_front().unwrap().id(), 1);
assert_eq!(q.pop_front().unwrap().id(), 2);
assert_eq!(q.pop_front().unwrap().id(), 3);
assert!(q.is_empty());
}
#[test]
fn lookup_finds_by_id() {
let mut q = MsgQueue::new();
q.push_back(Msg::new(11, MsgType::ReqRedisGet, true));
q.push_back(Msg::new(22, MsgType::ReqRedisSet, true));
assert_eq!(q.msg_get_id_lookup(22).unwrap().id(), 22);
assert!(q.msg_get_id_lookup(33).is_none());
}
#[test]
fn with_capacity_starts_empty() {
let q = MsgQueue::with_capacity(8);
assert!(q.is_empty());
assert_eq!(q.len(), 0);
}
#[test]
fn push_front_and_pop_back_are_lifo_ends() {
let mut q = MsgQueue::new();
q.push_back(Msg::new(1, MsgType::ReqRedisGet, true));
q.push_front(Msg::new(0, MsgType::ReqRedisGet, true));
assert_eq!(q.front().unwrap().id(), 0);
assert_eq!(q.pop_back().unwrap().id(), 1);
assert_eq!(q.pop_back().unwrap().id(), 0);
assert!(q.pop_back().is_none());
}
#[test]
fn front_mut_mutates_head_in_place() {
let mut q = MsgQueue::new();
q.push_back(Msg::new(5, MsgType::ReqRedisGet, true));
q.front_mut().unwrap().set_swallow(true);
assert!(q.front().unwrap().flags().swallow);
let mut empty = MsgQueue::new();
assert!(empty.front_mut().is_none());
}
#[test]
fn into_iter_for_reference_yields_front_to_back() {
let mut q = MsgQueue::new();
q.push_back(Msg::new(1, MsgType::ReqRedisGet, true));
q.push_back(Msg::new(2, MsgType::ReqRedisSet, true));
let ids: Vec<u64> = (&q).into_iter().map(Msg::id).collect();
assert_eq!(ids, vec![1, 2]);
}
}