1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Rust compiler backend.
16 
17 use crate::{analyzer, ast};
18 use quote::{format_ident, quote};
19 use std::collections::BTreeSet;
20 use std::collections::HashMap;
21 use std::path::Path;
22 use syn::LitInt;
23 
24 mod parser;
25 mod preamble;
26 mod serializer;
27 pub mod test;
28 mod types;
29 
30 use parser::FieldParser;
31 use serializer::FieldSerializer;
32 
33 pub use heck::ToUpperCamelCase;
34 
35 pub trait ToIdent {
36     /// Generate a sanitized rust identifier.
37     /// Rust specific keywords are renamed for validity.
to_ident(self) -> proc_macro2::Ident38     fn to_ident(self) -> proc_macro2::Ident;
39 }
40 
41 impl ToIdent for &'_ str {
to_ident(self) -> proc_macro2::Ident42     fn to_ident(self) -> proc_macro2::Ident {
43         match self {
44             "as" | "break" | "const" | "continue" | "crate" | "else" | "enum" | "extern"
45             | "false" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod"
46             | "move" | "mut" | "pub" | "ref" | "return" | "self" | "Self" | "static" | "struct"
47             | "super" | "trait" | "true" | "type" | "unsafe" | "use" | "where" | "while"
48             | "async" | "await" | "dyn" | "abstract" | "become" | "box" | "do" | "final"
49             | "macro" | "override" | "priv" | "typeof" | "unsized" | "virtual" | "yield"
50             | "try" => format_ident!("r#{}", self),
51             _ => format_ident!("{}", self),
52         }
53     }
54 }
55 
56 /// Generate a bit-mask which masks out `n` least significant bits.
57 ///
58 /// Literal integers in Rust default to the `i32` type. For this
59 /// reason, if `n` is larger than 31, a suffix is added to the
60 /// `LitInt` returned. This should either be `u64` or `usize`
61 /// depending on where the result is used.
mask_bits(n: usize, suffix: &str) -> syn::LitInt62 pub fn mask_bits(n: usize, suffix: &str) -> syn::LitInt {
63     let suffix = if n > 31 { format!("_{suffix}") } else { String::new() };
64     // Format the hex digits as 0x1111_2222_3333_usize.
65     let hex_digits = format!("{:x}", (1u64 << n) - 1)
66         .as_bytes()
67         .rchunks(4)
68         .rev()
69         .map(|chunk| std::str::from_utf8(chunk).unwrap())
70         .collect::<Vec<&str>>()
71         .join("_");
72     syn::parse_str::<syn::LitInt>(&format!("0x{hex_digits}{suffix}")).unwrap()
73 }
74 
generate_packet_size_getter<'a>( scope: &analyzer::Scope<'a>, schema: &analyzer::Schema, fields: impl Iterator<Item = &'a ast::Field>, is_packet: bool, ) -> (usize, proc_macro2::TokenStream)75 fn generate_packet_size_getter<'a>(
76     scope: &analyzer::Scope<'a>,
77     schema: &analyzer::Schema,
78     fields: impl Iterator<Item = &'a ast::Field>,
79     is_packet: bool,
80 ) -> (usize, proc_macro2::TokenStream) {
81     let mut constant_width = 0;
82     let mut dynamic_widths = Vec::new();
83 
84     for field in fields {
85         if let Some(width) =
86             schema.padded_size(field.key).or(schema.field_size(field.key).static_())
87         {
88             constant_width += width;
89             continue;
90         }
91 
92         let decl = scope.get_type_declaration(field);
93         dynamic_widths.push(match &field.desc {
94             ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body { .. } => {
95                 if is_packet {
96                     quote! {
97                         self.child.get_total_size()
98                     }
99                 } else {
100                     quote! {
101                         self.payload.len()
102                     }
103                 }
104             }
105             ast::FieldDesc::Scalar { id, width } => {
106                 assert!(field.cond.is_some());
107                 let id = id.to_ident();
108                 let width = syn::Index::from(*width / 8);
109                 quote!(if self.#id.is_some() { #width } else { 0 })
110             }
111             ast::FieldDesc::Typedef { id, type_id, .. } if field.cond.is_some() => {
112                 let id = id.to_ident();
113                 match &scope.typedef[type_id].desc {
114                     ast::DeclDesc::Enum { width, .. } => {
115                         let width = syn::Index::from(*width / 8);
116                         quote!(if self.#id.is_some() { #width } else { 0 })
117                     }
118                     _ => {
119                         let type_id = type_id.to_ident();
120                         quote! {
121                             self.#id
122                                 .as_ref()
123                                 .map(#type_id::get_size)
124                                 .unwrap_or(0)
125                         }
126                     }
127                 }
128             }
129             ast::FieldDesc::Typedef { id, .. } => {
130                 let id = id.to_ident();
131                 quote!(self.#id.get_size())
132             }
133             ast::FieldDesc::Array { id, width, .. } => {
134                 let id = id.to_ident();
135                 match &decl {
136                     Some(ast::Decl {
137                         desc: ast::DeclDesc::Struct { .. } | ast::DeclDesc::CustomField { .. },
138                         ..
139                     }) => {
140                         quote! {
141                             self.#id.iter().map(|elem| elem.get_size()).sum::<usize>()
142                         }
143                     }
144                     Some(ast::Decl { desc: ast::DeclDesc::Enum { width, .. }, .. }) => {
145                         let width = syn::Index::from(width / 8);
146                         let mul_width = (width.index > 1).then(|| quote!(* #width));
147                         quote! {
148                             self.#id.len() #mul_width
149                         }
150                     }
151                     _ => {
152                         let width = syn::Index::from(width.unwrap() / 8);
153                         let mul_width = (width.index > 1).then(|| quote!(* #width));
154                         quote! {
155                             self.#id.len() #mul_width
156                         }
157                     }
158                 }
159             }
160             _ => panic!("Unsupported field type: {field:?}"),
161         });
162     }
163 
164     if constant_width > 0 {
165         let width = syn::Index::from(constant_width / 8);
166         dynamic_widths.insert(0, quote!(#width));
167     }
168     if dynamic_widths.is_empty() {
169         dynamic_widths.push(quote!(0))
170     }
171 
172     (
173         constant_width,
174         quote! {
175             #(#dynamic_widths)+*
176         },
177     )
178 }
179 
top_level_packet<'a>(scope: &analyzer::Scope<'a>, packet_name: &'a str) -> &'a ast::Decl180 fn top_level_packet<'a>(scope: &analyzer::Scope<'a>, packet_name: &'a str) -> &'a ast::Decl {
181     let mut decl = scope.typedef[packet_name];
182     while let ast::DeclDesc::Packet { parent_id: Some(parent_id), .. }
183     | ast::DeclDesc::Struct { parent_id: Some(parent_id), .. } = &decl.desc
184     {
185         decl = scope.typedef[parent_id];
186     }
187     decl
188 }
189 
190 /// Find parent fields which are constrained in child packets.
191 ///
192 /// These fields are the fields which need to be passed in when
193 /// parsing a `id` packet since their values are needed for one or
194 /// more child packets.
find_constrained_parent_fields<'a>( scope: &analyzer::Scope<'a>, id: &str, ) -> Vec<&'a ast::Field>195 fn find_constrained_parent_fields<'a>(
196     scope: &analyzer::Scope<'a>,
197     id: &str,
198 ) -> Vec<&'a ast::Field> {
199     let all_parent_fields: HashMap<String, &'a ast::Field> = HashMap::from_iter(
200         scope
201             .iter_parent_fields(scope.typedef[id])
202             .filter_map(|f| f.id().map(|id| (id.to_string(), f))),
203     );
204 
205     let mut fields = Vec::new();
206     let mut field_names = BTreeSet::new();
207     let mut children = scope.iter_children(scope.typedef[id]).collect::<Vec<_>>();
208 
209     while let Some(child) = children.pop() {
210         if let ast::DeclDesc::Packet { id, constraints, .. }
211         | ast::DeclDesc::Struct { id, constraints, .. } = &child.desc
212         {
213             for constraint in constraints {
214                 if field_names.insert(&constraint.id)
215                     && all_parent_fields.contains_key(&constraint.id)
216                 {
217                     fields.push(all_parent_fields[&constraint.id]);
218                 }
219             }
220             children.extend(scope.iter_children(scope.typedef[id]).collect::<Vec<_>>());
221         }
222     }
223 
224     fields
225 }
226 
227 /// Generate the declaration and implementation for a data struct.
228 ///
229 /// This struct will hold the data for a packet or a struct. It knows
230 /// how to parse and serialize its own fields.
generate_data_struct( scope: &analyzer::Scope<'_>, schema: &analyzer::Schema, endianness: ast::EndiannessValue, id: &str, ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream)231 fn generate_data_struct(
232     scope: &analyzer::Scope<'_>,
233     schema: &analyzer::Schema,
234     endianness: ast::EndiannessValue,
235     id: &str,
236 ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
237     let decl = scope.typedef[id];
238     let is_packet = matches!(&decl.desc, ast::DeclDesc::Packet { .. });
239 
240     let span = format_ident!("bytes");
241     let serializer_span = format_ident!("buffer");
242     let mut field_parser = FieldParser::new(scope, schema, endianness, id, &span);
243     let mut field_serializer =
244         FieldSerializer::new(scope, schema, endianness, id, &serializer_span);
245     for field in decl.fields() {
246         field_parser.add(field);
247         field_serializer.add(field);
248     }
249     field_parser.done();
250 
251     let (parse_arg_names, parse_arg_types) = if is_packet {
252         let fields = find_constrained_parent_fields(scope, id);
253         let names = fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>();
254         let types = fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
255         (names, types)
256     } else {
257         (Vec::new(), Vec::new()) // No extra arguments to parse in structs.
258     };
259 
260     let (constant_width, packet_size) =
261         generate_packet_size_getter(scope, schema, decl.fields(), is_packet);
262     let conforms = if constant_width == 0 {
263         quote! { true }
264     } else {
265         let constant_width = syn::Index::from(constant_width / 8);
266         quote! { #span.len() >= #constant_width }
267     };
268 
269     let visibility = if is_packet { quote!() } else { quote!(pub) };
270     let has_payload = decl.payload().is_some();
271     let has_children = scope.iter_children(decl).next().is_some();
272 
273     let struct_name = if is_packet { format_ident!("{id}Data") } else { id.to_ident() };
274     let backed_fields = decl
275         .fields()
276         .filter(|f| f.id().is_some() && !matches!(&f.desc, ast::FieldDesc::Flag { .. }))
277         .collect::<Vec<_>>();
278 
279     let mut field_names =
280         backed_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>();
281     let mut field_types = backed_fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
282 
283     if has_children || has_payload {
284         if is_packet {
285             field_names.push(format_ident!("child"));
286             let field_type = format_ident!("{id}DataChild");
287             field_types.push(quote!(#field_type));
288         } else {
289             field_names.push(format_ident!("payload"));
290             field_types.push(quote!(Vec<u8>));
291         }
292     }
293 
294     let data_struct_decl = quote! {
295         #[derive(Debug, Clone, PartialEq, Eq)]
296         #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
297         pub struct #struct_name {
298             #(#visibility #field_names: #field_types,)*
299         }
300     };
301 
302     let data_struct_impl = quote! {
303         impl #struct_name {
304             fn conforms(#span: &[u8]) -> bool {
305                 #conforms
306             }
307 
308             #visibility fn parse(
309                 #span: &[u8] #(, #parse_arg_names: #parse_arg_types)*
310             ) -> Result<Self, DecodeError> {
311                 let mut cell = Cell::new(#span);
312                 let packet = Self::parse_inner(&mut cell #(, #parse_arg_names)*)?;
313                 // TODO(mgeisler): communicate back to user if !cell.get().is_empty()?
314                 Ok(packet)
315             }
316 
317             fn parse_inner(
318                 mut #span: &mut Cell<&[u8]> #(, #parse_arg_names: #parse_arg_types)*
319             ) -> Result<Self, DecodeError> {
320                 #field_parser
321                 Ok(Self {
322                     #(#field_names,)*
323                 })
324             }
325 
326             fn write_to<T: BufMut>(&self, buffer: &mut T) -> Result<(), EncodeError> {
327                 #field_serializer
328                 Ok(())
329             }
330 
331             fn get_total_size(&self) -> usize {
332                 self.get_size()
333             }
334 
335             fn get_size(&self) -> usize {
336                 #packet_size
337             }
338         }
339     };
340 
341     (data_struct_decl, data_struct_impl)
342 }
343 
344 /// Turn the constraint into a value (such as `10` or
345 /// `SomeEnum::Foo`).
constraint_to_value( all_fields: &HashMap<String, &'_ ast::Field>, constraint: &ast::Constraint, ) -> proc_macro2::TokenStream346 pub fn constraint_to_value(
347     all_fields: &HashMap<String, &'_ ast::Field>,
348     constraint: &ast::Constraint,
349 ) -> proc_macro2::TokenStream {
350     match constraint {
351         ast::Constraint { value: Some(value), .. } => {
352             let value = proc_macro2::Literal::usize_unsuffixed(*value);
353             quote!(#value)
354         }
355         // TODO(mgeisler): include type_id in `ast::Constraint` and
356         // drop the packet_scope argument.
357         ast::Constraint { tag_id: Some(tag_id), .. } => {
358             let type_id = match &all_fields[&constraint.id].desc {
359                 ast::FieldDesc::Typedef { type_id, .. } => type_id.to_ident(),
360                 _ => unreachable!("Invalid constraint: {constraint:?}"),
361             };
362             let tag_id = format_ident!("{}", tag_id.to_upper_camel_case());
363             quote!(#type_id::#tag_id)
364         }
365         _ => unreachable!("Invalid constraint: {constraint:?}"),
366     }
367 }
368 
369 /// Generate code for a `ast::Decl::Packet`.
generate_packet_decl( scope: &analyzer::Scope<'_>, schema: &analyzer::Schema, endianness: ast::EndiannessValue, id: &str, ) -> proc_macro2::TokenStream370 fn generate_packet_decl(
371     scope: &analyzer::Scope<'_>,
372     schema: &analyzer::Schema,
373     endianness: ast::EndiannessValue,
374     id: &str,
375 ) -> proc_macro2::TokenStream {
376     let decl = scope.typedef[id];
377     let top_level = top_level_packet(scope, id);
378     let top_level_id = top_level.id().unwrap();
379     let top_level_packet = top_level_id.to_ident();
380     let top_level_data = format_ident!("{top_level_id}Data");
381     let top_level_id_lower = top_level_id.to_lowercase().to_ident();
382 
383     // TODO(mgeisler): use the convert_case crate to convert between
384     // `FooBar` and `foo_bar` in the code below.
385     let span = format_ident!("bytes");
386     let id_lower = id.to_lowercase().to_ident();
387     let id_packet = id.to_ident();
388     let id_child = format_ident!("{id}Child");
389     let id_data_child = format_ident!("{id}DataChild");
390     let id_builder = format_ident!("{id}Builder");
391 
392     let mut parents = scope.iter_parents_and_self(decl).collect::<Vec<_>>();
393     parents.reverse();
394 
395     let parent_ids = parents.iter().map(|p| p.id().unwrap()).collect::<Vec<_>>();
396     let parent_shifted_ids = parent_ids.iter().skip(1).map(|id| id.to_ident());
397     let parent_lower_ids =
398         parent_ids.iter().map(|id| id.to_lowercase().to_ident()).collect::<Vec<_>>();
399     let parent_shifted_lower_ids = parent_lower_ids.iter().skip(1).collect::<Vec<_>>();
400     let parent_packet = parent_ids.iter().map(|id| id.to_ident());
401     let parent_data = parent_ids.iter().map(|id| format_ident!("{id}Data"));
402     let parent_data_child = parent_ids.iter().map(|id| format_ident!("{id}DataChild"));
403 
404     let all_fields = {
405         let mut fields = scope
406             .iter_fields(decl)
407             .filter(|f| f.id().is_some() && !matches!(&f.desc, ast::FieldDesc::Flag { .. }))
408             .collect::<Vec<_>>();
409         fields.sort_by_key(|f| f.id());
410         fields
411     };
412     let all_named_fields =
413         HashMap::from_iter(all_fields.iter().map(|f| (f.id().unwrap().to_string(), *f)));
414 
415     let all_field_names = all_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>();
416     let all_field_types = all_fields.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>();
417     let all_field_borrows =
418         all_fields.iter().map(|f| types::rust_borrow(f, scope)).collect::<Vec<_>>();
419     let all_field_getter_names =
420         all_fields.iter().map(|f| format_ident!("get_{}", f.id().unwrap()));
421     let all_field_self_field = all_fields.iter().map(|f| {
422         for (parent, parent_id) in parents.iter().zip(parent_lower_ids.iter()) {
423             if parent.fields().any(|ff| ff.id() == f.id()) {
424                 return quote!(self.#parent_id);
425             }
426         }
427         unreachable!("Could not find {f:?} in parent chain");
428     });
429 
430     let all_constraints = HashMap::<String, _>::from_iter(
431         scope.iter_constraints(decl).map(|c| (c.id.to_string(), c)),
432     );
433 
434     let unconstrained_fields = all_fields
435         .iter()
436         .filter(|f| !all_constraints.contains_key(f.id().unwrap()))
437         .collect::<Vec<_>>();
438     let unconstrained_field_names =
439         unconstrained_fields.iter().map(|f| f.id().unwrap().to_ident()).collect::<Vec<_>>();
440     let unconstrained_field_types = unconstrained_fields.iter().map(|f| types::rust_type(f));
441 
442     let rev_parents = parents.iter().rev().collect::<Vec<_>>();
443     let builder_assignments = rev_parents.iter().enumerate().map(|(idx, parent)| {
444         let parent_id = parent.id().unwrap();
445         let parent_id_lower = parent_id.to_lowercase().to_ident();
446         let parent_data = format_ident!("{parent_id}Data");
447         let parent_data_child = format_ident!("{parent_id}DataChild");
448 
449         let named_fields = {
450             let mut names = parent
451                 .fields()
452                 .filter(|f| !matches!(&f.desc, ast::FieldDesc::Flag { .. }))
453                 .filter_map(ast::Field::id)
454                 .collect::<Vec<_>>();
455             names.sort_unstable();
456             names
457         };
458 
459         let mut field = named_fields.iter().map(|id| id.to_ident()).collect::<Vec<_>>();
460         let mut value = named_fields
461             .iter()
462             .map(|&id| match all_constraints.get(id) {
463                 Some(constraint) => constraint_to_value(&all_named_fields, constraint),
464                 None => {
465                     let id = id.to_ident();
466                     quote!(self.#id)
467                 }
468             })
469             .collect::<Vec<_>>();
470 
471         if parent.payload().is_some() {
472             field.push(format_ident!("child"));
473             if idx == 0 {
474                 // Top-most parent, the child is simply created from
475                 // our payload.
476                 value.push(quote! {
477                     match self.payload {
478                         None => #parent_data_child::None,
479                         Some(bytes) => #parent_data_child::Payload(bytes),
480                     }
481                 });
482             } else {
483                 // Child is created from the previous parent.
484                 let prev_parent_id = rev_parents[idx - 1].id().unwrap();
485                 let prev_parent_id_lower = prev_parent_id.to_lowercase().to_ident();
486                 let prev_parent_id = prev_parent_id.to_ident();
487                 value.push(quote! {
488                     #parent_data_child::#prev_parent_id(#prev_parent_id_lower)
489                 });
490             }
491         } else if scope.iter_children(parent).next().is_some() {
492             field.push(format_ident!("child"));
493             value.push(quote! { #parent_data_child::None });
494         }
495 
496         quote! {
497             let #parent_id_lower = #parent_data {
498                 #(#field: #value,)*
499             };
500         }
501     });
502 
503     let children = scope.iter_children(decl).collect::<Vec<_>>();
504     let has_payload = decl.payload().is_some();
505     let has_children_or_payload = !children.is_empty() || has_payload;
506     let child = children.iter().map(|child| child.id().unwrap().to_ident()).collect::<Vec<_>>();
507     let child_data = child.iter().map(|child| format_ident!("{child}Data")).collect::<Vec<_>>();
508     let get_payload = (children.is_empty() && has_payload).then(|| {
509         quote! {
510             pub fn get_payload(&self) -> &[u8] {
511                 match &self.#id_lower.child {
512                     #id_data_child::Payload(bytes) => &bytes,
513                     #id_data_child::None => &[],
514                 }
515             }
516         }
517     });
518     let child_declaration = has_children_or_payload.then(|| {
519         quote! {
520             #[derive(Debug, Clone, PartialEq, Eq)]
521             #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
522             pub enum #id_data_child {
523                 #(#child(#child_data),)*
524                 Payload(Bytes),
525                 None,
526             }
527 
528             impl #id_data_child {
529                 fn get_total_size(&self) -> usize {
530                     match self {
531                         #(#id_data_child::#child(value) => value.get_total_size(),)*
532                         #id_data_child::Payload(bytes) => bytes.len(),
533                         #id_data_child::None => 0,
534                     }
535                 }
536             }
537 
538             #[derive(Debug, Clone, PartialEq, Eq)]
539             #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
540             pub enum #id_child {
541                 #(#child(#child),)*
542                 Payload(Bytes),
543                 None,
544             }
545         }
546     });
547     let specialize = has_children_or_payload.then(|| {
548         quote! {
549             pub fn specialize(&self) -> #id_child {
550                 match &self.#id_lower.child {
551                     #(
552                         #id_data_child::#child(_) =>
553                         #id_child::#child(#child::new(self.#top_level_id_lower.clone()).unwrap()),
554                     )*
555                     #id_data_child::Payload(payload) => #id_child::Payload(payload.clone()),
556                     #id_data_child::None => #id_child::None,
557                 }
558             }
559         }
560     });
561 
562     let builder_payload_field = has_children_or_payload.then(|| {
563         quote! {
564             pub payload: Option<Bytes>
565         }
566     });
567 
568     let ancestor_packets = parent_ids[..parent_ids.len() - 1].iter().map(|id| id.to_ident());
569     let impl_from_and_try_from = (top_level_id != id).then(|| {
570         quote! {
571             #(
572                 impl From<#id_packet> for #ancestor_packets {
573                     fn from(packet: #id_packet) -> #ancestor_packets {
574                         #ancestor_packets::new(packet.#top_level_id_lower).unwrap()
575                     }
576                 }
577             )*
578 
579             impl TryFrom<#top_level_packet> for #id_packet {
580                 type Error = DecodeError;
581                 fn try_from(packet: #top_level_packet) -> Result<#id_packet, Self::Error> {
582                     #id_packet::new(packet.#top_level_id_lower)
583                 }
584             }
585         }
586     });
587 
588     let (data_struct_decl, data_struct_impl) = generate_data_struct(scope, schema, endianness, id);
589 
590     quote! {
591         #child_declaration
592 
593         #data_struct_decl
594 
595         #[derive(Debug, Clone, PartialEq, Eq)]
596         #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
597         pub struct #id_packet {
598             #(
599                 #[cfg_attr(feature = "serde", serde(flatten))]
600                 #parent_lower_ids: #parent_data,
601             )*
602         }
603 
604         #[derive(Debug)]
605         #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
606         pub struct #id_builder {
607             #(pub #unconstrained_field_names: #unconstrained_field_types,)*
608             #builder_payload_field
609         }
610 
611         #data_struct_impl
612 
613         impl Packet for #id_packet {
614             fn encoded_len(&self) -> usize {
615                 self.get_size()
616             }
617             fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError> {
618                 self.#top_level_id_lower.write_to(buf)
619             }
620             fn decode(_: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
621                 unimplemented!("Rust legacy does not implement full packet trait")
622             }
623         }
624 
625         impl TryFrom<#id_packet> for Bytes {
626             type Error = EncodeError;
627             fn try_from(packet: #id_packet) -> Result<Self, Self::Error> {
628                 packet.encode_to_bytes()
629             }
630         }
631 
632         impl TryFrom<#id_packet> for Vec<u8> {
633             type Error = EncodeError;
634             fn try_from(packet: #id_packet) -> Result<Self, Self::Error> {
635                 packet.encode_to_vec()
636             }
637         }
638 
639         #impl_from_and_try_from
640 
641         impl #id_packet {
642             pub fn parse(#span: &[u8]) -> Result<Self, DecodeError> {
643                 let mut cell = Cell::new(#span);
644                 let packet = Self::parse_inner(&mut cell)?;
645                 // TODO(mgeisler): communicate back to user if !cell.get().is_empty()?
646                 Ok(packet)
647             }
648 
649             fn parse_inner(mut bytes: &mut Cell<&[u8]>) -> Result<Self, DecodeError> {
650                 let data = #top_level_data::parse_inner(&mut bytes)?;
651                 Self::new(data)
652             }
653 
654             #specialize
655 
656             fn new(#top_level_id_lower: #top_level_data) -> Result<Self, DecodeError> {
657                 #(
658                     let #parent_shifted_lower_ids = match &#parent_lower_ids.child {
659                         #parent_data_child::#parent_shifted_ids(value) => value.clone(),
660                         _ => return Err(DecodeError::InvalidChildError {
661                             expected: stringify!(#parent_data_child::#parent_shifted_ids),
662                             actual: format!("{:?}", &#parent_lower_ids.child),
663                         }),
664                     };
665                 )*
666                 Ok(Self { #(#parent_lower_ids),* })
667             }
668 
669             #(pub fn #all_field_getter_names(&self) -> #all_field_borrows #all_field_types {
670                 #all_field_borrows #all_field_self_field.#all_field_names
671             })*
672 
673             #get_payload
674 
675             fn write_to(&self, buffer: &mut impl BufMut) -> Result<(), EncodeError> {
676                 self.#id_lower.write_to(buffer)
677             }
678 
679             pub fn get_size(&self) -> usize {
680                 self.#top_level_id_lower.get_size()
681             }
682         }
683 
684         impl #id_builder {
685             pub fn build(self) -> #id_packet {
686                 #(#builder_assignments;)*
687                 #id_packet::new(#top_level_id_lower).unwrap()
688             }
689         }
690 
691         #(
692             impl From<#id_builder> for #parent_packet {
693                 fn from(builder: #id_builder) -> #parent_packet {
694                     builder.build().into()
695                 }
696             }
697         )*
698     }
699 }
700 
701 /// Generate code for a `ast::Decl::Struct`.
generate_struct_decl( scope: &analyzer::Scope<'_>, schema: &analyzer::Schema, endianness: ast::EndiannessValue, id: &str, ) -> proc_macro2::TokenStream702 fn generate_struct_decl(
703     scope: &analyzer::Scope<'_>,
704     schema: &analyzer::Schema,
705     endianness: ast::EndiannessValue,
706     id: &str,
707 ) -> proc_macro2::TokenStream {
708     let (struct_decl, struct_impl) = generate_data_struct(scope, schema, endianness, id);
709     quote! {
710         #struct_decl
711         #struct_impl
712     }
713 }
714 
715 /// Generate an enum declaration.
716 ///
717 /// # Arguments
718 /// * `id` - Enum identifier.
719 /// * `tags` - List of enum tags.
720 /// * `width` - Width of the backing type of the enum, in bits.
721 /// * `open` - Whether to generate an open or closed enum. Open enums have
722 ///            an additional Unknown case for unmatched valued. Complete
723 ///            enums (where the full range of values is covered) are
724 ///            automatically closed.
generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2::TokenStream725 fn generate_enum_decl(id: &str, tags: &[ast::Tag], width: usize) -> proc_macro2::TokenStream {
726     // Determine if the enum is open, i.e. a default tag is defined.
727     fn enum_default_tag(tags: &[ast::Tag]) -> Option<ast::TagOther> {
728         tags.iter()
729             .filter_map(|tag| match tag {
730                 ast::Tag::Other(tag) => Some(tag.clone()),
731                 _ => None,
732             })
733             .next()
734     }
735 
736     // Determine if the enum is complete, i.e. all values in the backing
737     // integer range have a matching tag in the original declaration.
738     fn enum_is_complete(tags: &[ast::Tag], max: usize) -> bool {
739         let mut ranges = tags
740             .iter()
741             .filter_map(|tag| match tag {
742                 ast::Tag::Value(tag) => Some((tag.value, tag.value)),
743                 ast::Tag::Range(tag) => Some(tag.range.clone().into_inner()),
744                 _ => None,
745             })
746             .collect::<Vec<_>>();
747         ranges.sort_unstable();
748         ranges.first().unwrap().0 == 0
749             && ranges.last().unwrap().1 == max
750             && ranges.windows(2).all(|window| {
751                 if let [left, right] = window {
752                     left.1 == right.0 - 1
753                 } else {
754                     false
755                 }
756             })
757     }
758 
759     // Determine if the enum is primitive, i.e. does not contain any tag range.
760     fn enum_is_primitive(tags: &[ast::Tag]) -> bool {
761         tags.iter().all(|tag| matches!(tag, ast::Tag::Value(_)))
762     }
763 
764     // Return the maximum value for the scalar type.
765     fn scalar_max(width: usize) -> usize {
766         if width >= usize::BITS as usize {
767             usize::MAX
768         } else {
769             (1 << width) - 1
770         }
771     }
772 
773     // Format an enum tag identifier to rust upper caml case.
774     fn format_tag_ident(id: &str) -> proc_macro2::TokenStream {
775         let id = format_ident!("{}", id.to_upper_camel_case());
776         quote! { #id }
777     }
778 
779     // Format a constant value as hexadecimal constant.
780     fn format_value(value: usize) -> LitInt {
781         syn::parse_str::<syn::LitInt>(&format!("{:#x}", value)).unwrap()
782     }
783 
784     // Backing type for the enum.
785     let backing_type = types::Integer::new(width);
786     let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width));
787     let range_max = scalar_max(width);
788     let default_tag = enum_default_tag(tags);
789     let is_open = default_tag.is_some();
790     let is_complete = enum_is_complete(tags, scalar_max(width));
791     let is_primitive = enum_is_primitive(tags);
792     let name = id.to_ident();
793 
794     // Generate the variant cases for the enum declaration.
795     // Tags declared in ranges are flattened in the same declaration.
796     let use_variant_values = is_primitive && (is_complete || !is_open);
797     let repr_u64 = use_variant_values.then(|| quote! { #[repr(u64)] });
798     let mut variants = vec![];
799     for tag in tags.iter() {
800         match tag {
801             ast::Tag::Value(tag) if use_variant_values => {
802                 let id = format_tag_ident(&tag.id);
803                 let value = format_value(tag.value);
804                 variants.push(quote! { #id = #value })
805             }
806             ast::Tag::Value(tag) => variants.push(format_tag_ident(&tag.id)),
807             ast::Tag::Range(tag) => {
808                 variants.extend(tag.tags.iter().map(|tag| format_tag_ident(&tag.id)));
809                 let id = format_tag_ident(&tag.id);
810                 variants.push(quote! { #id(Private<#backing_type>) })
811             }
812             ast::Tag::Other(_) => (),
813         }
814     }
815 
816     // Generate the cases for parsing the enum value from an integer.
817     let mut from_cases = vec![];
818     for tag in tags.iter() {
819         match tag {
820             ast::Tag::Value(tag) => {
821                 let id = format_tag_ident(&tag.id);
822                 let value = format_value(tag.value);
823                 from_cases.push(quote! { #value => Ok(#name::#id) })
824             }
825             ast::Tag::Range(tag) => {
826                 from_cases.extend(tag.tags.iter().map(|tag| {
827                     let id = format_tag_ident(&tag.id);
828                     let value = format_value(tag.value);
829                     quote! { #value => Ok(#name::#id) }
830                 }));
831                 let id = format_tag_ident(&tag.id);
832                 let start = format_value(*tag.range.start());
833                 let end = format_value(*tag.range.end());
834                 from_cases.push(quote! { #start ..= #end => Ok(#name::#id(Private(value))) })
835             }
836             ast::Tag::Other(_) => (),
837         }
838     }
839 
840     // Generate the cases for serializing the enum value to an integer.
841     let mut into_cases = vec![];
842     for tag in tags.iter() {
843         match tag {
844             ast::Tag::Value(tag) => {
845                 let id = format_tag_ident(&tag.id);
846                 let value = format_value(tag.value);
847                 into_cases.push(quote! { #name::#id => #value })
848             }
849             ast::Tag::Range(tag) => {
850                 into_cases.extend(tag.tags.iter().map(|tag| {
851                     let id = format_tag_ident(&tag.id);
852                     let value = format_value(tag.value);
853                     quote! { #name::#id => #value }
854                 }));
855                 let id = format_tag_ident(&tag.id);
856                 into_cases.push(quote! { #name::#id(Private(value)) => *value })
857             }
858             ast::Tag::Other(_) => (),
859         }
860     }
861 
862     // Generate a default case if the enum is open and incomplete.
863     if !is_complete && is_open {
864         let unknown_id = format_tag_ident(&default_tag.unwrap().id);
865         let range_max = format_value(range_max);
866         variants.push(quote! { #unknown_id(Private<#backing_type>) });
867         from_cases.push(quote! { 0..=#range_max => Ok(#name::#unknown_id(Private(value))) });
868         into_cases.push(quote! { #name::#unknown_id(Private(value)) => *value });
869     }
870 
871     // Generate an error case if the enum size is lower than the backing
872     // type size, or if the enum is closed or incomplete.
873     if backing_type.width != width || (!is_complete && !is_open) {
874         from_cases.push(quote! { _ => Err(value) });
875     }
876 
877     // Derive other Into<uN> and Into<iN> implementations from the explicit
878     // implementation, where the type is larger than the backing type.
879     let derived_signed_into_types = [8, 16, 32, 64]
880         .into_iter()
881         .filter(|w| *w > width)
882         .map(|w| syn::parse_str::<syn::Type>(&format!("i{}", w)).unwrap());
883     let derived_unsigned_into_types = [8, 16, 32, 64]
884         .into_iter()
885         .filter(|w| *w >= width && *w != backing_type.width)
886         .map(|w| syn::parse_str::<syn::Type>(&format!("u{}", w)).unwrap());
887     let derived_into_types = derived_signed_into_types.chain(derived_unsigned_into_types);
888 
889     quote! {
890         #repr_u64
891         #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
892         #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
893         #[cfg_attr(feature = "serde", serde(try_from = #backing_type_str, into = #backing_type_str))]
894         pub enum #name {
895             #(#variants,)*
896         }
897 
898         impl TryFrom<#backing_type> for #name {
899             type Error = #backing_type;
900             fn try_from(value: #backing_type) -> Result<Self, Self::Error> {
901                 match value {
902                     #(#from_cases,)*
903                 }
904             }
905         }
906 
907         impl From<&#name> for #backing_type {
908             fn from(value: &#name) -> Self {
909                 match value {
910                     #(#into_cases,)*
911                 }
912             }
913         }
914 
915         impl From<#name> for #backing_type {
916             fn from(value: #name) -> Self {
917                 (&value).into()
918             }
919         }
920 
921         #(impl From<#name> for #derived_into_types {
922             fn from(value: #name) -> Self {
923                 #backing_type::from(value) as Self
924             }
925         })*
926     }
927 }
928 
929 /// Generate the declaration for a custom field of static size.
930 ///
931 /// * `id` - Enum identifier.
932 /// * `width` - Width of the backing type of the enum, in bits.
generate_custom_field_decl(id: &str, width: usize) -> proc_macro2::TokenStream933 fn generate_custom_field_decl(id: &str, width: usize) -> proc_macro2::TokenStream {
934     let id = id.to_ident();
935     let backing_type = types::Integer::new(width);
936     let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width));
937     let max_value = mask_bits(width, &format!("u{}", backing_type.width));
938     let common = quote! {
939         impl From<&#id> for #backing_type {
940             fn from(value: &#id) -> #backing_type {
941                 value.0
942             }
943         }
944 
945         impl From<#id> for #backing_type {
946             fn from(value: #id) -> #backing_type {
947                 value.0
948             }
949         }
950     };
951 
952     if backing_type.width == width {
953         quote! {
954             #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
955             #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
956             #[cfg_attr(feature = "serde", serde(from = #backing_type_str, into = #backing_type_str))]
957             pub struct #id(#backing_type);
958 
959             #common
960 
961             impl From<#backing_type> for #id {
962                 fn from(value: #backing_type) -> Self {
963                     #id(value)
964                 }
965             }
966         }
967     } else {
968         quote! {
969             #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
970             #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
971             #[cfg_attr(feature = "serde", serde(try_from = #backing_type_str, into = #backing_type_str))]
972             pub struct #id(#backing_type);
973 
974             #common
975 
976             impl TryFrom<#backing_type> for #id {
977                 type Error = #backing_type;
978                 fn try_from(value: #backing_type) -> Result<Self, Self::Error> {
979                     if value > #max_value {
980                         Err(value)
981                     } else {
982                         Ok(#id(value))
983                     }
984                 }
985             }
986         }
987     }
988 }
989 
generate_decl( scope: &analyzer::Scope<'_>, schema: &analyzer::Schema, file: &ast::File, decl: &ast::Decl, ) -> proc_macro2::TokenStream990 fn generate_decl(
991     scope: &analyzer::Scope<'_>,
992     schema: &analyzer::Schema,
993     file: &ast::File,
994     decl: &ast::Decl,
995 ) -> proc_macro2::TokenStream {
996     match &decl.desc {
997         ast::DeclDesc::Packet { id, .. } => {
998             generate_packet_decl(scope, schema, file.endianness.value, id)
999         }
1000         ast::DeclDesc::Struct { id, parent_id: None, .. } => {
1001             // TODO(mgeisler): handle structs with parents. We could
1002             // generate code for them, but the code is not useful
1003             // since it would require the caller to unpack everything
1004             // manually. We either need to change the API, or
1005             // implement the recursive (de)serialization.
1006             generate_struct_decl(scope, schema, file.endianness.value, id)
1007         }
1008         ast::DeclDesc::Enum { id, tags, width } => generate_enum_decl(id, tags, *width),
1009         ast::DeclDesc::CustomField { id, width: Some(width), .. } => {
1010             generate_custom_field_decl(id, *width)
1011         }
1012         _ => todo!("unsupported Decl::{:?}", decl),
1013     }
1014 }
1015 
1016 /// Generate Rust code from an AST.
1017 ///
1018 /// The code is not formatted, pipe it through `rustfmt` to get
1019 /// readable source code.
generate_tokens( sources: &ast::SourceDatabase, file: &ast::File, ) -> proc_macro2::TokenStream1020 pub fn generate_tokens(
1021     sources: &ast::SourceDatabase,
1022     file: &ast::File,
1023 ) -> proc_macro2::TokenStream {
1024     let source = sources.get(file.file).expect("could not read source");
1025     let preamble = preamble::generate(Path::new(source.name()));
1026 
1027     let scope = analyzer::Scope::new(file).expect("could not create scope");
1028     let schema = analyzer::Schema::new(file);
1029     let decls = file.declarations.iter().map(|decl| generate_decl(&scope, &schema, file, decl));
1030     quote! {
1031         #preamble
1032 
1033         #(#decls)*
1034     }
1035 }
1036 
1037 /// Generate formatted Rust code from an AST.
1038 ///
1039 /// The code is not formatted, pipe it through `rustfmt` to get
1040 /// readable source code.
generate(sources: &ast::SourceDatabase, file: &ast::File) -> String1041 pub fn generate(sources: &ast::SourceDatabase, file: &ast::File) -> String {
1042     let syntax_tree = syn::parse2(generate_tokens(sources, file)).expect("Could not parse code");
1043     prettyplease::unparse(&syntax_tree)
1044 }
1045 
1046 #[cfg(test)]
1047 mod tests {
1048     use super::*;
1049     use crate::analyzer;
1050     use crate::ast;
1051     use crate::parser::parse_inline;
1052     use crate::test_utils::{assert_snapshot_eq, format_rust};
1053     use googletest::prelude::{elements_are, eq, expect_that};
1054     use paste::paste;
1055 
1056     /// Parse a string fragment as a PDL file.
1057     ///
1058     /// # Panics
1059     ///
1060     /// Panics on parse errors.
parse_str(text: &str) -> ast::File1061     pub fn parse_str(text: &str) -> ast::File {
1062         let mut db = ast::SourceDatabase::new();
1063         let file = parse_inline(&mut db, "stdin", String::from(text)).expect("parse error");
1064         analyzer::analyze(&file).expect("analyzer error")
1065     }
1066 
1067     #[googletest::test]
test_find_constrained_parent_fields() -> googletest::Result<()>1068     fn test_find_constrained_parent_fields() -> googletest::Result<()> {
1069         let code = "
1070               little_endian_packets
1071               packet Parent {
1072                 a: 8,
1073                 b: 8,
1074                 c: 8,
1075                 _payload_,
1076               }
1077               packet Child: Parent(a = 10) {
1078                 x: 8,
1079                 _payload_,
1080               }
1081               packet GrandChild: Child(b = 20) {
1082                 y: 8,
1083                 _payload_,
1084               }
1085               packet GrandGrandChild: GrandChild(c = 30) {
1086                 z: 8,
1087               }
1088             ";
1089         let file = parse_str(code);
1090         let scope = analyzer::Scope::new(&file).unwrap();
1091         let find_fields = |id| {
1092             find_constrained_parent_fields(&scope, id)
1093                 .iter()
1094                 .map(|field| field.id().unwrap())
1095                 .collect::<Vec<_>>()
1096         };
1097 
1098         expect_that!(find_fields("Parent"), elements_are![]);
1099         expect_that!(find_fields("Child"), elements_are![eq("b"), eq("c")]);
1100         expect_that!(find_fields("GrandChild"), elements_are![eq("c")]);
1101         expect_that!(find_fields("GrandGrandChild"), elements_are![]);
1102         Ok(())
1103     }
1104 
1105     /// Create a unit test for the given PDL `code`.
1106     ///
1107     /// The unit test will compare the generated Rust code for all
1108     /// declarations with previously saved snapshots. The snapshots
1109     /// are read from `"tests/generated/{name}_{endianness}_{id}.rs"`
1110     /// where `is` taken from the declaration.
1111     ///
1112     /// When adding new tests or modifying existing ones, use
1113     /// `UPDATE_SNAPSHOTS=1 cargo test` to automatically populate the
1114     /// snapshots with the expected output.
1115     ///
1116     /// The `code` cannot have an endianness declaration, instead you
1117     /// must supply either `little_endian` or `big_endian` as
1118     /// `endianness`.
1119     macro_rules! make_pdl_test {
1120         ($name:ident, $code:expr, $endianness:ident) => {
1121             paste! {
1122                 #[test]
1123                 fn [< test_ $name _ $endianness >]() {
1124                     let name = stringify!($name);
1125                     let endianness = stringify!($endianness);
1126                     let code = format!("{endianness}_packets\n{}", $code);
1127                     let mut db = ast::SourceDatabase::new();
1128                     let file = parse_inline(&mut db, "test", code).unwrap();
1129                     let file = analyzer::analyze(&file).unwrap();
1130                     let actual_code = generate(&db, &file);
1131                     assert_snapshot_eq(
1132                         &format!("tests/generated/rust_legacy/{name}_{endianness}.rs"),
1133                         &format_rust(&actual_code),
1134                     );
1135                 }
1136             }
1137         };
1138     }
1139 
1140     /// Create little- and bit-endian tests for the given PDL `code`.
1141     ///
1142     /// The `code` cannot have an endianness declaration: we will
1143     /// automatically generate unit tests for both
1144     /// "little_endian_packets" and "big_endian_packets".
1145     macro_rules! test_pdl {
1146         ($name:ident, $code:expr $(,)?) => {
1147             make_pdl_test!($name, $code, little_endian);
1148             make_pdl_test!($name, $code, big_endian);
1149         };
1150     }
1151 
1152     test_pdl!(packet_decl_empty, "packet Foo {}");
1153 
1154     test_pdl!(packet_decl_8bit_scalar, " packet Foo { x:  8 }");
1155     test_pdl!(packet_decl_24bit_scalar, "packet Foo { x: 24 }");
1156     test_pdl!(packet_decl_64bit_scalar, "packet Foo { x: 64 }");
1157 
1158     test_pdl!(
1159         enum_declaration,
1160         r#"
1161         enum IncompleteTruncatedClosed : 3 {
1162             A = 0,
1163             B = 1,
1164         }
1165 
1166         enum IncompleteTruncatedOpen : 3 {
1167             A = 0,
1168             B = 1,
1169             UNKNOWN = ..
1170         }
1171 
1172         enum IncompleteTruncatedClosedWithRange : 3 {
1173             A = 0,
1174             B = 1..6 {
1175                 X = 1,
1176                 Y = 2,
1177             }
1178         }
1179 
1180         enum IncompleteTruncatedOpenWithRange : 3 {
1181             A = 0,
1182             B = 1..6 {
1183                 X = 1,
1184                 Y = 2,
1185             },
1186             UNKNOWN = ..
1187         }
1188 
1189         enum CompleteTruncated : 3 {
1190             A = 0,
1191             B = 1,
1192             C = 2,
1193             D = 3,
1194             E = 4,
1195             F = 5,
1196             G = 6,
1197             H = 7,
1198         }
1199 
1200         enum CompleteTruncatedWithRange : 3 {
1201             A = 0,
1202             B = 1..7 {
1203                 X = 1,
1204                 Y = 2,
1205             }
1206         }
1207 
1208         enum CompleteWithRange : 8 {
1209             A = 0,
1210             B = 1,
1211             C = 2..255,
1212         }
1213         "#
1214     );
1215 
1216     test_pdl!(
1217         custom_field_declaration,
1218         r#"
1219         // Still unsupported.
1220         // custom_field Dynamic "dynamic"
1221 
1222         // Should generate a type with From<u32> implementation.
1223         custom_field ExactSize : 32 "exact_size"
1224 
1225         // Should generate a type with TryFrom<u32> implementation.
1226         custom_field TruncatedSize : 24 "truncated_size"
1227         "#
1228     );
1229 
1230     test_pdl!(
1231         packet_decl_simple_scalars,
1232         r#"
1233           packet Foo {
1234             x: 8,
1235             y: 16,
1236             z: 24,
1237           }
1238         "#
1239     );
1240 
1241     test_pdl!(
1242         packet_decl_complex_scalars,
1243         r#"
1244           packet Foo {
1245             a: 3,
1246             b: 8,
1247             c: 5,
1248             d: 24,
1249             e: 12,
1250             f: 4,
1251           }
1252         "#,
1253     );
1254 
1255     // Test that we correctly mask a byte-sized value in the middle of
1256     // a chunk.
1257     test_pdl!(
1258         packet_decl_mask_scalar_value,
1259         r#"
1260           packet Foo {
1261             a: 2,
1262             b: 24,
1263             c: 6,
1264           }
1265         "#,
1266     );
1267 
1268     test_pdl!(
1269         struct_decl_complex_scalars,
1270         r#"
1271           struct Foo {
1272             a: 3,
1273             b: 8,
1274             c: 5,
1275             d: 24,
1276             e: 12,
1277             f: 4,
1278           }
1279         "#,
1280     );
1281 
1282     test_pdl!(packet_decl_8bit_enum, " enum Foo :  8 { A = 1, B = 2 } packet Bar { x: Foo }");
1283     test_pdl!(packet_decl_24bit_enum, "enum Foo : 24 { A = 1, B = 2 } packet Bar { x: Foo }");
1284     test_pdl!(packet_decl_64bit_enum, "enum Foo : 64 { A = 1, B = 2 } packet Bar { x: Foo }");
1285 
1286     test_pdl!(
1287         packet_decl_mixed_scalars_enums,
1288         "
1289           enum Enum7 : 7 {
1290             A = 1,
1291             B = 2,
1292           }
1293 
1294           enum Enum9 : 9 {
1295             A = 1,
1296             B = 2,
1297           }
1298 
1299           packet Foo {
1300             x: Enum7,
1301             y: 5,
1302             z: Enum9,
1303             w: 3,
1304           }
1305         "
1306     );
1307 
1308     test_pdl!(packet_decl_8bit_scalar_array, " packet Foo { x:  8[3] }");
1309     test_pdl!(packet_decl_24bit_scalar_array, "packet Foo { x: 24[5] }");
1310     test_pdl!(packet_decl_64bit_scalar_array, "packet Foo { x: 64[7] }");
1311 
1312     test_pdl!(
1313         packet_decl_8bit_enum_array,
1314         "enum Foo :  8 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[3] }"
1315     );
1316     test_pdl!(
1317         packet_decl_24bit_enum_array,
1318         "enum Foo : 24 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[5] }"
1319     );
1320     test_pdl!(
1321         packet_decl_64bit_enum_array,
1322         "enum Foo : 64 { FOO_BAR = 1, BAZ = 2 } packet Bar { x: Foo[7] }"
1323     );
1324 
1325     test_pdl!(
1326         packet_decl_array_dynamic_count,
1327         "
1328           packet Foo {
1329             _count_(x): 5,
1330             padding: 3,
1331             x: 24[]
1332           }
1333         "
1334     );
1335 
1336     test_pdl!(
1337         packet_decl_array_dynamic_size,
1338         "
1339           packet Foo {
1340             _size_(x): 5,
1341             padding: 3,
1342             x: 24[]
1343           }
1344         "
1345     );
1346 
1347     test_pdl!(
1348         packet_decl_array_unknown_element_width_dynamic_size,
1349         "
1350           struct Foo {
1351             _count_(a): 40,
1352             a: 16[],
1353           }
1354 
1355           packet Bar {
1356             _size_(x): 40,
1357             x: Foo[],
1358           }
1359         "
1360     );
1361 
1362     test_pdl!(
1363         packet_decl_array_unknown_element_width_dynamic_count,
1364         "
1365           struct Foo {
1366             _count_(a): 40,
1367             a: 16[],
1368           }
1369 
1370           packet Bar {
1371             _count_(x): 40,
1372             x: Foo[],
1373           }
1374         "
1375     );
1376 
1377     test_pdl!(
1378         packet_decl_array_with_padding,
1379         "
1380           struct Foo {
1381             _count_(a): 40,
1382             a: 16[],
1383           }
1384 
1385           packet Bar {
1386             a: Foo[],
1387             _padding_ [128],
1388           }
1389         "
1390     );
1391 
1392     test_pdl!(
1393         packet_decl_reserved_field,
1394         "
1395           packet Foo {
1396             _reserved_: 40,
1397           }
1398         "
1399     );
1400 
1401     test_pdl!(
1402         packet_decl_custom_field,
1403         r#"
1404           custom_field Bar1 : 24 "exact"
1405           custom_field Bar2 : 32 "truncated"
1406 
1407           packet Foo {
1408             a: Bar1,
1409             b: Bar2,
1410           }
1411         "#
1412     );
1413 
1414     test_pdl!(
1415         packet_decl_fixed_scalar_field,
1416         "
1417           packet Foo {
1418             _fixed_ = 7 : 7,
1419             b: 57,
1420           }
1421         "
1422     );
1423 
1424     test_pdl!(
1425         packet_decl_fixed_enum_field,
1426         "
1427           enum Enum7 : 7 {
1428             A = 1,
1429             B = 2,
1430           }
1431 
1432           packet Foo {
1433               _fixed_ = A : Enum7,
1434               b: 57,
1435           }
1436         "
1437     );
1438 
1439     test_pdl!(
1440         packet_decl_payload_field_variable_size,
1441         "
1442           packet Foo {
1443               a: 8,
1444               _size_(_payload_): 8,
1445               _payload_,
1446               b: 16,
1447           }
1448         "
1449     );
1450 
1451     test_pdl!(
1452         packet_decl_payload_field_unknown_size,
1453         "
1454           packet Foo {
1455               a: 24,
1456               _payload_,
1457           }
1458         "
1459     );
1460 
1461     test_pdl!(
1462         packet_decl_payload_field_unknown_size_terminal,
1463         "
1464           packet Foo {
1465               _payload_,
1466               a: 24,
1467           }
1468         "
1469     );
1470 
1471     test_pdl!(
1472         packet_decl_child_packets,
1473         "
1474           enum Enum16 : 16 {
1475             A = 1,
1476             B = 2,
1477           }
1478 
1479           packet Foo {
1480               a: 8,
1481               b: Enum16,
1482               _size_(_payload_): 8,
1483               _payload_
1484           }
1485 
1486           packet Bar : Foo (a = 100) {
1487               x: 8,
1488           }
1489 
1490           packet Baz : Foo (b = B) {
1491               y: 16,
1492           }
1493         "
1494     );
1495 
1496     test_pdl!(
1497         packet_decl_grand_children,
1498         "
1499           enum Enum16 : 16 {
1500             A = 1,
1501             B = 2,
1502           }
1503 
1504           packet Parent {
1505               foo: Enum16,
1506               bar: Enum16,
1507               baz: Enum16,
1508               _size_(_payload_): 8,
1509               _payload_
1510           }
1511 
1512           packet Child : Parent (foo = A) {
1513               quux: Enum16,
1514               _payload_,
1515           }
1516 
1517           packet GrandChild : Child (bar = A, quux = A) {
1518               _body_,
1519           }
1520 
1521           packet GrandGrandChild : GrandChild (baz = A) {
1522               _body_,
1523           }
1524         "
1525     );
1526 
1527     test_pdl!(
1528         packet_decl_parent_with_no_payload,
1529         "
1530           enum Enum8 : 8 {
1531             A = 0,
1532           }
1533 
1534           packet Parent {
1535             v : Enum8,
1536           }
1537 
1538           packet Child : Parent (v = A) {
1539           }
1540         "
1541     );
1542 
1543     test_pdl!(
1544         packet_decl_parent_with_alias_child,
1545         "
1546           enum Enum8 : 8 {
1547             A = 0,
1548             B = 1,
1549             C = 2,
1550           }
1551 
1552           packet Parent {
1553             v : Enum8,
1554             _payload_,
1555           }
1556 
1557           packet AliasChild : Parent {
1558             _payload_
1559           }
1560 
1561           packet NormalChild : Parent (v = A) {
1562           }
1563 
1564           packet NormalGrandChild1 : AliasChild (v = B) {
1565           }
1566 
1567           packet NormalGrandChild2 : AliasChild (v = C) {
1568               _payload_
1569           }
1570         "
1571     );
1572 
1573     test_pdl!(
1574         reserved_identifier,
1575         "
1576           packet Test {
1577             type: 8,
1578           }
1579         "
1580     );
1581 
1582     test_pdl!(
1583         payload_with_size_modifier,
1584         "
1585         packet Test {
1586             _size_(_payload_): 8,
1587             _payload_ : [+1],
1588         }
1589         "
1590     );
1591 
1592     // TODO(mgeisler): enable this test when we have an approach to
1593     // struct fields with parents.
1594     //
1595     // test_pdl!(
1596     //     struct_decl_child_structs,
1597     //     "
1598     //       enum Enum16 : 16 {
1599     //         A = 1,
1600     //         B = 2,
1601     //       }
1602     //
1603     //       struct Foo {
1604     //           a: 8,
1605     //           b: Enum16,
1606     //           _size_(_payload_): 8,
1607     //           _payload_
1608     //       }
1609     //
1610     //       struct Bar : Foo (a = 100) {
1611     //           x: 8,
1612     //       }
1613     //
1614     //       struct Baz : Foo (b = B) {
1615     //           y: 16,
1616     //       }
1617     //     "
1618     // );
1619     //
1620     // test_pdl!(
1621     //     struct_decl_grand_children,
1622     //     "
1623     //       enum Enum16 : 16 {
1624     //         A = 1,
1625     //         B = 2,
1626     //       }
1627     //
1628     //       struct Parent {
1629     //           foo: Enum16,
1630     //           bar: Enum16,
1631     //           baz: Enum16,
1632     //           _size_(_payload_): 8,
1633     //           _payload_
1634     //       }
1635     //
1636     //       struct Child : Parent (foo = A) {
1637     //           quux: Enum16,
1638     //           _payload_,
1639     //       }
1640     //
1641     //       struct GrandChild : Child (bar = A, quux = A) {
1642     //           _body_,
1643     //       }
1644     //
1645     //       struct GrandGrandChild : GrandChild (baz = A) {
1646     //           _body_,
1647     //       }
1648     //     "
1649     // );
1650 }
1651