Loading tools/pdl/src/backends/rust.rs +10 −9 Original line number Diff line number Diff line Loading @@ -46,9 +46,9 @@ pub fn mask_bits(n: usize, suffix: &str) -> syn::LitInt { syn::parse_str::<syn::LitInt>(&format!("0x{hex_digits}{suffix}")).unwrap() } fn generate_packet_size_getter( scope: &lint::Scope<'_>, fields: &[&analyzer_ast::Field], fn generate_packet_size_getter<'a>( scope: &lint::Scope<'a>, fields: impl Iterator<Item = &'a analyzer_ast::Field>, is_packet: bool, ) -> (usize, proc_macro2::TokenStream) { let mut constant_width = 0; Loading Loading @@ -174,7 +174,7 @@ fn find_constrained_parent_fields<'a>( let packet_scope = &scope.scopes[&scope.typedef[id]]; find_constrained_fields(scope, id).into_iter().filter(|field| { let id = field.id().unwrap(); packet_scope.all_fields.contains_key(id) && !packet_scope.named.contains_key(id) packet_scope.all_fields.contains_key(id) && packet_scope.get_packet_field(id).is_none() }) } Loading @@ -195,7 +195,7 @@ fn generate_data_struct( let serializer_span = format_ident!("buffer"); let mut field_parser = FieldParser::new(scope, endianness, id, &span); let mut field_serializer = FieldSerializer::new(scope, endianness, id, &serializer_span); for field in &packet_scope.fields { for field in packet_scope.iter_fields() { field_parser.add(field); field_serializer.add(field); } Loading @@ -211,7 +211,7 @@ fn generate_data_struct( }; let (constant_width, packet_size) = generate_packet_size_getter(scope, &packet_scope.fields, is_packet); generate_packet_size_getter(scope, packet_scope.iter_fields(), is_packet); let conforms = if constant_width == 0 { quote! { true } } else { Loading @@ -225,7 +225,7 @@ fn generate_data_struct( let struct_name = if is_packet { format_ident!("{id}Data") } else { format_ident!("{id}") }; let fields_with_ids = packet_scope.fields.iter().filter(|f| f.id().is_some()).collect::<Vec<_>>(); packet_scope.iter_fields().filter(|f| f.id().is_some()).collect::<Vec<_>>(); let mut field_names = fields_with_ids.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>(); let mut field_types = fields_with_ids.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>(); Loading Loading @@ -376,7 +376,7 @@ fn generate_packet_decl( let all_field_getter_names = all_field_names.iter().map(|id| format_ident!("get_{id}")); let all_field_self_field = all_fields.iter().map(|f| { for (parent, parent_id) in parents.iter().zip(parent_lower_ids.iter()) { if scope.scopes[parent].fields.contains(f) { if scope.scopes[parent].iter_fields().any(|ff| ff.id() == f.id()) { return quote!(self.#parent_id); } } Loading @@ -402,7 +402,8 @@ fn generate_packet_decl( let parent_packet_scope = &scope.scopes[&scope.typedef[parent_id]]; let named_fields = { let mut names = parent_packet_scope.named.keys().collect::<Vec<_>>(); let mut names = parent_packet_scope.iter_fields().filter_map(ast::Field::id).collect::<Vec<_>>(); names.sort(); names }; Loading tools/pdl/src/backends/rust/parser.rs +1 −1 Original line number Diff line number Diff line Loading @@ -218,7 +218,7 @@ impl<'a> FieldParser<'a> { fn payload_field_offset_from_end(&self) -> Option<usize> { let packet_scope = self.packet_scope().unwrap(); let mut fields = packet_scope.fields.iter(); let mut fields = packet_scope.iter_fields(); fields.find(|f| { matches!(f.desc, ast::FieldDesc::Body { .. } | ast::FieldDesc::Payload { .. }) })?; Loading tools/pdl/src/lint.rs +30 −124 Original line number Diff line number Diff line Loading @@ -19,16 +19,8 @@ pub struct Scope<'d> { /// Gather information about a Packet, Struct, or Group declaration. #[derive(Debug)] pub struct PacketScope<'d> { // Typedef, scalar, array fields. pub named: HashMap<String, &'d analyzer_ast::Field>, // Flattened field declarations. // Contains field declarations from the original Packet, Struct, or Group, // where Group fields have been substituted by their body. pub fields: Vec<&'d analyzer_ast::Field>, // Constraint declarations gathered from Group inlining. pub constraints: HashMap<String, &'d Constraint>, // Original decl. decl: &'d analyzer_ast::Decl, // Local and inherited field declarations. Only named fields are preserved. // Saved here for reference for parent constraint resolving. Loading @@ -46,11 +38,6 @@ impl<'d> std::hash::Hash for &'d analyzer_ast::Decl { } impl<'d> PacketScope<'d> { /// Insert a field declaration into a packet scope. fn insert(&mut self, field: &'d analyzer_ast::Field) { field.id().and_then(|id| self.named.insert(id.to_owned(), field)); } /// Add parent fields and constraints to the scope. /// Only named fields are imported. fn inherit( Loading @@ -66,90 +53,53 @@ impl<'d> PacketScope<'d> { self.all_constraints.insert(id, constraint); } // Merge group constraints into parent constraints, // but generate no duplication warnings, the constraints // do no apply to the same field set. for (id, constraint) in self.constraints.iter() { self.all_constraints.insert(id.clone(), constraint); } // Save parent fields. self.all_fields = parent.all_fields.clone(); } /// Insert group field declarations into a packet scope. fn inline( &mut self, packet_scope: &PacketScope<'d>, constraints: impl Iterator<Item = &'d Constraint>, ) { for (id, field) in packet_scope.named.iter() { self.named.insert(id.clone(), field); } // Append group fields to the finalizeed fields. for field in packet_scope.fields.iter() { self.fields.push(field); } // Append group constraints to the caller packet_scope. for (id, constraint) in packet_scope.constraints.iter() { self.constraints.insert(id.clone(), constraint); } // Add constraints to the packet_scope, checking for duplicate constraints. for constraint in constraints { let id = constraint.id.clone(); self.constraints.insert(id, constraint); } /// Iterate over the packet's fields. pub fn iter_fields(&self) -> impl Iterator<Item = &'d analyzer_ast::Field> { self.decl.fields() } /// Lookup a field by name. This will also find the special /// `_payload_` and `_body_` fields. pub fn get_packet_field(&self, id: &str) -> Option<&analyzer_ast::Field> { self.named.get(id).copied().or(match id { "_payload_" | "_body_" => self.get_payload_field(), _ => None, self.decl.fields().find(|field| match &field.desc { FieldDesc::Payload { .. } => id == "_payload_", FieldDesc::Body { .. } => id == "_body_", _ => field.id() == Some(id), }) } /// Find the payload or body field, if any. pub fn get_payload_field(&self) -> Option<&analyzer_ast::Field> { self.fields .iter() self.decl .fields() .find(|field| matches!(&field.desc, FieldDesc::Payload { .. } | FieldDesc::Body { .. })) .copied() } /// Lookup the size field for an array field. pub fn get_array_size_field(&self, id: &str) -> Option<&analyzer_ast::Field> { self.fields .iter() .find(|field| match &field.desc { FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => { field_id == id } self.decl.fields().find(|field| match &field.desc { FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id, _ => false, }) .copied() } /// Find the size field corresponding to the payload or body /// field of this packet. pub fn get_payload_size_field(&self) -> Option<&analyzer_ast::Field> { self.fields .iter() .find(|field| match &field.desc { self.decl.fields().find(|field| match &field.desc { FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_", _ => false, }) .copied() } /// Cleanup scope after processing all fields. fn finalize(&mut self) { // Check field shadowing. for f in self.fields.iter() { for f in self.decl.fields() { if let Some(id) = f.id() { self.all_fields.insert(id.to_string(), f); } Loading @@ -169,9 +119,6 @@ impl<'d> Scope<'d> { if let Some(id) = decl.id() { scope.typedef.insert(id.to_string(), decl); } if let Some(lscope) = decl_scope(decl) { scope.scopes.insert(decl, lscope); } } scope.finalize(); Loading @@ -179,13 +126,7 @@ impl<'d> Scope<'d> { } // Sort Packet, Struct, and Group declarations by reverse topological // orde, and inline Group fields. // Raises errors and warnings for: // - undeclared included Groups, // - undeclared Typedef fields, // - undeclared Packet or Struct parents, // - recursive Group insertion, // - recursive Packet or Struct inheritance. // order. fn finalize(&mut self) -> Vec<&'d analyzer_ast::Decl> { // Auxiliary function implementing BFS on Packet tree. enum Mark { Loading Loading @@ -219,34 +160,20 @@ impl<'d> Scope<'d> { }; context.visited.insert(decl, Mark::Temporary); let mut lscope = decl_scope(decl).unwrap(); let mut lscope = PacketScope { decl, all_fields: HashMap::new(), all_constraints: HashMap::new() }; // Iterate over Struct and Group fields. for f in fields { match &f.desc { FieldDesc::Group { group_id, constraints, .. } => { match scope.typedef.get(group_id) { Some(group_decl @ Decl { desc: DeclDesc::Group { .. }, .. }) => { // Recurse to flatten the inserted group. if let Some(rscope) = bfs(group_decl, context, scope) { // Inline the group fields and constraints into // the current scope. lscope.inline(rscope, constraints.iter()) } } None | Some(_) => (), } } FieldDesc::Typedef { type_id, .. } => { lscope.fields.push(f); match scope.typedef.get(type_id) { FieldDesc::Group { .. } => unreachable!(), FieldDesc::Typedef { type_id, .. } => match scope.typedef.get(type_id) { Some(struct_decl @ Decl { desc: DeclDesc::Struct { .. }, .. }) => { bfs(struct_decl, context, scope); } None | Some(_) => (), } } _ => lscope.fields.push(f), }, _ => (), } } Loading Loading @@ -374,24 +301,3 @@ impl<'d> Scope<'d> { } } } fn decl_scope(decl: &analyzer_ast::Decl) -> Option<PacketScope<'_>> { match &decl.desc { DeclDesc::Packet { fields, .. } | DeclDesc::Struct { fields, .. } | DeclDesc::Group { fields, .. } => { let mut scope = PacketScope { named: HashMap::new(), fields: Vec::new(), constraints: HashMap::new(), all_fields: HashMap::new(), all_constraints: HashMap::new(), }; for field in fields { scope.insert(field) } Some(scope) } _ => None, } } Loading
tools/pdl/src/backends/rust.rs +10 −9 Original line number Diff line number Diff line Loading @@ -46,9 +46,9 @@ pub fn mask_bits(n: usize, suffix: &str) -> syn::LitInt { syn::parse_str::<syn::LitInt>(&format!("0x{hex_digits}{suffix}")).unwrap() } fn generate_packet_size_getter( scope: &lint::Scope<'_>, fields: &[&analyzer_ast::Field], fn generate_packet_size_getter<'a>( scope: &lint::Scope<'a>, fields: impl Iterator<Item = &'a analyzer_ast::Field>, is_packet: bool, ) -> (usize, proc_macro2::TokenStream) { let mut constant_width = 0; Loading Loading @@ -174,7 +174,7 @@ fn find_constrained_parent_fields<'a>( let packet_scope = &scope.scopes[&scope.typedef[id]]; find_constrained_fields(scope, id).into_iter().filter(|field| { let id = field.id().unwrap(); packet_scope.all_fields.contains_key(id) && !packet_scope.named.contains_key(id) packet_scope.all_fields.contains_key(id) && packet_scope.get_packet_field(id).is_none() }) } Loading @@ -195,7 +195,7 @@ fn generate_data_struct( let serializer_span = format_ident!("buffer"); let mut field_parser = FieldParser::new(scope, endianness, id, &span); let mut field_serializer = FieldSerializer::new(scope, endianness, id, &serializer_span); for field in &packet_scope.fields { for field in packet_scope.iter_fields() { field_parser.add(field); field_serializer.add(field); } Loading @@ -211,7 +211,7 @@ fn generate_data_struct( }; let (constant_width, packet_size) = generate_packet_size_getter(scope, &packet_scope.fields, is_packet); generate_packet_size_getter(scope, packet_scope.iter_fields(), is_packet); let conforms = if constant_width == 0 { quote! { true } } else { Loading @@ -225,7 +225,7 @@ fn generate_data_struct( let struct_name = if is_packet { format_ident!("{id}Data") } else { format_ident!("{id}") }; let fields_with_ids = packet_scope.fields.iter().filter(|f| f.id().is_some()).collect::<Vec<_>>(); packet_scope.iter_fields().filter(|f| f.id().is_some()).collect::<Vec<_>>(); let mut field_names = fields_with_ids.iter().map(|f| format_ident!("{}", f.id().unwrap())).collect::<Vec<_>>(); let mut field_types = fields_with_ids.iter().map(|f| types::rust_type(f)).collect::<Vec<_>>(); Loading Loading @@ -376,7 +376,7 @@ fn generate_packet_decl( let all_field_getter_names = all_field_names.iter().map(|id| format_ident!("get_{id}")); let all_field_self_field = all_fields.iter().map(|f| { for (parent, parent_id) in parents.iter().zip(parent_lower_ids.iter()) { if scope.scopes[parent].fields.contains(f) { if scope.scopes[parent].iter_fields().any(|ff| ff.id() == f.id()) { return quote!(self.#parent_id); } } Loading @@ -402,7 +402,8 @@ fn generate_packet_decl( let parent_packet_scope = &scope.scopes[&scope.typedef[parent_id]]; let named_fields = { let mut names = parent_packet_scope.named.keys().collect::<Vec<_>>(); let mut names = parent_packet_scope.iter_fields().filter_map(ast::Field::id).collect::<Vec<_>>(); names.sort(); names }; Loading
tools/pdl/src/backends/rust/parser.rs +1 −1 Original line number Diff line number Diff line Loading @@ -218,7 +218,7 @@ impl<'a> FieldParser<'a> { fn payload_field_offset_from_end(&self) -> Option<usize> { let packet_scope = self.packet_scope().unwrap(); let mut fields = packet_scope.fields.iter(); let mut fields = packet_scope.iter_fields(); fields.find(|f| { matches!(f.desc, ast::FieldDesc::Body { .. } | ast::FieldDesc::Payload { .. }) })?; Loading
tools/pdl/src/lint.rs +30 −124 Original line number Diff line number Diff line Loading @@ -19,16 +19,8 @@ pub struct Scope<'d> { /// Gather information about a Packet, Struct, or Group declaration. #[derive(Debug)] pub struct PacketScope<'d> { // Typedef, scalar, array fields. pub named: HashMap<String, &'d analyzer_ast::Field>, // Flattened field declarations. // Contains field declarations from the original Packet, Struct, or Group, // where Group fields have been substituted by their body. pub fields: Vec<&'d analyzer_ast::Field>, // Constraint declarations gathered from Group inlining. pub constraints: HashMap<String, &'d Constraint>, // Original decl. decl: &'d analyzer_ast::Decl, // Local and inherited field declarations. Only named fields are preserved. // Saved here for reference for parent constraint resolving. Loading @@ -46,11 +38,6 @@ impl<'d> std::hash::Hash for &'d analyzer_ast::Decl { } impl<'d> PacketScope<'d> { /// Insert a field declaration into a packet scope. fn insert(&mut self, field: &'d analyzer_ast::Field) { field.id().and_then(|id| self.named.insert(id.to_owned(), field)); } /// Add parent fields and constraints to the scope. /// Only named fields are imported. fn inherit( Loading @@ -66,90 +53,53 @@ impl<'d> PacketScope<'d> { self.all_constraints.insert(id, constraint); } // Merge group constraints into parent constraints, // but generate no duplication warnings, the constraints // do no apply to the same field set. for (id, constraint) in self.constraints.iter() { self.all_constraints.insert(id.clone(), constraint); } // Save parent fields. self.all_fields = parent.all_fields.clone(); } /// Insert group field declarations into a packet scope. fn inline( &mut self, packet_scope: &PacketScope<'d>, constraints: impl Iterator<Item = &'d Constraint>, ) { for (id, field) in packet_scope.named.iter() { self.named.insert(id.clone(), field); } // Append group fields to the finalizeed fields. for field in packet_scope.fields.iter() { self.fields.push(field); } // Append group constraints to the caller packet_scope. for (id, constraint) in packet_scope.constraints.iter() { self.constraints.insert(id.clone(), constraint); } // Add constraints to the packet_scope, checking for duplicate constraints. for constraint in constraints { let id = constraint.id.clone(); self.constraints.insert(id, constraint); } /// Iterate over the packet's fields. pub fn iter_fields(&self) -> impl Iterator<Item = &'d analyzer_ast::Field> { self.decl.fields() } /// Lookup a field by name. This will also find the special /// `_payload_` and `_body_` fields. pub fn get_packet_field(&self, id: &str) -> Option<&analyzer_ast::Field> { self.named.get(id).copied().or(match id { "_payload_" | "_body_" => self.get_payload_field(), _ => None, self.decl.fields().find(|field| match &field.desc { FieldDesc::Payload { .. } => id == "_payload_", FieldDesc::Body { .. } => id == "_body_", _ => field.id() == Some(id), }) } /// Find the payload or body field, if any. pub fn get_payload_field(&self) -> Option<&analyzer_ast::Field> { self.fields .iter() self.decl .fields() .find(|field| matches!(&field.desc, FieldDesc::Payload { .. } | FieldDesc::Body { .. })) .copied() } /// Lookup the size field for an array field. pub fn get_array_size_field(&self, id: &str) -> Option<&analyzer_ast::Field> { self.fields .iter() .find(|field| match &field.desc { FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => { field_id == id } self.decl.fields().find(|field| match &field.desc { FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => field_id == id, _ => false, }) .copied() } /// Find the size field corresponding to the payload or body /// field of this packet. pub fn get_payload_size_field(&self) -> Option<&analyzer_ast::Field> { self.fields .iter() .find(|field| match &field.desc { self.decl.fields().find(|field| match &field.desc { FieldDesc::Size { field_id, .. } => field_id == "_payload_" || field_id == "_body_", _ => false, }) .copied() } /// Cleanup scope after processing all fields. fn finalize(&mut self) { // Check field shadowing. for f in self.fields.iter() { for f in self.decl.fields() { if let Some(id) = f.id() { self.all_fields.insert(id.to_string(), f); } Loading @@ -169,9 +119,6 @@ impl<'d> Scope<'d> { if let Some(id) = decl.id() { scope.typedef.insert(id.to_string(), decl); } if let Some(lscope) = decl_scope(decl) { scope.scopes.insert(decl, lscope); } } scope.finalize(); Loading @@ -179,13 +126,7 @@ impl<'d> Scope<'d> { } // Sort Packet, Struct, and Group declarations by reverse topological // orde, and inline Group fields. // Raises errors and warnings for: // - undeclared included Groups, // - undeclared Typedef fields, // - undeclared Packet or Struct parents, // - recursive Group insertion, // - recursive Packet or Struct inheritance. // order. fn finalize(&mut self) -> Vec<&'d analyzer_ast::Decl> { // Auxiliary function implementing BFS on Packet tree. enum Mark { Loading Loading @@ -219,34 +160,20 @@ impl<'d> Scope<'d> { }; context.visited.insert(decl, Mark::Temporary); let mut lscope = decl_scope(decl).unwrap(); let mut lscope = PacketScope { decl, all_fields: HashMap::new(), all_constraints: HashMap::new() }; // Iterate over Struct and Group fields. for f in fields { match &f.desc { FieldDesc::Group { group_id, constraints, .. } => { match scope.typedef.get(group_id) { Some(group_decl @ Decl { desc: DeclDesc::Group { .. }, .. }) => { // Recurse to flatten the inserted group. if let Some(rscope) = bfs(group_decl, context, scope) { // Inline the group fields and constraints into // the current scope. lscope.inline(rscope, constraints.iter()) } } None | Some(_) => (), } } FieldDesc::Typedef { type_id, .. } => { lscope.fields.push(f); match scope.typedef.get(type_id) { FieldDesc::Group { .. } => unreachable!(), FieldDesc::Typedef { type_id, .. } => match scope.typedef.get(type_id) { Some(struct_decl @ Decl { desc: DeclDesc::Struct { .. }, .. }) => { bfs(struct_decl, context, scope); } None | Some(_) => (), } } _ => lscope.fields.push(f), }, _ => (), } } Loading Loading @@ -374,24 +301,3 @@ impl<'d> Scope<'d> { } } } fn decl_scope(decl: &analyzer_ast::Decl) -> Option<PacketScope<'_>> { match &decl.desc { DeclDesc::Packet { fields, .. } | DeclDesc::Struct { fields, .. } | DeclDesc::Group { fields, .. } => { let mut scope = PacketScope { named: HashMap::new(), fields: Vec::new(), constraints: HashMap::new(), all_fields: HashMap::new(), all_constraints: HashMap::new(), }; for field in fields { scope.insert(field) } Some(scope) } _ => None, } }