use alloc::collections::BTreeMap;
use core::marker::PhantomData;
use bevy::prelude::*;
use bytes::Bytes;
use smallvec::SmallVec;
use crate::prelude::*;
#[derive(Resource)]
pub(super) struct MessageQueue<M> {
map: BTreeMap<RepliconTick, SmallVec<[Bytes; 4]>>,
marker: PhantomData<M>,
}
impl<M> MessageQueue<M> {
pub(super) fn insert(&mut self, tick: RepliconTick, message: Bytes) {
self.map.entry(tick).or_default().push(message);
}
pub(super) fn pop_if_le(
&mut self,
update_tick: RepliconTick,
) -> Option<(RepliconTick, SmallVec<[Bytes; 4]>)> {
let entry = self.map.first_entry()?;
if *entry.key() > update_tick {
return None;
}
Some(entry.remove_entry())
}
pub(super) fn len(&self) -> usize {
self.map.len()
}
pub(super) fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub(super) fn clear(&mut self) {
self.map.clear();
}
}
impl<M> Default for MessageQueue<M> {
fn default() -> Self {
Self {
map: Default::default(),
marker: PhantomData,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lower_tick() {
let mut queue = MessageQueue::<Test>::default();
queue.insert(RepliconTick::new(1), Default::default());
assert_eq!(queue.len(), 1);
assert!(queue.pop_if_le(RepliconTick::new(0)).is_none());
}
#[test]
fn bigger_tick() {
let mut queue = MessageQueue::<Test>::default();
queue.insert(RepliconTick::new(1), Default::default());
assert!(queue.pop_if_le(RepliconTick::new(2)).is_some());
assert!(queue.is_empty());
}
#[test]
fn ticks_ordering() {
let mut queue = MessageQueue::<Test>::default();
queue.insert(RepliconTick::new(0), Default::default());
queue.insert(RepliconTick::new(1), Default::default());
queue.insert(RepliconTick::new(2), Default::default());
let (tick, _) = queue.pop_if_le(RepliconTick::new(1)).unwrap();
assert_eq!(tick, RepliconTick::new(0));
let (tick, _) = queue.pop_if_le(RepliconTick::new(1)).unwrap();
assert_eq!(tick, RepliconTick::new(1));
assert!(queue.pop_if_le(RepliconTick::new(1)).is_none());
assert_eq!(queue.len(), 1);
}
#[test]
fn messages_ordering() {
let mut queue = MessageQueue::<Test>::default();
queue.insert(RepliconTick::new(0), Bytes::from_static(&[0]));
queue.insert(RepliconTick::new(0), Bytes::from_static(&[1]));
let (_, messages) = queue.pop_if_le(RepliconTick::new(0)).unwrap();
let bytes: Vec<_> = messages.into_iter().flatten().collect();
assert_eq!(bytes, [0, 1]);
assert!(queue.is_empty());
}
struct Test;
}