1 //! Utility functions for X11 things.
2 //!
3 //! The most important definitions in this module are the [`TryParse`], [`TryParseFd`] and
4 //! [`Serialize`] traits. These traits are used internally for parsing incoming data and producing
5 //! outgoing data when talking with the X11 server.
6
7 use std::convert::TryInto;
8
9 use crate::errors::ParseError;
10 use crate::protocol::ErrorKind;
11 use crate::utils::RawFdContainer;
12
13 /// Representation of an X11 error packet that was sent by the server.
14 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
15 pub struct X11Error {
16 /// The kind of error that occurred.
17 pub error_kind: ErrorKind,
18 /// The kind of error that occurred as it appears "on the wire".
19 pub error_code: u8,
20 /// The sequence number of the request that caused this error.
21 pub sequence: u16,
22 /// The value in the request that caused the error.
23 pub bad_value: u32,
24 /// The minor opcode of the request that caused this error.
25 pub minor_opcode: u16,
26 /// The major opcode of the request that caused this error.
27 pub major_opcode: u8,
28 }
29
30 impl X11Error {
31 /// Parse an X11 error.
try_parse( data: &[u8], ext_info_provider: &dyn ExtInfoProvider, ) -> Result<Self, ParseError>32 pub fn try_parse(
33 data: &[u8],
34 ext_info_provider: &dyn ExtInfoProvider,
35 ) -> Result<Self, ParseError> {
36 let (response_type, remaining) = u8::try_parse(data)?;
37 let (error_code, remaining) = u8::try_parse(remaining)?;
38 let (sequence, remaining) = u16::try_parse(remaining)?;
39 let (bad_value, remaining) = u32::try_parse(remaining)?;
40 let (minor_opcode, remaining) = u16::try_parse(remaining)?;
41 let (major_opcode, _) = u8::try_parse(remaining)?;
42 if response_type != 0 {
43 Err(ParseError::InvalidValue)
44 } else {
45 let error_kind = ErrorKind::from_wire_error_code(error_code, ext_info_provider);
46 Ok(X11Error {
47 error_kind,
48 error_code,
49 sequence,
50 bad_value,
51 minor_opcode,
52 major_opcode,
53 })
54 }
55 }
56 }
57
58 impl From<&X11Error> for [u8; 32] {
from(input: &X11Error) -> Self59 fn from(input: &X11Error) -> Self {
60 let sequence_bytes = input.sequence.serialize();
61 let bad_value_bytes = input.bad_value.serialize();
62 let minor_opcode_bytes = input.minor_opcode.serialize();
63 [
64 0,
65 input.error_code,
66 sequence_bytes[0],
67 sequence_bytes[1],
68 bad_value_bytes[0],
69 bad_value_bytes[1],
70 bad_value_bytes[2],
71 bad_value_bytes[3],
72 minor_opcode_bytes[0],
73 minor_opcode_bytes[1],
74 input.major_opcode,
75 0,
76 0,
77 0,
78 0,
79 0,
80 0,
81 0,
82 0,
83 0,
84 0,
85 0,
86 0,
87 0,
88 0,
89 0,
90 0,
91 0,
92 0,
93 0,
94 0,
95 0,
96 ]
97 }
98 }
99 impl From<X11Error> for [u8; 32] {
from(input: X11Error) -> Self100 fn from(input: X11Error) -> Self {
101 Self::from(&input)
102 }
103 }
104
105 /// Information about a X11 extension.
106 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
107 pub struct ExtensionInformation {
108 /// Major opcode used in request
109 pub major_opcode: u8,
110 /// Lowest event number used by the extension.
111 pub first_event: u8,
112 /// Lowest error number used by the extension.
113 pub first_error: u8,
114 }
115
116 /// Trait to provide information about extensions.
117 pub trait ExtInfoProvider {
118 /// Returns the information of the extension that whose
119 /// opcode is `major_opcode`.
get_from_major_opcode(&self, major_opcode: u8) -> Option<(&str, ExtensionInformation)>120 fn get_from_major_opcode(&self, major_opcode: u8) -> Option<(&str, ExtensionInformation)>;
121
122 /// Returns the information of the extension that whose
123 /// event number range includes `event_number`.
get_from_event_code(&self, event_code: u8) -> Option<(&str, ExtensionInformation)>124 fn get_from_event_code(&self, event_code: u8) -> Option<(&str, ExtensionInformation)>;
125
126 /// Returns the information of the extension that whose
127 /// error number range includes `error_number`.
get_from_error_code(&self, error_code: u8) -> Option<(&str, ExtensionInformation)>128 fn get_from_error_code(&self, error_code: u8) -> Option<(&str, ExtensionInformation)>;
129 }
130
131 /// A type implementing this trait can be parsed from some raw bytes.
132 pub trait TryParse: Sized {
133 /// Try to parse the given values into an instance of this type.
134 ///
135 /// If parsing is successful, an instance of the type and a slice for the remaining data should
136 /// be returned. Otherwise, an error is returned.
try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError>137 fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError>;
138 }
139
140 /// A type implementing this trait can be parsed from some raw bytes and a list of fds.
141 pub trait TryParseFd: Sized {
142 /// Try to parse the given values into an instance of this type.
143 ///
144 /// File descriptors are consumed by removing them from the beginning of the given `fds` `Vec`.
145 /// If a file descriptor is expected, but missing, a `ParseError` should be returned. If more file
146 /// descriptors are provided than expected, this is not an error and the remaining descriptors
147 /// should be left in the `Vec`.
148 ///
149 /// If parsing is successful, an instance of the type and a slice for the remaining data should
150 /// be returned. Otherwise, an error is returned.
try_parse_fd<'a>( value: &'a [u8], fds: &mut Vec<RawFdContainer>, ) -> Result<(Self, &'a [u8]), ParseError>151 fn try_parse_fd<'a>(
152 value: &'a [u8],
153 fds: &mut Vec<RawFdContainer>,
154 ) -> Result<(Self, &'a [u8]), ParseError>;
155 }
156
157 impl<T: TryParse> TryParseFd for T {
try_parse_fd<'a>( value: &'a [u8], _: &mut Vec<RawFdContainer>, ) -> Result<(Self, &'a [u8]), ParseError>158 fn try_parse_fd<'a>(
159 value: &'a [u8],
160 _: &mut Vec<RawFdContainer>,
161 ) -> Result<(Self, &'a [u8]), ParseError> {
162 T::try_parse(value)
163 }
164 }
165
166 /// A representation of the header of a request.
167 #[derive(Debug, Clone, Copy)]
168 pub struct RequestHeader {
169 /// The major opcode of the request.
170 pub major_opcode: u8,
171 /// The minor opcode of the request (which, for some requests, may not be an
172 /// opcode at all).
173 pub minor_opcode: u8,
174 /// The remaining length of the request, measured in 4 bytes units. Unlike the wire format,
175 /// this does *not* include the header itself, which is 1 unit (or 2 if BigRequests is
176 /// enabled and the length in the first unit is zero). If the BigRequests extension is
177 /// enabled this can be greater than u16::max_value - 1.
178 pub remaining_length: u32,
179 }
180
181 /// Has the BigRequests extension been enabled?
182 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
183 pub enum BigRequests {
184 /// The BigRequests extension has been enabled.
185 Enabled,
186 /// The BigRequests extension has not been enabled.
187 NotEnabled,
188 }
189
190 /// Parse the given input for a RequestHeader and the remaining input.
parse_request_header( input: &[u8], big_requests_enabled: BigRequests, ) -> Result<(RequestHeader, &[u8]), ParseError>191 pub fn parse_request_header(
192 input: &[u8],
193 big_requests_enabled: BigRequests,
194 ) -> Result<(RequestHeader, &[u8]), ParseError> {
195 let (major_opcode, remaining) = u8::try_parse(input)?;
196 let (minor_opcode, remaining) = u8::try_parse(remaining)?;
197 let (length, remaining) = u16::try_parse(remaining)?;
198 let (remaining_length, finally_remaining) = if length == 0 {
199 if big_requests_enabled == BigRequests::NotEnabled {
200 return Err(ParseError::InvalidValue);
201 }
202
203 let (length, remaining) = u32::try_parse(remaining)?;
204 if length < 2 {
205 return Err(ParseError::InvalidValue);
206 }
207 // Adjust length for the size of this header (two 4 byte units).
208 (length - 2, remaining)
209 } else {
210 // Adjust length for the size of this header (one 4 byte unit).
211 (u32::from(length) - 1, remaining)
212 };
213 Ok((
214 RequestHeader {
215 major_opcode,
216 minor_opcode,
217 remaining_length,
218 },
219 finally_remaining,
220 ))
221 }
222
223 /// A type implementing this trait is an X11 request.
224 pub trait Request {
225 /// The kind of reply that this request generates.
226 type Reply: Into<crate::protocol::Reply> + TryParseFd;
227
228 /// Parse a reply to this request.
229 ///
230 /// The default implementation of this function uses `Self::Reply::try_parse_fd`. There should
231 /// not be a reason why you need different behaviour.
parse_reply<'a>( bytes: &'a [u8], fds: &mut Vec<RawFdContainer>, ) -> Result<(crate::protocol::Reply, &'a [u8]), ParseError>232 fn parse_reply<'a>(
233 bytes: &'a [u8],
234 fds: &mut Vec<RawFdContainer>,
235 ) -> Result<(crate::protocol::Reply, &'a [u8]), ParseError> {
236 let (reply, remaining) = Self::Reply::try_parse_fd(bytes, fds)?;
237 Ok((reply.into(), remaining))
238 }
239 }
240
241 /// A type alias for reply parsers (matches the signature of TryParseFd).
242 pub type ReplyParsingFunction =
243 for<'a> fn(
244 &'a [u8],
245 &mut Vec<RawFdContainer>,
246 ) -> Result<(crate::protocol::Reply, &'a [u8]), ParseError>;
247
248 /// A type implementing this trait can be serialized into X11 raw bytes.
249 pub trait Serialize {
250 /// The value returned by `serialize`.
251 ///
252 /// This should be `Vec<u8>` in most cases. However, arrays like `[u8; 4]` should also be
253 /// allowed and thus this is an associated type.
254 ///
255 /// If generic associated types were available, implementing `AsRef<[u8]>` would be required.
256 type Bytes;
257
258 /// Serialize this value into X11 raw bytes.
serialize(&self) -> Self::Bytes259 fn serialize(&self) -> Self::Bytes;
260
261 /// Serialize this value into X11 raw bytes, appending the result into `bytes`.
262 ///
263 /// When calling this method, the given vector must satisfy `assert_eq!(bytes.len() % 4, 0);`.
264 /// In words: Its length must be a multiple of four.
serialize_into(&self, bytes: &mut Vec<u8>)265 fn serialize_into(&self, bytes: &mut Vec<u8>);
266 }
267
268 // Now implement TryParse and Serialize for some primitive data types that we need.
269
270 macro_rules! implement_try_parse {
271 ($t:ty) => {
272 impl TryParse for $t {
273 fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
274 let len = std::mem::size_of::<$t>();
275 let bytes = value
276 .get(..len)
277 .ok_or(ParseError::InsufficientData)?
278 .try_into() // TryInto<[u8; len]>
279 .unwrap();
280 Ok((<$t>::from_ne_bytes(bytes), &value[len..]))
281 }
282 }
283 };
284 }
285
286 macro_rules! implement_serialize {
287 ($t:ty: $size:expr) => {
288 impl Serialize for $t {
289 type Bytes = [u8; $size];
290 fn serialize(&self) -> Self::Bytes {
291 self.to_ne_bytes()
292 }
293 fn serialize_into(&self, bytes: &mut Vec<u8>) {
294 bytes.extend_from_slice(&self.to_ne_bytes());
295 }
296 }
297 };
298 }
299
300 macro_rules! forward_float {
301 ($from:ty: $to:ty) => {
302 impl TryParse for $from {
303 fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
304 let (data, remaining) = <$to>::try_parse(value)?;
305 Ok((<$from>::from_bits(data), remaining))
306 }
307 }
308 impl Serialize for $from {
309 type Bytes = <$to as Serialize>::Bytes;
310 fn serialize(&self) -> Self::Bytes {
311 self.to_bits().serialize()
312 }
313 fn serialize_into(&self, bytes: &mut Vec<u8>) {
314 self.to_bits().serialize_into(bytes);
315 }
316 }
317 };
318 }
319
320 implement_try_parse!(u8);
321 implement_try_parse!(i8);
322 implement_try_parse!(u16);
323 implement_try_parse!(i16);
324 implement_try_parse!(u32);
325 implement_try_parse!(i32);
326 implement_try_parse!(u64);
327 implement_try_parse!(i64);
328
329 implement_serialize!(u8: 1);
330 implement_serialize!(i8: 1);
331 implement_serialize!(u16: 2);
332 implement_serialize!(i16: 2);
333 implement_serialize!(u32: 4);
334 implement_serialize!(i32: 4);
335 implement_serialize!(u64: 8);
336 implement_serialize!(i64: 8);
337
338 forward_float!(f32: u32);
339 forward_float!(f64: u64);
340
341 impl TryParse for bool {
try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError>342 fn try_parse(value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
343 let (data, remaining) = u8::try_parse(value)?;
344 Ok((data != 0, remaining))
345 }
346 }
347
348 impl Serialize for bool {
349 type Bytes = [u8; 1];
serialize(&self) -> Self::Bytes350 fn serialize(&self) -> Self::Bytes {
351 [u8::from(*self)]
352 }
serialize_into(&self, bytes: &mut Vec<u8>)353 fn serialize_into(&self, bytes: &mut Vec<u8>) {
354 bytes.push(u8::from(*self));
355 }
356 }
357
358 // Tuple handling
359
360 macro_rules! tuple_try_parse {
361 ($($name:ident)*) => {
362 impl<$($name,)*> TryParse for ($($name,)*)
363 where $($name: TryParse,)*
364 {
365 #[allow(non_snake_case)]
366 fn try_parse(remaining: &[u8]) -> Result<(($($name,)*), &[u8]), ParseError> {
367 $(let ($name, remaining) = $name::try_parse(remaining)?;)*
368 Ok((($($name,)*), remaining))
369 }
370 }
371 }
372 }
373
374 macro_rules! tuple_serialize {
375 ($($name:ident:$idx:tt)*) => {
376 impl<$($name,)*> Serialize for ($($name,)*)
377 where $($name: Serialize,)*
378 {
379 type Bytes = Vec<u8>;
380 fn serialize(&self) -> Self::Bytes {
381 let mut result = Vec::new();
382 self.serialize_into(&mut result);
383 result
384 }
385 fn serialize_into(&self, bytes: &mut Vec<u8>) {
386 $(self.$idx.serialize_into(bytes);)*
387 }
388 }
389 }
390 }
391
392 macro_rules! tuple_impls {
393 ($($name:ident:$idx:tt)*) => {
394 tuple_try_parse!($($name)*);
395 tuple_serialize!($($name:$idx)*);
396 }
397 }
398
399 // We can optimise serialisation of empty tuples or one-element-tuples with different Bytes type
400 impl Serialize for () {
401 type Bytes = [u8; 0];
serialize(&self) -> Self::Bytes402 fn serialize(&self) -> Self::Bytes {
403 []
404 }
serialize_into(&self, _bytes: &mut Vec<u8>)405 fn serialize_into(&self, _bytes: &mut Vec<u8>) {}
406 }
407
408 impl<T: Serialize> Serialize for (T,) {
409 type Bytes = T::Bytes;
serialize(&self) -> Self::Bytes410 fn serialize(&self) -> Self::Bytes {
411 self.0.serialize()
412 }
serialize_into(&self, bytes: &mut Vec<u8>)413 fn serialize_into(&self, bytes: &mut Vec<u8>) {
414 self.0.serialize_into(bytes)
415 }
416 }
417
418 tuple_try_parse!();
419 tuple_try_parse!(A);
420 tuple_impls!(A:0 B:1);
421 tuple_impls!(A:0 B:1 C:2);
422 tuple_impls!(A:0 B:1 C:2 D:3);
423 tuple_impls!(A:0 B:1 C:2 D:3 E:4);
424 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5);
425 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6);
426 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7);
427 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8);
428 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9);
429 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10);
430 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11);
431 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12);
432 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12 N:13);
433 tuple_impls!(A:0 B:1 C:2 D:3 E:4 F:5 G:6 H:7 I:8 J:9 K:10 L:11 M:12 N:13 O:14);
434
435 /// Parse a list of objects from the given data.
436 ///
437 /// This function parses a list of objects where the length of the list was specified externally.
438 /// The wire format for `list_length` instances of `T` will be read from the given data.
parse_list<T>(data: &[u8], list_length: usize) -> Result<(Vec<T>, &[u8]), ParseError> where T: TryParse,439 pub fn parse_list<T>(data: &[u8], list_length: usize) -> Result<(Vec<T>, &[u8]), ParseError>
440 where
441 T: TryParse,
442 {
443 let mut remaining = data;
444 let mut result = Vec::with_capacity(list_length);
445 for _ in 0..list_length {
446 let (entry, new_remaining) = T::try_parse(remaining)?;
447 result.push(entry);
448 remaining = new_remaining;
449 }
450 Ok((result, remaining))
451 }
452
453 /// Parse a list of `u8` from the given data.
parse_u8_list(data: &[u8], list_length: usize) -> Result<(&[u8], &[u8]), ParseError>454 pub fn parse_u8_list(data: &[u8], list_length: usize) -> Result<(&[u8], &[u8]), ParseError> {
455 if data.len() < list_length {
456 Err(ParseError::InsufficientData)
457 } else {
458 Ok(data.split_at(list_length))
459 }
460 }
461
462 impl<T: Serialize> Serialize for [T] {
463 type Bytes = Vec<u8>;
serialize(&self) -> Self::Bytes464 fn serialize(&self) -> Self::Bytes {
465 let mut result = Vec::new();
466 self.serialize_into(&mut result);
467 result
468 }
serialize_into(&self, bytes: &mut Vec<u8>)469 fn serialize_into(&self, bytes: &mut Vec<u8>) {
470 for item in self {
471 item.serialize_into(bytes);
472 }
473 }
474 }
475
476 // This macro is used by the generated code to implement `std::ops::BitOr` and
477 // `std::ops::BitOrAssign`.
478 macro_rules! bitmask_binop {
479 ($t:ty, $u:ty) => {
480 impl std::ops::BitOr for $t {
481 type Output = $t;
482 fn bitor(self, other: Self) -> Self::Output {
483 Self::from(<$u>::from(self) | <$u>::from(other))
484 }
485 }
486 impl std::ops::BitOr<$u> for $t {
487 type Output = $t;
488 fn bitor(self, other: $u) -> Self::Output {
489 self | Self::from(other)
490 }
491 }
492 impl std::ops::BitOr<$t> for $u {
493 type Output = $t;
494 fn bitor(self, other: $t) -> Self::Output {
495 <$t>::from(self) | other
496 }
497 }
498 impl std::ops::BitOrAssign<$t> for $u {
499 fn bitor_assign(&mut self, other: $t) {
500 *self |= Self::from(other)
501 }
502 }
503 impl std::ops::BitOrAssign<$u> for $t {
504 fn bitor_assign(&mut self, other: $u) {
505 *self = *self | Self::from(other)
506 }
507 }
508 };
509 }
510
511 /// Wrapper around TryInto that produces a ParseError.
512 ///
513 /// This trait shortens `x.try_into().or(Err(ParseError::ConversionFailed))` to `x.try_to_usize()`.
514 pub(crate) trait TryIntoUSize: TryInto<usize> {
515 /// Attempt the conversion
try_to_usize(self) -> Result<usize, ParseError>516 fn try_to_usize(self) -> Result<usize, ParseError> {
517 self.try_into().or(Err(ParseError::ConversionFailed))
518 }
519 }
520
521 impl TryIntoUSize for u8 {}
522 impl TryIntoUSize for u16 {}
523 impl TryIntoUSize for u32 {}
524 impl TryIntoUSize for u64 {}
525 impl TryIntoUSize for i8 {}
526 impl TryIntoUSize for i16 {}
527 impl TryIntoUSize for i32 {}
528 impl TryIntoUSize for i64 {}
529
530 /// A helper macro for managing atoms
531 ///
532 /// If we need to use multiple atoms, one would normally write code such as
533 /// ```
534 /// # use x11rb::protocol::xproto::{Atom, ConnectionExt, InternAtomReply};
535 /// # use x11rb::errors::{ConnectionError, ReplyError};
536 /// # use x11rb::cookie::Cookie;
537 /// #[allow(non_snake_case)]
538 /// pub struct AtomCollection {
539 /// pub _NET_WM_NAME: Atom,
540 /// pub _NET_WM_ICON: Atom,
541 /// pub ATOM_WITH_SPACES: Atom,
542 /// pub WHATEVER: Atom,
543 /// }
544 ///
545 /// #[allow(non_snake_case)]
546 /// struct AtomCollectionCookie<'c, C: ConnectionExt> {
547 /// _NET_WM_NAME: Cookie<'c, C, InternAtomReply>,
548 /// _NET_WM_ICON: Cookie<'c, C, InternAtomReply>,
549 /// ATOM_WITH_SPACES: Cookie<'c, C, InternAtomReply>,
550 /// WHATEVER: Cookie<'c, C, InternAtomReply>,
551 /// }
552 ///
553 /// impl AtomCollection {
554 /// pub fn new<C: ConnectionExt>(
555 /// conn: &C,
556 /// ) -> Result<AtomCollectionCookie<'_, C>, ConnectionError> {
557 /// Ok(AtomCollectionCookie {
558 /// _NET_WM_NAME: conn.intern_atom(false, b"_NET_WM_NAME")?,
559 /// _NET_WM_ICON: conn.intern_atom(false, b"_NET_WM_ICON")?,
560 /// ATOM_WITH_SPACES: conn.intern_atom(false, b"ATOM WITH SPACES")?,
561 /// WHATEVER: conn.intern_atom(false, b"WHATEVER")?,
562 /// })
563 /// }
564 /// }
565 ///
566 /// impl<'c, C> AtomCollectionCookie<'c, C>
567 /// where
568 /// C: ConnectionExt,
569 /// {
570 /// pub fn reply(self) -> Result<AtomCollection, ReplyError> {
571 /// Ok(AtomCollection {
572 /// _NET_WM_NAME: self._NET_WM_NAME.reply()?.atom,
573 /// _NET_WM_ICON: self._NET_WM_ICON.reply()?.atom,
574 /// ATOM_WITH_SPACES: self.ATOM_WITH_SPACES.reply()?.atom,
575 /// WHATEVER: self.WHATEVER.reply()?.atom,
576 /// })
577 /// }
578 /// }
579 /// ```
580 /// This macro automatically produces this code with
581 /// ```
582 /// # use x11rb::atom_manager;
583 /// atom_manager! {
584 /// pub AtomCollection: AtomCollectionCookie {
585 /// _NET_WM_NAME,
586 /// _NET_WM_ICON,
587 /// ATOM_WITH_SPACES: b"ATOM WITH SPACES",
588 /// WHATEVER,
589 /// }
590 /// }
591 /// ```
592 #[macro_export]
593 macro_rules! atom_manager {
594 {
595 $vis:vis $struct_name:ident: $cookie_name:ident {
596 $($field_name:ident$(: $atom_value:expr)?,)*
597 }
598 } => {
599 // Cookie version
600 #[allow(non_snake_case)]
601 #[derive(Debug)]
602 $vis struct $cookie_name<'a, C: $crate::protocol::xproto::ConnectionExt> {
603 phantom: std::marker::PhantomData<&'a C>,
604 $(
605 $field_name: $crate::cookie::Cookie<'a, C, $crate::protocol::xproto::InternAtomReply>,
606 )*
607 }
608
609 // Replies
610 #[allow(non_snake_case)]
611 #[derive(Debug, Clone, Copy)]
612 $vis struct $struct_name {
613 $(
614 $vis $field_name: $crate::protocol::xproto::Atom,
615 )*
616 }
617
618 impl $struct_name {
619 $vis fn new<C: $crate::protocol::xproto::ConnectionExt>(
620 _conn: &C,
621 ) -> ::std::result::Result<$cookie_name<'_, C>, $crate::errors::ConnectionError> {
622 Ok($cookie_name {
623 phantom: std::marker::PhantomData,
624 $(
625 $field_name: _conn.intern_atom(
626 false,
627 $crate::__atom_manager_atom_value!($field_name$(: $atom_value)?),
628 )?,
629 )*
630 })
631 }
632 }
633
634 impl<'a, C: $crate::protocol::xproto::ConnectionExt> $cookie_name<'a, C> {
635 $vis fn reply(self) -> ::std::result::Result<$struct_name, $crate::errors::ReplyError> {
636 Ok($struct_name {
637 $(
638 $field_name: self.$field_name.reply()?.atom,
639 )*
640 })
641 }
642 }
643 }
644 }
645
646 #[doc(hidden)]
647 #[macro_export]
648 macro_rules! __atom_manager_atom_value {
649 ($field_name:ident) => {
650 stringify!($field_name).as_bytes()
651 };
652 ($field_name:ident: $atom_value:expr) => {
653 $atom_value
654 };
655 }
656