diff -r 478d5372eb4a -r ae8e14d14596 rust/hedgewars-engine-messages/src/queue.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hedgewars-engine-messages/src/queue.rs Fri Aug 02 13:35:23 2019 +0200 @@ -0,0 +1,112 @@ +use crate::messages::{EngineMessage::*, SyncedEngineMessage::*, UnsyncedEngineMessage::*, *}; +use queues::*; + +#[derive(PartialEq)] +pub enum QueueChatStrategy { + NetworkGame, + LocalGame, +} + +pub struct MessagesQueue { + strategy: QueueChatStrategy, + hi_ticks: u32, + unordered: Queue, + ordered: Queue, +} + +impl MessagesQueue { + pub fn new(strategy: QueueChatStrategy) -> Self { + MessagesQueue { + strategy, + hi_ticks: 0, + unordered: queue![], + ordered: queue![], + } + } + + fn is_unordered(&self, message: &EngineMessage) -> bool { + match message { + Unordered(_) => true, + Unsynced(HogSay(_)) | Unsynced(ChatMessage(_)) | Unsynced(TeamMessage(_)) => { + self.strategy == QueueChatStrategy::NetworkGame + } + _ => false, + } + } + + pub fn push(&mut self, engine_message: EngineMessage) { + if self.is_unordered(&engine_message) { + self.unordered.add(engine_message).unwrap(); + } else if let Synced(TimeWrap, timestamp) = engine_message { + self.ordered + .add(Synced(TimeWrap, timestamp + self.hi_ticks)) + .unwrap(); + self.hi_ticks += 65536; + } else if let Synced(message, timestamp) = engine_message { + self.ordered + .add(Synced(message, timestamp + self.hi_ticks)) + .unwrap(); + } else { + self.ordered.add(engine_message).unwrap(); + } + } + + pub fn pop(&mut self, timestamp: u32) -> Option { + if let Ok(message) = self.unordered.remove() { + Some(message) + } else if let Ok(Synced(_, message_timestamp)) = self.ordered.peek() { + if message_timestamp == timestamp { + self.ordered.remove().ok() + } else { + None + } + } else { + self.ordered.remove().ok() + } + } + + pub fn iter(&mut self, timestamp: u32) -> MessagesQueueIterator { + MessagesQueueIterator { + timestamp, + queue: self, + } + } +} + +pub struct MessagesQueueIterator<'a> { + timestamp: u32, + queue: &'a mut MessagesQueue, +} + +impl<'a> Iterator for MessagesQueueIterator<'a> { + type Item = EngineMessage; + + fn next(&mut self) -> Option { + self.queue.pop(self.timestamp) + } +} + +#[test] +fn queue_order() { + use crate::messages::UnorderedEngineMessage::*; + + let mut queue = MessagesQueue::new(QueueChatStrategy::LocalGame); + + queue.push(Synced(Skip, 1)); + queue.push(Unsynced(ChatMessage("hi".to_string()))); + queue.push(Synced(TimeWrap, 65535)); + queue.push(Unordered(Ping)); + queue.push(Synced(Skip, 2)); + + let zero_tick: Vec = queue.iter(0).collect(); + assert_eq!(zero_tick, vec![Unordered(Ping)]); + assert_eq!(queue.pop(1), Some(Synced(Skip, 1))); + assert_eq!(queue.pop(1), Some(Unsynced(ChatMessage("hi".to_string())))); + assert_eq!(queue.pop(1), None); + assert_eq!(queue.pop(2), None); + assert_eq!(queue.pop(65535), Some(Synced(TimeWrap, 65535))); + assert_eq!(queue.pop(65535), None); + assert_eq!(queue.pop(65538), Some(Synced(Skip, 65538))); + assert_eq!(queue.pop(65538), None); + assert_eq!(queue.pop(65539), None); +}