1//! Collects X11 data into "packets" to be parsed by a display.
2
3use core::convert::TryInto;
4use core::fmt;
5use core::mem::replace;
6
7use alloc::{vec, vec::Vec};
8
9/// Minimal length of an X11 packet.
10const MINIMAL_PACKET_LENGTH: usize = 32;
11
12/// A wrapper around a buffer used to read X11 packets.
13pub struct PacketReader {
14 /// A partially-read packet.
15 pending_packet: Vec<u8>,
16
17 /// The point at which the packet is already read.
18 already_read: usize,
19}
20
21impl fmt::Debug for PacketReader {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 f&mut DebugTuple<'_, '_>.debug_tuple(name:"PacketReader")
24 .field(&format_args!(
25 "{}/{}",
26 self.already_read,
27 self.pending_packet.len()
28 ))
29 .finish()
30 }
31}
32
33impl Default for PacketReader {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl PacketReader {
40 /// Create a new, empty `PacketReader`.
41 ///
42 /// # Example
43 ///
44 /// ```rust
45 /// # use x11rb_protocol::packet_reader::PacketReader;
46 /// let reader = PacketReader::new();
47 /// ```
48 pub fn new() -> Self {
49 Self {
50 pending_packet: vec![0; MINIMAL_PACKET_LENGTH],
51 already_read: 0,
52 }
53 }
54
55 /// Get the buffer that the reader should fill with data.
56 ///
57 /// # Example
58 ///
59 /// ```rust
60 /// # use x11rb_protocol::packet_reader::PacketReader;
61 /// # use x11rb_protocol::protocol::xproto::{GetInputFocusReply, InputFocus, Window};
62 /// let mut reader = PacketReader::new();
63 /// let buffer: [u8; 32] = read_in_buffer();
64 ///
65 /// reader.buffer().copy_from_slice(&buffer);
66 ///
67 /// # fn read_in_buffer() -> [u8; 32] { [0; 32] }
68 /// ```
69 pub fn buffer(&mut self) -> &mut [u8] {
70 &mut self.pending_packet[self.already_read..]
71 }
72
73 /// The remaining capacity that needs to be filled.
74 pub fn remaining_capacity(&self) -> usize {
75 self.pending_packet.len() - self.already_read
76 }
77
78 /// Advance this buffer by the given amount.
79 ///
80 /// This will return the packet that was read, if enough bytes were read in order
81 /// to form a complete packet.
82 pub fn advance(&mut self, amount: usize) -> Option<Vec<u8>> {
83 self.already_read += amount;
84 debug_assert!(self.already_read <= self.pending_packet.len());
85
86 if self.already_read == MINIMAL_PACKET_LENGTH {
87 // we've read in the minimal packet, compute the amount of data we need to read
88 // to form a complete packet
89 let extra_length = extra_length(&self.pending_packet);
90
91 // tell if we need to read more
92 if extra_length > 0 {
93 let total_length = MINIMAL_PACKET_LENGTH + extra_length;
94 self.pending_packet.resize(total_length, 0);
95 return None;
96 }
97 } else if self.already_read != self.pending_packet.len() {
98 // we haven't read the full packet yet, return
99 return None;
100 }
101
102 // we've read in the full packet, return it
103 self.already_read = 0;
104 Some(replace(
105 &mut self.pending_packet,
106 vec![0; MINIMAL_PACKET_LENGTH],
107 ))
108 }
109}
110
111/// Compute the length of the data we need to read, beyond the `MINIMAL_PACKET_LENGTH`.
112fn extra_length(buffer: &[u8]) -> usize {
113 use crate::protocol::xproto::GE_GENERIC_EVENT;
114 const REPLY: u8 = 1;
115
116 let response_type: u8 = buffer[0];
117
118 if response_type == REPLY || response_type & 0x7f == GE_GENERIC_EVENT {
119 let length_field: [u8; 4] = buffer[4..8].try_into().unwrap();
120 let length_field: usize = u32::from_ne_bytes(length_field) as usize;
121 4 * length_field
122 } else {
123 // Fixed size packet: error or event that is not GE_GENERIC_EVENT
124 0
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::PacketReader;
131 use alloc::{vec, vec::Vec};
132
133 fn test_packets(packets: Vec<Vec<u8>>) {
134 // Combine all packet data into one big chunk and test that the packet reader splits things
135 let mut all_data = packets.iter().flatten().copied().collect::<Vec<u8>>();
136
137 let mut reader = PacketReader::default();
138 for (i, packet) in packets.into_iter().enumerate() {
139 std::println!("Checking packet {i}");
140 loop {
141 let buffer = reader.buffer();
142 let amount = std::cmp::min(buffer.len(), all_data.len());
143 buffer.copy_from_slice(&all_data[..amount]);
144 let _ = all_data.drain(..amount);
145
146 if let Some(read_packet) = reader.advance(amount) {
147 assert_eq!(read_packet, packet);
148 break;
149 }
150 }
151 }
152 }
153
154 fn make_reply_with_length(len: usize) -> Vec<u8> {
155 let mut packet = vec![0; len];
156 let len = (len - 32) / 4;
157
158 // write "len" to bytes 4..8 in the packet
159 let len_bytes = (len as u32).to_ne_bytes();
160 packet[4..8].copy_from_slice(&len_bytes);
161 packet[0] = 1;
162
163 packet
164 }
165
166 #[test]
167 fn fixed_size_packet() {
168 // packet with a fixed size
169 let packet = vec![0; 32];
170 test_packets(vec![packet]);
171 }
172
173 #[test]
174 fn variable_size_packet() {
175 // packet with a variable size
176 let packet = make_reply_with_length(1200);
177 test_packets(vec![packet]);
178 }
179
180 #[test]
181 fn test_many_fixed_size_packets() {
182 let mut packets = vec![];
183 for _ in 0..100 {
184 packets.push(vec![0; 32]);
185 }
186 test_packets(packets);
187 }
188
189 #[test]
190 fn test_many_variable_size_packets() {
191 let mut packets = vec![];
192 for i in 0..100 {
193 // for maximum variation, increase packet size in a curved parabola
194 // defined by -1/25 (x - 50)^2 + 100
195 let variation = ((i - 50) * (i - 50)) as f32;
196 let variation = -1.0 / 25.0 * variation + 100.0;
197 let variation = variation as usize;
198 // round to a multiple of 4
199 let variation = variation / 4 * 4;
200
201 let mut len = 1200 + variation;
202 let mut packet = vec![0; len];
203 assert_eq!(0, len % 4);
204 len = (len - 32) / 4;
205
206 // write "len" to bytes 4..8 in the packet
207 let len_bytes = (len as u32).to_ne_bytes();
208 packet[4..8].copy_from_slice(&len_bytes);
209 packet[0] = 1;
210
211 packets.push(packet);
212 }
213 test_packets(packets);
214 }
215
216 #[test]
217 fn test_many_size_packets_mixed() {
218 let mut packets = vec![];
219 for i in 0..100 {
220 // on odds, do a varsize packet
221 let mut len = if i & 1 == 1 {
222 // for maximum variation, increase packet size in a curved parabola
223 // defined by -1/25 (x - 50)^2 + 100
224 let variation = ((i - 50) * (i - 50)) as f32;
225 let variation = -1.0 / 25.0 * variation + 100.0;
226 let variation = variation as usize;
227 // round to a multiple of 4
228 let variation = variation / 4 * 4;
229
230 1200 + variation
231 } else {
232 32
233 };
234 assert_eq!(0, len % 4);
235 let mut packet = vec![0; len];
236 len = (len - 32) / 4;
237
238 // write "len" to bytes 4..8 in the packet
239 let len_bytes = (len as u32).to_ne_bytes();
240 packet[4..8].copy_from_slice(&len_bytes);
241 packet[0] = 1;
242
243 packets.push(packet);
244 }
245 test_packets(packets);
246 }
247
248 #[test]
249 fn test_debug_fixed_size_packet() {
250 // The debug output includes the length of the packet of the packet and how much was
251 // already read
252 let mut reader = PacketReader::new();
253 assert_eq!(std::format!("{:?}", reader), "PacketReader(0/32)");
254
255 let _ = reader.advance(15);
256 assert_eq!(std::format!("{:?}", reader), "PacketReader(15/32)");
257
258 let _ = reader.advance(15);
259 assert_eq!(std::format!("{:?}", reader), "PacketReader(30/32)");
260
261 let _ = reader.advance(2);
262 assert_eq!(std::format!("{:?}", reader), "PacketReader(0/32)");
263 }
264
265 #[test]
266 fn test_debug_variable_size_packet() {
267 let packet = make_reply_with_length(1200);
268 let mut reader = PacketReader::new();
269
270 let first_len = 32;
271 let second_len = 3;
272
273 reader.buffer()[..first_len].copy_from_slice(&packet[..first_len]);
274 let _ = reader.advance(first_len);
275
276 reader.buffer()[..second_len].copy_from_slice(&packet[..second_len]);
277 let _ = reader.advance(second_len);
278
279 assert_eq!(std::format!("{:?}", reader), "PacketReader(35/1200)");
280 }
281}
282