use super::helper;
use frame_support_procedural_tools::get_doc_literals;
use syn::spanned::Spanned;
mod keyword {
syn::custom_keyword!(DispatchResultWithPostInfo);
syn::custom_keyword!(Call);
syn::custom_keyword!(OriginFor);
syn::custom_keyword!(weight);
syn::custom_keyword!(compact);
syn::custom_keyword!(T);
syn::custom_keyword!(pallet);
syn::custom_keyword!(constant_name);
}
pub struct ExtraConstantsDef {
pub where_clause: Option<syn::WhereClause>,
pub instances: Vec<helper::InstanceUsage>,
pub extra_constants: Vec<ExtraConstantDef>,
}
pub struct ExtraConstantDef {
pub ident: syn::Ident,
pub type_: syn::Type,
pub doc: Vec<syn::Expr>,
pub metadata_name: Option<syn::Ident>,
pub attrs: Vec<syn::Attribute>,
}
pub struct ExtraConstAttr {
metadata_name: syn::Ident,
}
impl syn::parse::Parse for ExtraConstAttr {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
input.parse::<syn::Token![#]>()?;
let content;
syn::bracketed!(content in input);
content.parse::<keyword::pallet>()?;
content.parse::<syn::Token![::]>()?;
content.parse::<keyword::constant_name>()?;
let metadata_name;
syn::parenthesized!(metadata_name in content);
Ok(ExtraConstAttr { metadata_name: metadata_name.parse::<syn::Ident>()? })
}
}
impl ExtraConstantsDef {
pub fn try_from(item: &mut syn::Item) -> syn::Result<Self> {
let item = if let syn::Item::Impl(item) = item {
item
} else {
return Err(syn::Error::new(
item.span(),
"Invalid pallet::extra_constants, expected item impl",
));
};
let instances = vec![
helper::check_impl_gen(&item.generics, item.impl_token.span())?,
helper::check_pallet_struct_usage(&item.self_ty)?,
];
if let Some((_, _, for_)) = item.trait_ {
let msg = "Invalid pallet::call, expected no trait ident as in \
`impl<..> Pallet<..> { .. }`";
return Err(syn::Error::new(for_.span(), msg));
}
let mut extra_constants = vec![];
for impl_item in &mut item.items {
let method = if let syn::ImplItem::Fn(method) = impl_item {
method
} else {
let msg = "Invalid pallet::call, only method accepted";
return Err(syn::Error::new(impl_item.span(), msg));
};
if !method.sig.inputs.is_empty() {
let msg = "Invalid pallet::extra_constants, method must have 0 args";
return Err(syn::Error::new(method.sig.span(), msg));
}
if !method.sig.generics.params.is_empty() {
let msg = "Invalid pallet::extra_constants, method must have 0 generics";
return Err(syn::Error::new(method.sig.generics.params[0].span(), msg));
}
if method.sig.generics.where_clause.is_some() {
let msg = "Invalid pallet::extra_constants, method must have no where clause";
return Err(syn::Error::new(method.sig.generics.where_clause.span(), msg));
}
let type_ = match &method.sig.output {
syn::ReturnType::Default => {
let msg = "Invalid pallet::extra_constants, method must have a return type";
return Err(syn::Error::new(method.span(), msg));
},
syn::ReturnType::Type(_, type_) => *type_.clone(),
};
let mut extra_constant_attrs: Vec<ExtraConstAttr> =
helper::take_item_pallet_attrs(method)?;
if extra_constant_attrs.len() > 1 {
let msg =
"Invalid attribute in pallet::constant_name, only one attribute is expected";
return Err(syn::Error::new(extra_constant_attrs[1].metadata_name.span(), msg));
}
let metadata_name = extra_constant_attrs.pop().map(|attr| attr.metadata_name);
extra_constants.push(ExtraConstantDef {
ident: method.sig.ident.clone(),
type_,
doc: get_doc_literals(&method.attrs),
metadata_name,
attrs: method.attrs.clone(),
});
}
Ok(Self { instances, where_clause: item.generics.where_clause.clone(), extra_constants })
}
}