1use crate::{
7 connection::{advance_io, new_io_slice, IoSlice},
8 Error, Fd, Result,
9};
10use alloc::{boxed::Box, vec::Vec};
11use core::{convert::TryFrom, mem};
12use x11rb_protocol::{
13 connection::ReplyFdKind,
14 x11_utils::{ReplyFDsRequest, ReplyRequest, Request, TryParseFd, VoidRequest},
15 DiscardMode,
16};
17
18pub struct RawRequest<'target, 'req> {
27 data: &'target mut [IoSlice<'req>],
32 fds: Vec<Fd>,
33 advanced: usize,
35 variant: ReplyFdKind,
36 extension_name: Option<&'static str>,
37 discard_reply: bool,
38 buffer: Option<&'req mut [u8; 8]>,
40}
41
42pub(crate) struct BufferedRequest {
46 data: Vec<u8>,
47 fds: Vec<Fd>,
48 advanced: usize,
49 variant: ReplyFdKind,
50 discard_reply: bool,
51 extension_name: Option<&'static str>,
52 buffer: [u8; 8],
53}
54
55fn from_request<R: Request, Ret>(
56 request: R,
57 variant: ReplyFdKind,
58 discard_reply: bool,
59 f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
60) -> Ret {
61 let (serialized, fds) = request.serialize(u8::MAX);
63
64 let mut slices = [
66 new_io_slice(&[]),
67 new_io_slice(&[]),
68 new_io_slice(&serialized),
69 ];
70
71 let mut buffer = [0; 8];
73
74 let mut req = RawRequest::new(&mut slices, fds, variant, R::EXTENSION_NAME, &mut buffer);
75 if discard_reply {
76 req.discard_reply();
77 }
78
79 f(req)
80}
81
82pub fn from_void_request<R: VoidRequest, Ret>(
84 request: R,
85 discard_reply: bool,
86 f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
87) -> Ret {
88 from_request(request, ReplyFdKind::NoReply, discard_reply, f)
89}
90
91pub fn from_reply_request<R: ReplyRequest, Ret>(
93 request: R,
94 f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
95) -> Ret {
96 from_request(request, ReplyFdKind::ReplyWithoutFDs, false, f)
97}
98
99pub fn from_reply_fds_request<R: ReplyFDsRequest, Ret>(
101 request: R,
102 f: impl FnOnce(RawRequest<'_, '_>) -> Ret,
103) -> Ret {
104 from_request(request, ReplyFdKind::ReplyWithFDs, false, f)
105}
106
107impl<'target, 'req> RawRequest<'target, 'req> {
108 pub fn new(
117 data: &'target mut [IoSlice<'req>],
118 fds: Vec<Fd>,
119 variant: ReplyFdKind,
120 extension_name: Option<&'static str>,
121 buffer: &'req mut [u8; 8],
122 ) -> Self {
123 assert!(data.len() >= 3);
124 assert!(data[2].len() >= 4);
125
126 Self {
127 data,
128 fds,
129 advanced: 0,
130 variant,
131 extension_name,
132 discard_reply: false,
133 buffer: Some(buffer),
134 }
135 }
136
137 fn discard_reply(&mut self) {
139 self.discard_reply = true;
140 }
141
142 #[must_use]
143 pub fn discard_mode(&self) -> Option<DiscardMode> {
144 if self.discard_reply {
145 Some(DiscardMode::DiscardReply)
146 } else {
147 None
148 }
149 }
150
151 #[must_use]
153 pub fn variant(&self) -> ReplyFdKind {
154 self.variant
155 }
156
157 #[must_use]
160 pub fn into_raw_parts(self) -> (Box<[u8]>, Vec<Fd>) {
161 let BufferedRequest { data, fds, .. } = self.into();
162
163 (data.into_boxed_slice(), fds)
164 }
165
166 #[allow(clippy::cast_possible_truncation)]
172 pub fn format(&mut self, ext_opcode: Option<u8>, max_len: usize) -> Result<()> {
173 let len = self.len();
174
175 let x_len = len / 4;
177
178 if x_len > max_len {
179 return Err(Error::make_large_request(x_len, max_len));
180 }
181
182 if let Ok(x_len) = u16::try_from(x_len) {
184 let [l1, l2] = x_len.to_ne_bytes();
185
186 let buffer = self.buffer.as_mut().unwrap();
188 buffer[0] = match ext_opcode {
189 Some(x) => x,
190 None => self.data[2][0],
191 };
192 buffer[1] = self.data[2][1];
193 buffer[2] = l1;
194 buffer[3] = l2;
195
196 let buffer = self.buffer.take().unwrap();
198 self.data[1] = new_io_slice(&buffer[..4]);
199 advance_io(&mut self.data[2], 4);
200 } else {
201 let length_bytes = ((x_len + 1) as u32).to_ne_bytes();
202
203 let buffer = self.buffer.as_mut().unwrap();
205 buffer[0] = match ext_opcode {
206 Some(x) => x,
207 None => self.data[2][0],
208 };
209 buffer[1] = self.data[2][1];
210 buffer[2] = 0;
211 buffer[3] = 0;
212 buffer[4..8].copy_from_slice(&length_bytes);
213
214 self.data[1] = new_io_slice(self.buffer.take().unwrap());
215 advance_io(&mut self.data[2], 4);
216 }
217
218 Ok(())
219 }
220
221 #[must_use]
223 pub fn extension(&self) -> Option<&'static str> {
224 self.extension_name
225 }
226
227 pub fn len(&self) -> usize {
229 self.data
230 .iter()
231 .map(|buf| buf.len())
232 .fold(0, usize::saturating_add)
233 }
234
235 #[must_use]
237 pub fn is_empty(&self) -> bool {
238 self.data.iter().all(|buf| buf.is_empty())
239 }
240
241 #[allow(clippy::mut_mut)]
243 pub fn mut_parts(&mut self) -> (&mut &'target mut [IoSlice<'req>], &mut Vec<Fd>) {
244 (&mut self.data, &mut self.fds)
245 }
246
247 pub fn advance(&mut self, bytes: usize) {
249 self.advanced += bytes;
251
252 let mut to_remove = 0;
255 let mut total_len = 0;
256
257 for buf in self.data.iter() {
258 if total_len + buf.len() > bytes {
259 break;
260 }
261 total_len += buf.len();
262 to_remove += 1;
263 }
264
265 tracing::trace!(
266 "Advancing by {} bytes, removing {} slices and {} bytes",
267 bytes,
268 to_remove,
269 bytes - total_len,
270 );
271 self.data = &mut mem::take(&mut self.data)[to_remove..];
278
279 if !self.data.is_empty() {
281 advance_io(&mut self.data[0], bytes - total_len);
282 }
283 }
284}
285
286impl BufferedRequest {
287 pub(crate) fn take<Ret>(&mut self, f: impl FnOnce(RawRequest<'_, '_>) -> Ret) -> Ret {
288 let raw = RawRequest {
290 buffer: Some(&mut self.buffer),
291 data: &mut [
292 new_io_slice(&[]),
293 new_io_slice(&[]),
294 new_io_slice(&self.data[self.advanced..]),
295 ],
296 fds: mem::take(&mut self.fds),
297 advanced: self.advanced,
298 variant: self.variant,
299 discard_reply: self.discard_reply,
300 extension_name: self.extension_name,
301 };
302
303 f(raw)
305 }
306}
307
308cfg_async! {
309 impl BufferedRequest {
310 pub(crate) fn borrow<Ret>(&mut self, f: impl FnOnce(&mut RawRequest<'_, '_>) -> Ret) -> Ret {
311 tracing::trace!(data_len = self.data.len());
313 let mut raw = RawRequest {
314 buffer: Some(&mut self.buffer),
315 data: &mut [
316 new_io_slice(&[]),
317 new_io_slice(&[]),
318 new_io_slice(&self.data[self.advanced..]),
319 ],
320 fds: mem::take(&mut self.fds),
321 advanced: self.advanced,
322 variant: self.variant,
323 discard_reply: self.discard_reply,
324 extension_name: self.extension_name,
325 };
326
327 let ret = f(&mut raw);
329
330 let merge_buffer = if raw.data.len() > 2 && raw.data[1].len() > 0 {
332 Some(raw.data[1].len())
333 } else {
334 None
335 };
336
337 self.advanced = raw.advanced;
340 self.fds = mem::take(&mut raw.fds);
341
342 if self.advanced >= self.data.len() {
343 self.data.clear();
344 return ret;
345 }
346
347 if let Some(merge_len) = merge_buffer {
348 tracing::trace!(merge_len, "merging buffer into data");
350 self.data
351 .splice(0..4, self.buffer[..merge_len].iter().copied());
352 }
353
354 tracing::trace!("{:?}", &self.data);
355
356 ret
357 }
358 }
359}
360
361impl<'target, 'req> From<RawRequest<'target, 'req>> for BufferedRequest {
362 fn from(raw: RawRequest<'target, 'req>) -> Self {
363 let mut data = Vec::with_capacity(raw.len() + 4);
365 for buf in raw.data.iter() {
366 data.extend_from_slice(buf);
367 }
368
369 Self {
370 data,
371 advanced: raw.advanced,
372 variant: raw.variant,
373 extension_name: raw.extension_name,
374 fds: raw.fds,
375 discard_reply: raw.discard_reply,
376 buffer: match raw.buffer {
377 Some(buf) => *buf,
378 None => [0; 8],
379 },
380 }
381 }
382}
383
384pub struct RawReply {
386 data: Box<[u8]>,
387 fds: Vec<Fd>,
388}
389
390impl RawReply {
391 #[must_use]
392 pub fn new(data: Box<[u8]>, fds: Vec<Fd>) -> Self {
393 Self { data, fds }
394 }
395
396 pub fn into_reply<T: TryParseFd>(mut self) -> Result<T> {
397 let (val, _) =
398 T::try_parse_fd(&self.data, &mut self.fds).map_err(Error::make_parse_error)?;
399 Ok(val)
400 }
401}