use convert_case::{Case, Casing};
use proc_macro2::TokenStream as TokenStream2;
use quote::{format_ident, quote};
use syn::Ident as Ident2;
use toml::value::Array;
use toml::Table;
use crate::parse::StaticTomlAttributes;
use crate::toml_tokens::TomlTokens;
#[inline]
pub(crate) fn array(
array: &Array,
key: &str,
config: &StaticTomlAttributes,
namespace: &mut Vec<Ident2>,
namespace_ts: TokenStream2
) -> Result<TokenStream2, super::super::TomlError> {
let use_slices = super::use_slices(array, config);
let values_ident = [config
.values_ident
.as_ref()
.map(Ident2::to_string)
.unwrap_or_else(|| String::from("values"))];
let key_iter: Box<dyn Iterator<Item = String>> = match use_slices {
true => Box::new(values_ident.iter().cycle().cloned()),
false => Box::new(
values_ident
.iter()
.cycle()
.enumerate()
.map(|(i, v)| format!("{v}{i}"))
)
};
let inner: Vec<TokenStream2> = array
.iter()
.zip(key_iter)
.map(|(v, k)| {
namespace.push(format_ident!("{}", k.to_case(Case::Snake)));
let value = v.static_tokens(&k, config, namespace);
namespace.pop();
value
})
.collect::<Result<Vec<TokenStream2>, super::super::TomlError>>()?;
let type_ident = super::fixed_ident(key, &config.prefix, &config.suffix);
Ok(match (use_slices, config.cow) {
(true, None) => quote!([#(#inner),*]),
(true, Some(_)) => quote!(std::borrow::Cow::Borrowed(&[#(#inner),*])),
(false, _) => quote!(#namespace_ts::#type_ident(#(#inner),*))
})
}
#[inline]
pub(crate) fn table(
table: &Table,
key: &str,
config: &StaticTomlAttributes,
namespace: &mut Vec<Ident2>,
namespace_ts: TokenStream2
) -> Result<TokenStream2, super::super::TomlError> {
let inner: Vec<(Ident2, TokenStream2)> = table
.iter()
.map(|(k, v)| {
if !super::is_valid_identifier(k.to_case(Case::Snake).as_str()) {
return Err(super::super::TomlError::KeyInvalid(k.to_string()));
}
let field_key = format_ident!("{}", k.to_case(Case::Snake));
namespace.push(field_key.clone());
let value = (field_key, v.static_tokens(k, config, namespace));
namespace.pop();
match value {
(ident, Ok(ts)) => Ok((ident, ts)),
(_, Err(e)) => Err(e)
}
})
.collect::<Result<Vec<(Ident2, TokenStream2)>, super::super::TomlError>>()?;
let field_keys: Vec<&Ident2> = inner.iter().map(|(k, _)| k).collect();
let field_values: Vec<&TokenStream2> = inner.iter().map(|(_, v)| v).collect();
let type_ident = super::fixed_ident(key, &config.prefix, &config.suffix);
Ok(quote! {
#namespace_ts::#type_ident {
#(#field_keys: #field_values),*
}
})
}