1 use hedgewars_engine_messages::{ |
|
2 messages::EngineMessage::*, messages::SyncedEngineMessage::*, |
|
3 messages::UnsyncedEngineMessage::*, messages::*, |
|
4 }; |
|
5 use queues::*; |
|
6 |
|
7 #[derive(PartialEq)] |
|
8 pub enum QueueChatStrategy { |
|
9 NetworkGame, |
|
10 LocalGame, |
|
11 } |
|
12 |
|
13 pub struct MessagesQueue { |
|
14 strategy: QueueChatStrategy, |
|
15 hi_ticks: u32, |
|
16 unordered: Queue<EngineMessage>, |
|
17 ordered: Queue<EngineMessage>, |
|
18 } |
|
19 |
|
20 impl MessagesQueue { |
|
21 pub fn new(strategy: QueueChatStrategy) -> Self { |
|
22 MessagesQueue { |
|
23 strategy, |
|
24 hi_ticks: 0, |
|
25 unordered: queue![], |
|
26 ordered: queue![], |
|
27 } |
|
28 } |
|
29 |
|
30 fn is_unordered(&self, message: &EngineMessage) -> bool { |
|
31 match message { |
|
32 Unordered(_) => true, |
|
33 Unsynced(HogSay(_)) | Unsynced(ChatMessage(_)) | Unsynced(TeamMessage(_)) => { |
|
34 self.strategy == QueueChatStrategy::NetworkGame |
|
35 } |
|
36 _ => false, |
|
37 } |
|
38 } |
|
39 |
|
40 pub fn push(&mut self, engine_message: EngineMessage) { |
|
41 if self.is_unordered(&engine_message) { |
|
42 self.unordered.add(engine_message).unwrap(); |
|
43 } else if let Synced(TimeWrap, timestamp) = engine_message { |
|
44 self.ordered |
|
45 .add(Synced(TimeWrap, timestamp + self.hi_ticks)) |
|
46 .unwrap(); |
|
47 self.hi_ticks += 65536; |
|
48 } else if let Synced(message, timestamp) = engine_message { |
|
49 self.ordered |
|
50 .add(Synced(message, timestamp + self.hi_ticks)) |
|
51 .unwrap(); |
|
52 } else { |
|
53 self.ordered.add(engine_message).unwrap(); |
|
54 } |
|
55 } |
|
56 |
|
57 pub fn pop(&mut self, timestamp: u32) -> Option<EngineMessage> { |
|
58 if let Ok(message) = self.unordered.remove() { |
|
59 Some(message) |
|
60 } else if let Ok(Synced(_, message_timestamp)) = self.ordered.peek() { |
|
61 if message_timestamp == timestamp { |
|
62 self.ordered.remove().ok() |
|
63 } else { |
|
64 None |
|
65 } |
|
66 } else { |
|
67 self.ordered.remove().ok() |
|
68 } |
|
69 } |
|
70 |
|
71 pub fn iter(&mut self, timestamp: u32) -> MessagesQueueIterator { |
|
72 MessagesQueueIterator { |
|
73 timestamp, |
|
74 queue: self, |
|
75 } |
|
76 } |
|
77 } |
|
78 |
|
79 pub struct MessagesQueueIterator<'a> { |
|
80 timestamp: u32, |
|
81 queue: &'a mut MessagesQueue, |
|
82 } |
|
83 |
|
84 impl<'a> Iterator for MessagesQueueIterator<'a> { |
|
85 type Item = EngineMessage; |
|
86 |
|
87 fn next(&mut self) -> Option<EngineMessage> { |
|
88 self.queue.pop(self.timestamp) |
|
89 } |
|
90 } |
|
91 |
|
92 #[test] |
|
93 fn queue_order() { |
|
94 use hedgewars_engine_messages::messages::UnorderedEngineMessage::*; |
|
95 |
|
96 let mut queue = MessagesQueue::new(QueueChatStrategy::LocalGame); |
|
97 |
|
98 queue.push(Synced(Skip, 1)); |
|
99 queue.push(Unsynced(ChatMessage("hi".to_string()))); |
|
100 queue.push(Synced(TimeWrap, 65535)); |
|
101 queue.push(Unordered(Ping)); |
|
102 queue.push(Synced(Skip, 2)); |
|
103 |
|
104 let zero_tick: Vec<EngineMessage> = queue.iter(0).collect(); |
|
105 assert_eq!(zero_tick, vec![Unordered(Ping)]); |
|
106 assert_eq!(queue.pop(1), Some(Synced(Skip, 1))); |
|
107 assert_eq!(queue.pop(1), Some(Unsynced(ChatMessage("hi".to_string())))); |
|
108 assert_eq!(queue.pop(1), None); |
|
109 assert_eq!(queue.pop(2), None); |
|
110 assert_eq!(queue.pop(65535), Some(Synced(TimeWrap, 65535))); |
|
111 assert_eq!(queue.pop(65535), None); |
|
112 assert_eq!(queue.pop(65538), Some(Synced(Skip, 65538))); |
|
113 assert_eq!(queue.pop(65538), None); |
|
114 assert_eq!(queue.pop(65539), None); |
|
115 } |
|