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