use crate::{
ast,
error::ExtError as _,
ir::config::WhitelistedAttributes,
};
use syn::spanned::Spanned;
#[derive(Debug, Default, PartialEq, Eq)]
pub struct TraitDefinitionConfig {
namespace: Option<syn::LitStr>,
whitelisted_attributes: WhitelistedAttributes,
}
impl TraitDefinitionConfig {
#[cfg(test)]
pub fn with_namespace(mut self, namespace: &str) -> Self {
self.namespace =
Some(syn::LitStr::new(namespace, proc_macro2::Span::call_site()));
self
}
}
fn duplicate_config_err<F, S>(fst: F, snd: S, name: &str) -> syn::Error
where
F: Spanned,
S: Spanned,
{
format_err!(
snd.span(),
"encountered duplicate ink! trait definition `{}` configuration argument",
name,
)
.into_combine(format_err!(
fst.span(),
"first `{}` configuration argument here",
name
))
}
impl TryFrom<ast::AttributeArgs> for TraitDefinitionConfig {
type Error = syn::Error;
fn try_from(args: ast::AttributeArgs) -> Result<Self, Self::Error> {
let mut namespace: Option<(syn::LitStr, ast::MetaNameValue)> = None;
let mut whitelisted_attributes = WhitelistedAttributes::default();
for arg in args.into_iter() {
if arg.name.is_ident("namespace") {
if let Some((_, meta_name_value)) = namespace {
return Err(duplicate_config_err(meta_name_value, arg, "namespace"))
}
if let ast::PathOrLit::Lit(syn::Lit::Str(lit_str)) = &arg.value {
if syn::parse_str::<syn::Ident>(&lit_str.value()).is_err() {
return Err(format_err_spanned!(
lit_str,
"encountered invalid Rust identifier for the ink! namespace configuration parameter"
))
}
namespace = Some((lit_str.clone(), arg))
} else {
return Err(format_err_spanned!(
arg,
"expected a string literal for `namespace` ink! trait definition configuration argument",
))
}
} else if arg.name.is_ident("keep_attr") {
if let Err(err) = whitelisted_attributes.parse_arg_value(&arg) {
return Err(err)
}
} else {
return Err(format_err_spanned!(
arg,
"encountered unknown or unsupported ink! trait definition configuration argument",
))
}
}
Ok(TraitDefinitionConfig {
namespace: namespace.map(|(value, _)| value),
whitelisted_attributes,
})
}
}
impl TraitDefinitionConfig {
pub fn namespace(&self) -> Option<&syn::LitStr> {
self.namespace.as_ref()
}
pub fn whitelisted_attributes(&self) -> &WhitelistedAttributes {
&self.whitelisted_attributes
}
}