Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ec924426 authored by Henri Chataing's avatar Henri Chataing Committed by Automerger Merge Worker
Browse files

Merge changes If4c3a82e,Ibbd97441 am: 643cae14

parents c2cda7ff 643cae14
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -97,6 +97,10 @@ filegroup {
        "tests/generated/packet_decl_mask_scalar_value_little_endian.rs",
        "tests/generated/packet_decl_mask_scalar_value_little_endian.rs",
        "tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs",
        "tests/generated/packet_decl_mixed_scalars_enums_big_endian.rs",
        "tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs",
        "tests/generated/packet_decl_mixed_scalars_enums_little_endian.rs",
        "tests/generated/packet_decl_parent_with_alias_child_big_endian.rs",
        "tests/generated/packet_decl_parent_with_alias_child_little_endian.rs",
        "tests/generated/packet_decl_parent_with_no_payload_big_endian.rs",
        "tests/generated/packet_decl_parent_with_no_payload_little_endian.rs",
        "tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs",
        "tests/generated/packet_decl_payload_field_unknown_size_big_endian.rs",
        "tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs",
        "tests/generated/packet_decl_payload_field_unknown_size_little_endian.rs",
        "tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs",
        "tests/generated/packet_decl_payload_field_unknown_size_terminal_big_endian.rs",
+50 −1
Original line number Original line Diff line number Diff line
@@ -477,6 +477,9 @@ fn generate_packet_decl(
                    #parent_data_child::#prev_parent_id(#prev_parent_id_lower)
                    #parent_data_child::#prev_parent_id(#prev_parent_id_lower)
                });
                });
            }
            }
        } else if scope.iter_children(parent_id).next().is_some() {
            field.push(format_ident!("child"));
            value.push(quote! { #parent_data_child::None });
        }
        }


        quote! {
        quote! {
@@ -907,7 +910,7 @@ fn generate_custom_field_decl(id: &str, width: usize) -> proc_macro2::TokenStrea
    let id = format_ident!("{}", id);
    let id = format_ident!("{}", id);
    let backing_type = types::Integer::new(width);
    let backing_type = types::Integer::new(width);
    let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width));
    let backing_type_str = proc_macro2::Literal::string(&format!("u{}", backing_type.width));
    let max_value = mask_bits(width, "usize");
    let max_value = mask_bits(width, &format!("u{}", backing_type.width));
    let common = quote! {
    let common = quote! {
        impl From<&#id> for #backing_type {
        impl From<&#id> for #backing_type {
            fn from(value: &#id) -> #backing_type {
            fn from(value: &#id) -> #backing_type {
@@ -1479,6 +1482,52 @@ mod tests {
        "
        "
    );
    );


    test_pdl!(
        packet_decl_parent_with_no_payload,
        "
          enum Enum8 : 8 {
            A = 0,
          }

          packet Parent {
            v : Enum8,
          }

          packet Child : Parent (v = A) {
          }
        "
    );

    test_pdl!(
        packet_decl_parent_with_alias_child,
        "
          enum Enum8 : 8 {
            A = 0,
            B = 1,
            C = 2,
          }

          packet Parent {
            v : Enum8,
            _payload_,
          }

          packet AliasChild : Parent {
            _payload_
          }

          packet NormalChild : Parent (v = A) {
          }

          packet NormalGrandChild1 : AliasChild (v = B) {
          }

          packet NormalGrandChild2 : AliasChild (v = C) {
              _payload_
          }
        "
    );

    // TODO(mgeisler): enable this test when we have an approach to
    // TODO(mgeisler): enable this test when we have an approach to
    // struct fields with parents.
    // struct fields with parents.
    //
    //
+61 −37
Original line number Original line Diff line number Diff line
@@ -18,7 +18,7 @@ use crate::backends::rust::{
};
};
use crate::{ast, lint};
use crate::{ast, lint};
use quote::{format_ident, quote};
use quote::{format_ident, quote};
use std::collections::{BTreeSet, HashMap};
use std::collections::BTreeSet;


fn size_field_ident(id: &str) -> proc_macro2::Ident {
fn size_field_ident(id: &str) -> proc_macro2::Ident {
    format_ident!("{}_size", id.trim_matches('_'))
    format_ident!("{}_size", id.trim_matches('_'))
@@ -627,51 +627,75 @@ impl<'a> FieldParser<'a> {
            return;
            return;
        }
        }


        let child_ids = children
        // Gather fields that are constrained in immediate child declarations.
        // Keep the fields sorted by name.
        // TODO: fields that are only matched in grand children will not be included.
        let constrained_fields = children
            .iter()
            .iter()
            .map(|child| format_ident!("{}", child.id().unwrap()))
            .flat_map(|child| child.constraints().map(|c| &c.id))
            .collect::<Vec<_>>();
            .collect::<BTreeSet<_>>();
        let child_ids_data = child_ids.iter().map(|ident| format_ident!("{ident}Data"));


        let mut match_values = Vec::new();
        // Set of field names (sorted by name).
        let mut child_parse_args = Vec::new();
        let mut constrained_fields = BTreeSet::new();
        let mut child_ids_data = Vec::new();
        // Maps (child name, field name) -> value.
        let mut child_ids = Vec::new();
        let mut constraint_values = HashMap::new();
        let get_constraint_value = |mut constraints: std::slice::Iter<'_, ast::Constraint>,
                                    id: &str|
         -> Option<proc_macro2::TokenStream> {
            constraints.find(|c| c.id == id).map(|c| constraint_to_value(packet_scope, c))
        };


        for child in children.iter() {
        for child in children.iter() {
            match &child.desc {
            let tuple_values = constrained_fields
                ast::DeclDesc::Packet { id, constraints, .. }
                .iter()
                | ast::DeclDesc::Struct { id, constraints, .. } => {
                .map(|id| {
                    for constraint in constraints.iter() {
                    get_constraint_value(child.constraints(), id).map(|v| vec![v]).unwrap_or_else(
                        constrained_fields.insert(&constraint.id);
                        || {
                        constraint_values.insert(
                            self.scope
                            (id.as_str(), &constraint.id),
                                .file
                            constraint_to_value(packet_scope, constraint),
                                .iter_children(child)
                        );
                                .filter_map(|d| get_constraint_value(d.constraints(), id))
                    }
                                .collect()
                }
                        },
                _ => unreachable!("Invalid child: {child:?}"),
                    )
            }
                })
                .collect::<Vec<_>>();

            // If no constraint values are found for the tuple just skip the child
            // packet as it would capture unwanted input packets.
            if tuple_values.iter().all(|v| v.is_empty()) {
                continue;
            }
            }


        let wildcard = quote!(_);
            let tuple_values = tuple_values
        let match_values = children.iter().map(|child| {
                .iter()
            let child_id = child.id().unwrap();
                .map(|v| v.is_empty().then_some(quote!(_)).unwrap_or_else(|| quote!( #(#v)|* )))
            let values = constrained_fields.iter().map(|field_name| {
                .collect::<Vec<_>>();
                constraint_values.get(&(child_id, field_name)).unwrap_or(&wildcard)

            });
            let fields = find_constrained_parent_fields(self.scope, child.id().unwrap())
            quote! {
                .map(|field| format_ident!("{}", field.id().unwrap()));
                (#(#values),*)

            match_values.push(quote!( (#(#tuple_values),*) ));
            child_parse_args.push(quote!( #(, #fields)*));
            child_ids_data.push(format_ident!("{}Data", child.id().unwrap()));
            child_ids.push(format_ident!("{}", child.id().unwrap()));
        }
        }
        });

        let constrained_field_idents =
        let constrained_field_idents =
            constrained_fields.iter().map(|field| format_ident!("{field}"));
            constrained_fields.iter().map(|field| format_ident!("{field}"));
        let child_parse_args = children.iter().map(|child| {
            let fields = find_constrained_parent_fields(self.scope, child.id().unwrap())
                .map(|field| format_ident!("{}", field.id().unwrap()));
            quote!(#(, #fields)*)
        });
        let packet_data_child = format_ident!("{}DataChild", self.packet_name);
        let packet_data_child = format_ident!("{}DataChild", self.packet_name);

        // Parsing of packet children requires having a payload field;
        // it is allowed to inherit from a packet with empty payload, in this
        // case generate an empty payload value.
        if !decl
            .fields()
            .any(|f| matches!(&f.desc, ast::FieldDesc::Payload { .. } | ast::FieldDesc::Body))
        {
            self.code.push(quote! {
                let payload: &[u8] = &[];
            })
        }
        self.code.push(quote! {
        self.code.push(quote! {
            let child = match (#(#constrained_field_idents),*) {
            let child = match (#(#constrained_field_idents),*) {
                #(#match_values if #child_ids_data::conforms(&payload) => {
                #(#match_values if #child_ids_data::conforms(&payload) => {
+1 −1
Original line number Original line Diff line number Diff line
@@ -90,7 +90,7 @@ pub fn rust_borrow(
        ast::FieldDesc::Typedef { type_id, .. } => match &scope.typedef[type_id].desc {
        ast::FieldDesc::Typedef { type_id, .. } => match &scope.typedef[type_id].desc {
            ast::DeclDesc::Enum { .. } => quote!(),
            ast::DeclDesc::Enum { .. } => quote!(),
            ast::DeclDesc::Struct { .. } => quote!(&),
            ast::DeclDesc::Struct { .. } => quote!(&),
            ast::DeclDesc::CustomField { .. } => quote!(&),
            ast::DeclDesc::CustomField { .. } => quote!(),
            desc => unreachable!("unexpected declaration: {desc:?}"),
            desc => unreachable!("unexpected declaration: {desc:?}"),
        },
        },
        ast::FieldDesc::Array { .. } => quote!(&),
        ast::FieldDesc::Array { .. } => quote!(&),
+1 −1
Original line number Original line Diff line number Diff line
@@ -21,7 +21,7 @@ use crate::ast::*;
#[derive(Debug)]
#[derive(Debug)]
pub struct Scope<'d> {
pub struct Scope<'d> {
    // Original file.
    // Original file.
    file: &'d analyzer_ast::File,
    pub file: &'d analyzer_ast::File,


    // Collection of Group, Packet, Enum, Struct, Checksum, and CustomField declarations.
    // Collection of Group, Packet, Enum, Struct, Checksum, and CustomField declarations.
    pub typedef: HashMap<String, &'d analyzer_ast::Decl>,
    pub typedef: HashMap<String, &'d analyzer_ast::Decl>,
Loading