use super::super::{DeclStorageDefExt, StorageLineTypeDef};
use frame_support_procedural_tools::syn_ext as ext;
use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::spanned::Spanned;
pub struct BuilderDef {
pub blocks: Vec<TokenStream>,
pub is_generic: bool,
}
impl BuilderDef {
pub fn from_def(scrate: &TokenStream, def: &DeclStorageDefExt) -> Self {
let mut blocks = Vec::new();
let mut is_generic = false;
for line in def.storage_lines.iter() {
let storage_struct = &line.storage_struct;
let storage_trait = &line.storage_trait;
let value_type = &line.value_type;
let mut data = None;
if let Some(builder) = &line.build {
is_generic |= ext::expr_contains_ident(builder, &def.module_runtime_generic);
is_generic |= line.is_generic;
data = Some(match &line.storage_type {
StorageLineTypeDef::Simple(_) if line.is_option => {
quote_spanned!(builder.span() =>
let builder: fn(&Self) -> _ = #builder;
let data = builder(self);
let data = Option::as_ref(&data);
)
},
_ => quote_spanned!(builder.span() =>
let builder: fn(&Self) -> _ = #builder;
let data = &builder(self);
),
});
} else if let Some(config) = &line.config {
is_generic |= line.is_generic;
data = Some(match &line.storage_type {
StorageLineTypeDef::Simple(_) if line.is_option => {
quote!( let data = Some(&self.#config); )
},
_ => quote!( let data = &self.#config; ),
});
};
if let Some(data) = data {
blocks.push(match &line.storage_type {
StorageLineTypeDef::Simple(_) if line.is_option => {
quote! {{
#data
let v: Option<&#value_type>= data;
if let Some(v) = v {
<#storage_struct as #scrate::#storage_trait>::put::<&#value_type>(v);
}
}}
},
StorageLineTypeDef::Simple(_) if !line.is_option => {
quote! {{
#data
let v: &#value_type = data;
<#storage_struct as #scrate::#storage_trait>::put::<&#value_type>(v);
}}
},
StorageLineTypeDef::Simple(_) => unreachable!(),
StorageLineTypeDef::Map(map) => {
let key = &map.key;
quote! {{
#data
let data: &#scrate::sp_std::vec::Vec<(#key, #value_type)> = data;
data.iter().for_each(|(k, v)| {
<#storage_struct as #scrate::#storage_trait>::insert::<
&#key, &#value_type
>(k, v);
});
}}
},
StorageLineTypeDef::DoubleMap(map) => {
let key1 = &map.key1;
let key2 = &map.key2;
quote! {{
#data
let data: &#scrate::sp_std::vec::Vec<(#key1, #key2, #value_type)> = data;
data.iter().for_each(|(k1, k2, v)| {
<#storage_struct as #scrate::#storage_trait>::insert::<
&#key1, &#key2, &#value_type
>(k1, k2, v);
});
}}
},
StorageLineTypeDef::NMap(map) => {
let key_tuple = map.to_key_tuple();
let key_arg = if map.keys.len() == 1 { quote!((k,)) } else { quote!(k) };
quote! {{
#data
let data: &#scrate::sp_std::vec::Vec<(#key_tuple, #value_type)> = data;
data.iter().for_each(|(k, v)| {
<#storage_struct as #scrate::#storage_trait>::insert(#key_arg, v);
});
}}
},
});
}
}
if let Some(builder) = def.extra_genesis_build.as_ref() {
is_generic |= ext::expr_contains_ident(builder, &def.module_runtime_generic);
blocks.push(quote_spanned! { builder.span() =>
let extra_genesis_builder: fn(&Self) = #builder;
extra_genesis_builder(self);
});
}
Self { blocks, is_generic }
}
}