use crate::construct_runtime::Pallet;
use inflector::Inflector;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens};
use std::str::FromStr;
use syn::Ident;
pub fn expand_outer_config(
runtime: &Ident,
pallet_decls: &[Pallet],
scrate: &TokenStream,
) -> TokenStream {
let mut types = TokenStream::new();
let mut fields = TokenStream::new();
let mut build_storage_calls = TokenStream::new();
let mut query_genesis_config_part_macros = Vec::new();
for decl in pallet_decls {
if let Some(pallet_entry) = decl.find_part("Config") {
let path = &decl.path;
let pallet_name = &decl.name;
let path_str = path.into_token_stream().to_string();
let config = format_ident!("{}Config", pallet_name);
let field_name =
&Ident::new(&pallet_name.to_string().to_snake_case(), decl.name.span());
let part_is_generic = !pallet_entry.generics.params.is_empty();
let attr = &decl.cfg_pattern.iter().fold(TokenStream::new(), |acc, pattern| {
let attr = TokenStream::from_str(&format!("#[cfg({})]", pattern.original()))
.expect("was successfully parsed before; qed");
quote! {
#acc
#attr
}
});
types.extend(expand_config_types(attr, runtime, decl, &config, part_is_generic));
fields.extend(quote!(#attr pub #field_name: #config,));
build_storage_calls
.extend(expand_config_build_storage_call(scrate, attr, runtime, decl, field_name));
query_genesis_config_part_macros.push(quote! {
#path::__substrate_genesis_config_check::is_genesis_config_defined!(#pallet_name);
#[cfg(feature = "std")]
#path::__substrate_genesis_config_check::is_std_enabled_for_genesis!(#pallet_name, #path_str);
});
}
}
quote! {
#( #query_genesis_config_part_macros )*
#types
#[cfg(any(feature = "std", test))]
use #scrate::serde as __genesis_config_serde_import__;
#[cfg(any(feature = "std", test))]
#[derive(#scrate::serde::Serialize, #scrate::serde::Deserialize, Default)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
#[serde(crate = "__genesis_config_serde_import__")]
pub struct GenesisConfig {
#fields
}
#[cfg(any(feature = "std", test))]
impl #scrate::sp_runtime::BuildStorage for GenesisConfig {
fn assimilate_storage(
&self,
storage: &mut #scrate::sp_runtime::Storage,
) -> std::result::Result<(), String> {
#build_storage_calls
#scrate::BasicExternalities::execute_with_storage(storage, || {
<AllPalletsWithSystem as #scrate::traits::OnGenesis>::on_genesis();
});
Ok(())
}
}
}
}
fn expand_config_types(
attr: &TokenStream,
runtime: &Ident,
decl: &Pallet,
config: &Ident,
part_is_generic: bool,
) -> TokenStream {
let path = &decl.path;
match (decl.instance.as_ref(), part_is_generic) {
(Some(inst), true) => quote! {
#attr
#[cfg(any(feature = "std", test))]
pub type #config = #path::GenesisConfig<#runtime, #path::#inst>;
},
(None, true) => quote! {
#attr
#[cfg(any(feature = "std", test))]
pub type #config = #path::GenesisConfig<#runtime>;
},
(_, false) => quote! {
#attr
#[cfg(any(feature = "std", test))]
pub type #config = #path::GenesisConfig;
},
}
}
fn expand_config_build_storage_call(
scrate: &TokenStream,
attr: &TokenStream,
runtime: &Ident,
decl: &Pallet,
field_name: &Ident,
) -> TokenStream {
let path = &decl.path;
let instance = if let Some(inst) = decl.instance.as_ref() {
quote!(#path::#inst)
} else {
quote!(#path::__InherentHiddenInstance)
};
quote! {
#attr
#scrate::sp_runtime::BuildModuleGenesisStorage::
<#runtime, #instance>::build_module_genesis_storage(&self.#field_name, storage)?;
}
}