1use 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#[derive(clap::ValueEnum, Clone, Debug, PartialEq, Eq, Hash)]
18pub enum Codec {
19 Aper,
21
22 Uper,
24}
25
26#[derive(clap::ValueEnum, Clone, Debug, PartialEq, Eq, Hash)]
28pub enum Derive {
29 Debug,
32
33 Clone,
35
36 Serialize,
38
39 Deserialize,
41
42 Eq,
44
45 PartialEq,
47
48 All,
50}
51
52#[derive(clap::ValueEnum, Clone, Debug)]
54pub enum Visibility {
55 Public,
57 Crate,
59 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 pub(crate) items: Vec<TokenStream>,
86
87 pub(crate) counter: usize,
89
90 pub(crate) aux_items: Vec<TokenStream>,
92
93 pub(crate) visibility: Visibility,
95
96 pub(crate) codecs: Vec<Codec>,
98
99 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 pub(crate) fn generate(&mut self, resolver: &Resolver) -> Result<String> {
118 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 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}