1macro_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 #[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 #[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 #[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
103macro_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 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 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 _ => {
189 r.rest();
190 return Ok(false);
191 }
192 }
193
194 Ok(true)
195 }
196
197 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 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 #[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 #[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 #[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 #[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 #[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 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}