1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Implementation of Code Generation for ASN.1 `SEQUENCE` Type.

use proc_macro2::TokenStream;
use quote::quote;

use crate::error::Error;
use crate::generator::Generator;
use crate::resolver::asn::structs::types::{
    constructed::ResolvedConstructedType, Asn1ResolvedType,
};

impl ResolvedConstructedType {
    pub(crate) fn generate_sequence(
        &self,
        name: &str,
        generator: &mut Generator,
    ) -> Result<TokenStream, Error> {
        if let ResolvedConstructedType::Sequence {
            ref components,
            ref extensible,
            ref additions,
            ..
        } = self
        {
            let type_name = generator.to_type_ident(name);

            let extensible = if *extensible {
                quote! { true }
            } else {
                quote! { false }
            };

            let vis = generator.get_visibility_tokens();

            let mut comp_tokens = TokenStream::new();
            let mut optional_fields = 0;
            for c in components {
                let comp_field_ident = generator.to_value_ident(&c.component.id);
                let comp_ty_suffix = generator.to_type_ident(&c.component.id);
                let input_comp_ty_ident = format!("{}{}", name, comp_ty_suffix);
                let comp_ty_ident = Asn1ResolvedType::generate_name_maybe_aux_type(
                    &c.component.ty,
                    generator,
                    Some(&input_comp_ty_ident),
                )?;
                let mut fld_attrs = vec![];

                let fld_tokens = if c.optional {
                    let idx: proc_macro2::TokenStream =
                        format!("{}", optional_fields).parse().unwrap();
                    fld_attrs.push(quote! { optional_idx = #idx,  });

                    optional_fields += 1;

                    quote! { #vis #comp_field_ident: Option<#comp_ty_ident>, }
                } else {
                    quote! { #vis #comp_field_ident: #comp_ty_ident, }
                };

                if c.key_field {
                    fld_attrs.push(quote! { key_field = true })
                }

                let fld_attr_tokens = if !fld_attrs.is_empty() {
                    quote! { #[asn(#(#fld_attrs),*)] }
                } else {
                    quote! {}
                };

                comp_tokens.extend(quote! {
                    #fld_attr_tokens #fld_tokens
                });
            }

            if additions.is_some() {
                log::warn!("Fields for some sequence additions may not be generated!");
            };

            let mut ty_tokens = quote! { type = "SEQUENCE", extensible = #extensible };

            if optional_fields > 0 {
                let optflds: proc_macro2::TokenStream =
                    format!("{}", optional_fields).parse().unwrap();
                ty_tokens.extend(quote! { , optional_fields = #optflds });
            }

            let dir = generator.generate_derive_tokens();
            Ok(quote! {
                #dir
                #[asn(#ty_tokens)]
                #vis struct #type_name {
                    #comp_tokens
                }
            })
        } else {
            Ok(TokenStream::new())
        }
    }
}