asn1_compiler/generator/
int.rs

1//! Code Generation module
2
3use std::collections::HashMap;
4
5use anyhow::Result;
6use heck::{ToShoutySnakeCase, ToSnakeCase};
7use proc_macro2::{Ident, Literal, Span, TokenStream};
8use quote::quote;
9
10use lazy_static::lazy_static;
11
12use crate::resolver::Resolver;
13
14use crate::resolver::asn::structs::{types::Asn1ResolvedType, values::Asn1ResolvedValue};
15
16/// Supported Codecs
17#[derive(clap::ValueEnum, Clone, Debug, PartialEq, Eq, Hash)]
18pub enum Codec {
19    /// Generate code for ASN.1 APER Codec
20    Aper,
21
22    /// Generate code for ASN.1 UPER Codec
23    Uper,
24}
25
26/// Supported Derive Macros
27#[derive(clap::ValueEnum, Clone, Debug, PartialEq, Eq, Hash)]
28pub enum Derive {
29    /// Generate `Debug` code for the generated strucutres. Generated for all structures by
30    /// default.
31    Debug,
32
33    /// Generate 'Clone' code for the generated structures.
34    Clone,
35
36    /// Generate 'serde::Serialize' code for the generated structures.
37    Serialize,
38
39    /// Generate 'serde::Deserialize' code for the generated structures.
40    Deserialize,
41
42    /// Generate `Eq` code for the generated structures.
43    Eq,
44
45    /// Generate `PartialEq` code for the generated structures.
46    PartialEq,
47
48    /// Generate code for all supported derives for the generated structures.
49    All,
50}
51
52/// Visibility to be used for the generated Structs, Enums etc.
53#[derive(clap::ValueEnum, Clone, Debug)]
54pub enum Visibility {
55    /// Visibility is Public
56    Public,
57    /// Visibility is Crate
58    Crate,
59    /// Visibility is Private
60    Private,
61}
62
63lazy_static! {
64    static ref CODEC_TOKENS: HashMap<Codec, String> = {
65        let mut m = HashMap::new();
66        m.insert(Codec::Aper, "asn1_codecs_derive::AperCodec".to_string());
67        m.insert(Codec::Uper, "asn1_codecs_derive::UperCodec".to_string());
68        m
69    };
70    static ref DERIVE_TOKENS: HashMap<Derive, String> = {
71        let mut m = HashMap::new();
72        m.insert(Derive::Debug, "Debug".to_string());
73        m.insert(Derive::Clone, "Clone".to_string());
74        m.insert(Derive::Serialize, "serde::Serialize".to_string());
75        m.insert(Derive::Deserialize, "serde::Deserialize".to_string());
76        m.insert(Derive::Eq, "Eq".to_string());
77        m.insert(Derive::PartialEq, "PartialEq".to_string());
78        m
79    };
80}
81
82#[derive(Debug)]
83pub(crate) struct Generator {
84    // Generated Tokens for the module.
85    pub(crate) items: Vec<TokenStream>,
86
87    // A counter to uniquify certain names
88    pub(crate) counter: usize,
89
90    // Auxillary Items: These are structs/that are referenced inside constructed type.
91    pub(crate) aux_items: Vec<TokenStream>,
92
93    // Visibility: Visibility of Generated Items
94    pub(crate) visibility: Visibility,
95
96    // codecs
97    pub(crate) codecs: Vec<Codec>,
98
99    // Derives
100    pub(crate) derives: Vec<Derive>,
101}
102
103impl Generator {
104    pub(crate) fn new(visibility: &Visibility, codecs: Vec<Codec>, derives: Vec<Derive>) -> Self {
105        Generator {
106            items: vec![],
107            counter: 1,
108            aux_items: vec![],
109            visibility: visibility.clone(),
110            codecs,
111            derives,
112        }
113    }
114
115    // Generates the code using the information from the `Resolver`. Returns a String
116    // containing all the code (which is basically a `format!` of the `TokenStream`.
117    pub(crate) fn generate(&mut self, resolver: &Resolver) -> Result<String> {
118        // FIXME: Not sure how to make sure the crates defined here are a dependency.
119        // May be can just do with documenting it.
120
121        // First Get the 'consts' for builtin values.
122        let mut items = vec![];
123        for (k, v) in resolver.get_resolved_values() {
124            let item = Asn1ResolvedValue::generate_const_for_base_value(k, v, self)?;
125            if let Some(it) = item {
126                items.push(it)
127            }
128        }
129
130        // Now get the types
131        for (k, t) in resolver.get_resolved_types() {
132            let item = Asn1ResolvedType::generate_for_type(k, t, self)?;
133            if let Some(it) = item {
134                items.push(it)
135            }
136        }
137
138        for aux in &self.aux_items {
139            items.push(aux.clone())
140        }
141
142        self.items.extend(items);
143
144        Ok(self
145            .items
146            .iter()
147            .map(|t| t.to_string())
148            .collect::<Vec<String>>()
149            .join("\n\n"))
150    }
151
152    pub(crate) fn to_type_ident(&self, name: &str) -> Ident {
153        Ident::new(
154            &capitalize_first(name).replace(['-', ' '], "_"),
155            Span::call_site(),
156        )
157    }
158
159    pub(crate) fn to_const_ident(&self, name: &str) -> Ident {
160        Ident::new(&name.to_shouty_snake_case(), Span::call_site())
161    }
162
163    pub(crate) fn to_value_ident(&self, name: &str) -> Ident {
164        let mut val = capitalize_first(name).to_snake_case();
165        if val == *"type" {
166            val = "typ".to_string()
167        }
168        Ident::new(&val, Span::call_site())
169    }
170
171    pub(crate) fn to_inner_type(&self, bits: u8, signed: bool) -> TokenStream {
172        if !signed {
173            match bits {
174                8 => quote!(u8),
175                16 => quote!(u16),
176                32 => quote!(u32),
177                64 => quote!(u64),
178                _ => quote!(u64),
179            }
180        } else {
181            match bits {
182                8 => quote!(i8),
183                16 => quote!(i16),
184                32 => quote!(i32),
185                64 => quote!(i64),
186                _ => quote!(i64),
187            }
188        }
189    }
190
191    pub(crate) fn to_suffixed_literal(&self, bits: u8, signed: bool, value: i128) -> Literal {
192        if !signed {
193            match bits {
194                8 => Literal::u8_suffixed(value as u8),
195                16 => Literal::u16_suffixed(value as u16),
196                32 => Literal::u32_suffixed(value as u32),
197                64 => Literal::u64_suffixed(value as u64),
198                _ => Literal::u64_suffixed(value as u64),
199            }
200        } else {
201            match bits {
202                8 => Literal::i8_suffixed(value as i8),
203                16 => Literal::i16_suffixed(value as i16),
204                32 => Literal::i32_suffixed(value as i32),
205                64 => Literal::i64_suffixed(value as i64),
206                _ => Literal::i64_suffixed(value as i64),
207            }
208        }
209    }
210
211    pub(crate) fn get_unique_name(&mut self, name: &str) -> String {
212        self.counter += 1;
213
214        format!("{} {}", name, self.counter)
215    }
216
217    pub(crate) fn get_visibility_tokens(&self) -> TokenStream {
218        match self.visibility {
219            Visibility::Public => quote! { pub },
220            Visibility::Crate => quote! { pub(crate) },
221            Visibility::Private => quote! {},
222        }
223    }
224
225    pub(crate) fn generate_derive_tokens(&self) -> TokenStream {
226        let mut tokens = vec![];
227        for codec in &self.codecs {
228            let codec_token = CODEC_TOKENS.get(codec).unwrap();
229            tokens.push(codec_token.to_string());
230        }
231
232        for derive in &self.derives {
233            if derive == &Derive::All {
234                for derive_token in DERIVE_TOKENS.values() {
235                    tokens.push(derive_token.to_string());
236                }
237            } else {
238                let derive_token = DERIVE_TOKENS.get(derive).unwrap();
239                tokens.push(derive_token.to_string());
240            }
241        }
242
243        let token_string = tokens.join(",");
244
245        let derive_token_string = format!("#[derive({})]\n", token_string);
246        let derive_token_stream: TokenStream = derive_token_string.parse().unwrap();
247        derive_token_stream
248    }
249}
250
251fn capitalize_first(input: &str) -> String {
252    if !input.is_empty() {
253        let mut input = input.to_string();
254        let (first, _) = input.split_at_mut(1);
255        first.make_ascii_uppercase();
256
257        input
258    } else {
259        input.to_string()
260    }
261}
262
263#[cfg(test)]
264mod tests {
265
266    use super::*;
267
268    #[test]
269    fn test_capitalize_first_empty() {
270        let empty = "".to_string();
271        let capitalized = capitalize_first(&empty);
272        assert_eq!(capitalized, empty);
273    }
274
275    #[test]
276    fn test_capitalize_first_single_letter() {
277        let empty = "a".to_string();
278        let capitalized = capitalize_first(&empty);
279        assert_eq!(capitalized, "A");
280    }
281
282    #[test]
283    fn test_capitalize_first_word() {
284        let empty = "amfTnlAssociationToAddItem".to_string();
285        let capitalized = capitalize_first(&empty);
286        assert_eq!(capitalized, "AmfTnlAssociationToAddItem");
287    }
288}