use heck::{ShoutySnakeCase, SnakeCase};
use proc_macro2::{Ident, Literal, Span, TokenStream};
use quote::quote;
use crate::error::Error;
use crate::resolver::Resolver;
use crate::resolver::asn::structs::types::Asn1ResolvedType;
#[derive(Debug)]
pub(crate) struct Generator {
pub(crate) items: Vec<TokenStream>,
pub(crate) name: String,
pub(crate) counter: usize,
pub(crate) aux_items: Vec<TokenStream>,
}
impl Generator {
pub(crate) fn new(name: &str) -> Self {
Generator {
items: vec![],
name: name.to_string(),
counter: 1,
aux_items: vec![],
}
}
pub(crate) fn generate(&mut self, resolver: &Resolver) -> Result<String, Error> {
let use_tokens = self.generate_use_tokens();
self.items.push(use_tokens);
let mut items = vec![];
for (k, t) in resolver.get_resolved_types() {
let item = Asn1ResolvedType::generate_for_type(k, t, self)?;
if item.is_some() {
items.push(item.unwrap())
}
}
for aux in &self.aux_items {
items.push(aux.clone())
}
self.items.extend(items);
Ok(format!(
"{}",
self.items
.iter()
.map(|t| t.to_string())
.collect::<Vec<String>>()
.join("\n\n")
))
}
pub(crate) fn to_type_ident(&self, name: &str) -> Ident {
Ident::new(&name.replace("-", "_").replace(" ", "_"), Span::call_site())
}
pub(crate) fn to_const_ident(&self, name: &str) -> Ident {
Ident::new(&name.to_shouty_snake_case(), Span::call_site())
}
pub(crate) fn to_value_ident(&self, name: &str) -> Ident {
let mut val = name.to_snake_case();
if val == "type".to_string() {
val = "typ".to_string()
}
Ident::new(&val, Span::call_site())
}
pub(crate) fn to_inner_type(&self, bits: u8, signed: bool) -> TokenStream {
if !signed {
match bits {
8 => quote!(u8),
16 => quote!(u16),
32 => quote!(u32),
64 => quote!(u64),
_ => quote!(u64),
}
} else {
match bits {
8 => quote!(i8),
16 => quote!(i16),
32 => quote!(i32),
64 => quote!(i64),
_ => quote!(i64),
}
}
}
pub(crate) fn to_suffixed_literal(&self, bits: u8, signed: bool, value: i128) -> Literal {
if !signed {
match bits {
8 => Literal::u8_suffixed(value as u8),
16 => Literal::u16_suffixed(value as u16),
32 => Literal::u32_suffixed(value as u32),
64 => Literal::u64_suffixed(value as u64),
_ => Literal::u64_suffixed(value as u64),
}
} else {
match bits {
8 => Literal::i8_suffixed(value as i8),
16 => Literal::i16_suffixed(value as i16),
32 => Literal::i32_suffixed(value as i32),
64 => Literal::i64_suffixed(value as i64),
_ => Literal::i64_suffixed(value as i64),
}
}
}
pub(crate) fn to_unique_name(&mut self, name: &str) -> String {
self.counter += 1;
format!("{} {}", name, self.counter)
}
fn generate_use_tokens(&self) -> TokenStream {
quote! {
#![allow(dead_code, unreachable_patterns, non_camel_case_types)]
use bitvec::vec::BitVec;
use bitvec::order::Msb0;
use asn1_codecs_derive::AperCodec;
}
}
}