rustls/msgs/
macros.rs

1/// A macro which defines an enum type.
2macro_rules! enum_builder {
3    (
4        $(#[doc = $comment:literal])*
5        #[repr($uint:ty)]
6        $(#[$metas:meta])*
7        $enum_vis:vis enum $enum_name:ident
8        {
9          $(
10            $(#[$enum_metas:meta])*
11            $enum_var:ident => $enum_val:literal),* $(,)?
12          $( !Debug:
13            $(
14                $(#[$enum_metas_nd:meta])*
15                $enum_var_nd:ident => $enum_val_nd:literal
16            ),* $(,)?
17          )?
18        }
19    ) => {
20        $(#[doc = $comment])*
21        $(#[$metas])*
22        #[non_exhaustive]
23        #[derive(PartialEq, Eq, Clone, Copy)]
24        $enum_vis enum $enum_name {
25            $(
26                $(#[$enum_metas])*
27                $enum_var
28            ),*
29            $(
30                ,
31                $(
32                    $(#[$enum_metas_nd])*
33                    $enum_var_nd
34                ),*
35            )?
36            ,Unknown($uint)
37        }
38
39        impl $enum_name {
40            // NOTE(allow) generated irrespective if there are callers
41            #[allow(dead_code)]
42            $enum_vis fn to_array(self) -> [u8; core::mem::size_of::<$uint>()] {
43                <$uint>::from(self).to_be_bytes()
44            }
45
46            // NOTE(allow) generated irrespective if there are callers
47            #[allow(dead_code)]
48            $enum_vis fn as_str(&self) -> Option<&'static str> {
49                match self {
50                    $( $enum_name::$enum_var => Some(stringify!($enum_var))),*
51                    $(, $( $enum_name::$enum_var_nd => Some(stringify!($enum_var_nd))),* )?
52                    ,$enum_name::Unknown(_) => None,
53                }
54            }
55        }
56
57        impl Codec<'_> for $enum_name {
58            // NOTE(allow) fully qualified Vec is only needed in no-std mode
59            #[allow(unused_qualifications)]
60            fn encode(&self, bytes: &mut alloc::vec::Vec<u8>) {
61                <$uint>::from(*self).encode(bytes);
62            }
63
64            fn read(r: &mut Reader<'_>) -> Result<Self, crate::error::InvalidMessage> {
65                match <$uint>::read(r) {
66                    Ok(x) => Ok($enum_name::from(x)),
67                    Err(_) => Err(crate::error::InvalidMessage::MissingData(stringify!($enum_name))),
68                }
69            }
70        }
71
72        impl From<$uint> for $enum_name {
73            fn from(x: $uint) -> Self {
74                match x {
75                    $($enum_val => $enum_name::$enum_var),*
76                    $(, $($enum_val_nd => $enum_name::$enum_var_nd),* )?
77                    , x => $enum_name::Unknown(x),
78                }
79            }
80        }
81
82        impl From<$enum_name> for $uint {
83            fn from(value: $enum_name) -> Self {
84                match value {
85                    $( $enum_name::$enum_var => $enum_val),*
86                    $(, $( $enum_name::$enum_var_nd => $enum_val_nd),* )?
87                    ,$enum_name::Unknown(x) => x
88                }
89            }
90        }
91
92        impl core::fmt::Debug for $enum_name {
93            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
94                match self {
95                    $( $enum_name::$enum_var => f.write_str(stringify!($enum_var)), )*
96                    _ => write!(f, "{}(0x{:x?})", stringify!($enum_name), <$uint>::from(*self)),
97                }
98            }
99        }
100    };
101}
102
103/// A macro which defines a structure containing TLS extensions
104///
105/// The contents are defined by two blocks, which are merged to
106/// give the struct's items.  The second block is optional.
107///
108/// The first block defines the items read-into by decoding,
109/// and used for encoding.
110///
111/// The type of each item in the first block _must_ be an `Option`.
112/// This records the presence of that extension.
113///
114/// Each item in the first block is prefixed with a match arm,
115/// which must match an `ExtensionType` variant.  This maps
116/// the item to its extension type.
117///
118/// Items in the second block are not encoded or decoded-to.
119/// They therefore must have a reasonable `Default` value.
120///
121/// All items must have a `Default`, `Debug` and `Clone`.
122macro_rules! extension_struct {
123    (
124        $(#[doc = $comment:literal])*
125        $struct_vis:vis struct $struct_name:ident$(<$struct_lt:lifetime>)*
126        {
127          $(
128            $(#[$item_attr:meta])*
129            $item_id:path => $item_vis:vis $item_slot:ident : Option<$item_ty:ty>,
130          )+
131        } $( + {
132          $(
133            $(#[$meta_attr:meta])*
134            $meta_vis:vis $meta_slot:ident : $meta_ty:ty,
135          )+
136        })*
137    ) => {
138        $(#[doc = $comment])*
139        #[non_exhaustive]
140        #[derive(Clone, Default)]
141        $struct_vis struct $struct_name$(<$struct_lt>)* {
142            $(
143              $(#[$item_attr])*
144              $item_vis $item_slot: Option<$item_ty>,
145            )+
146            $($(
147              $(#[$meta_attr])*
148              $meta_vis $meta_slot: $meta_ty,
149            )+)*
150        }
151
152        impl<'a> $struct_name$(<$struct_lt>)* {
153            /// Reads one extension typ, length and body from `r`.
154            ///
155            /// Unhandled extensions (according to `read_extension_body()` are inserted into `unknown_extensions`)
156            fn read_one(
157                &mut self,
158                r: &mut Reader<'a>,
159                mut unknown: impl FnMut(ExtensionType) -> Result<(), InvalidMessage>,
160            ) -> Result<ExtensionType, InvalidMessage> {
161                let typ = ExtensionType::read(r)?;
162                let len = usize::from(u16::read(r)?);
163                let mut ext_body = r.sub(len)?;
164                match self.read_extension_body(typ, &mut ext_body)? {
165                    true => ext_body.expect_empty(stringify!($struct_name))?,
166                    false => unknown(typ)?,
167
168                };
169                Ok(typ)
170            }
171
172            /// Reads one extension body for an extension named by `typ`.
173            ///
174            /// Returns `true` if handled, `false` otherwise.
175            ///
176            /// `r` is fully consumed if `typ` is unhandled.
177            fn read_extension_body(
178                &mut self,
179                typ: ExtensionType,
180                r: &mut Reader<'a>,
181            ) -> Result<bool, InvalidMessage> {
182                match typ {
183                   $(
184                      $item_id => Self::read_once(r, $item_id, &mut self.$item_slot)?,
185                   )*
186
187                   // read and ignore unhandled extensions
188                   _ => {
189                       r.rest();
190                       return Ok(false);
191                   }
192                }
193
194                Ok(true)
195            }
196
197            /// Decode `r` as `T` into `out`, only if `out` is `None`.
198            fn read_once<T>(r: &mut Reader<'a>, id: ExtensionType, out: &mut Option<T>) -> Result<(), InvalidMessage>
199            where T: Codec<'a>,
200            {
201                if let Some(_) = out {
202                    return Err(InvalidMessage::DuplicateExtension(u16::from(id)));
203                }
204
205                *out = Some(T::read(r)?);
206                Ok(())
207            }
208
209            /// Encode one extension body for `typ` into `output`.
210            ///
211            /// Adds nothing to `output` if `typ` is absent from this
212            /// struct, either because it is `None` or unhandled by
213            /// this struct.
214            fn encode_one(
215                &self,
216                typ: ExtensionType,
217                output: &mut Vec<u8>,
218            ) {
219                match typ {
220                    $(
221                        $item_id => if let Some(item) = &self.$item_slot {
222                            typ.encode(output);
223                            item.encode(LengthPrefixedBuffer::new(ListLength::U16, output).buf);
224                        },
225
226                    )*
227                    _ => {},
228                }
229            }
230
231            /// Return a list of extensions whose items are `Some`
232            #[allow(dead_code)]
233            pub(crate) fn collect_used(&self) -> Vec<ExtensionType> {
234                let mut r = Vec::with_capacity(Self::ALL_EXTENSIONS.len());
235
236                $(
237                    if let Some(_) = &self.$item_slot {
238                        r.push($item_id);
239                    }
240                )*
241
242                r
243            }
244
245            /// Clone the value of the extension identified by `typ` from `source` to `self`.
246            ///
247            /// Does nothing if `typ` is not an extension handled by this object.
248            #[allow(dead_code)]
249            pub(crate) fn clone_one(
250                &mut self,
251                source: &Self,
252                typ: ExtensionType,
253            )  {
254                match typ {
255                    $(
256                        $item_id => self.$item_slot = source.$item_slot.clone(),
257                    )*
258                    _ => {},
259                }
260            }
261
262            /// Remove the extension identified by `typ` from `self`.
263            #[allow(dead_code)]
264            pub(crate) fn clear(&mut self, typ: ExtensionType) {
265                match typ {
266                    $(
267                        $item_id => self.$item_slot = None,
268                    )*
269                    _ => {},
270                }
271            }
272
273            /// Return true if all present extensions are named in `allowed`
274            #[allow(dead_code)]
275            pub(crate) fn only_contains(&self, allowed: &[ExtensionType]) -> bool {
276                $(
277                    if let Some(_) = &self.$item_slot {
278                        if !allowed.contains(&$item_id) {
279                            return false;
280                        }
281                    }
282                )*
283
284                true
285            }
286
287            /// Return true if any extension named in `exts` is present.
288            #[allow(dead_code)]
289            pub(crate) fn contains_any(&self, exts: &[ExtensionType]) -> bool {
290                for e in exts {
291                    if self.contains(*e) {
292                        return true;
293                    }
294                }
295                false
296            }
297
298            fn contains(&self, e: ExtensionType) -> bool {
299                match e {
300                    $(
301
302                        $item_id => self.$item_slot.is_some(),
303                    )*
304                    _ => false,
305                }
306            }
307
308            /// Every `ExtensionType` this structure may encode/decode.
309            const ALL_EXTENSIONS: &'static [ExtensionType] = &[
310                $($item_id,)*
311            ];
312        }
313
314        impl<'a> core::fmt::Debug for $struct_name$(<$struct_lt>)*  {
315            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
316                let mut ds = f.debug_struct(stringify!($struct_name));
317                $(
318                    if let Some(ext) = &self.$item_slot {
319                        ds.field(stringify!($item_slot), ext);
320                    }
321                )*
322                $($(
323                    ds.field(stringify!($meta_slot), &self.$meta_slot);
324                )+)*
325                ds.finish_non_exhaustive()
326            }
327        }
328    }
329}