use crate::{
counter_prefix,
pallet::{
parse::{
helper::two128_str,
storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
},
Def,
},
};
use quote::ToTokens;
use std::{collections::HashMap, ops::IndexMut};
use syn::spanned::Spanned;
fn prefix_ident(storage: &StorageDef) -> syn::Ident {
let storage_ident = &storage.ident;
syn::Ident::new(&format!("_GeneratedPrefixForStorage{}", storage_ident), storage_ident.span())
}
fn counter_prefix_ident(storage_ident: &syn::Ident) -> syn::Ident {
syn::Ident::new(
&format!("_GeneratedCounterPrefixForStorage{}", storage_ident),
storage_ident.span(),
)
}
fn check_prefix_duplicates(
storage_def: &StorageDef,
used_prefixes: &mut HashMap<String, syn::Error>,
) -> syn::Result<()> {
let prefix = storage_def.prefix();
let dup_err = syn::Error::new(
storage_def.prefix_span(),
format!("Duplicate storage prefixes found for `{}`", prefix),
);
if let Some(other_dup_err) = used_prefixes.insert(prefix.clone(), dup_err.clone()) {
let mut err = dup_err;
err.combine(other_dup_err);
return Err(err);
}
if let Metadata::CountedMap { .. } = storage_def.metadata {
let counter_prefix = counter_prefix(&prefix);
let counter_dup_err = syn::Error::new(
storage_def.prefix_span(),
format!(
"Duplicate storage prefixes found for `{}`, used for counter associated to \
counted storage map",
counter_prefix,
),
);
if let Some(other_dup_err) = used_prefixes.insert(counter_prefix, counter_dup_err.clone()) {
let mut err = counter_dup_err;
err.combine(other_dup_err);
return Err(err);
}
}
Ok(())
}
pub struct ResultOnEmptyStructMetadata {
pub name: syn::Ident,
pub error_path: syn::Path,
pub visibility: syn::Visibility,
pub value_ty: syn::Type,
pub variant_name: syn::Ident,
pub span: proc_macro2::Span,
}
pub fn process_generics(def: &mut Def) -> syn::Result<Vec<ResultOnEmptyStructMetadata>> {
let frame_support = &def.frame_support;
let mut on_empty_struct_metadata = Vec::new();
for storage_def in def.storages.iter_mut() {
let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage_def.index];
let typ_item = match item {
syn::Item::Type(t) => t,
_ => unreachable!("Checked by def"),
};
typ_item.attrs.push(syn::parse_quote!(#[allow(type_alias_bounds)]));
let typ_path = match &mut *typ_item.ty {
syn::Type::Path(p) => p,
_ => unreachable!("Checked by def"),
};
let args = match &mut typ_path.path.segments[0].arguments {
syn::PathArguments::AngleBracketed(args) => args,
_ => unreachable!("Checked by def"),
};
let prefix_ident = prefix_ident(storage_def);
let type_use_gen = if def.config.has_instance {
quote::quote_spanned!(storage_def.attr_span => T, I)
} else {
quote::quote_spanned!(storage_def.attr_span => T)
};
let default_query_kind: syn::Type =
syn::parse_quote!(#frame_support::storage::types::OptionQuery);
let mut default_on_empty = |value_ty: syn::Type| -> syn::Type {
if let Some(QueryKind::ResultQuery(error_path, variant_name)) =
storage_def.query_kind.as_ref()
{
let on_empty_ident =
quote::format_ident!("__Frame_Internal_Get{}Result", storage_def.ident);
on_empty_struct_metadata.push(ResultOnEmptyStructMetadata {
name: on_empty_ident.clone(),
visibility: storage_def.vis.clone(),
value_ty,
error_path: error_path.clone(),
variant_name: variant_name.clone(),
span: storage_def.attr_span,
});
return syn::parse_quote!(#on_empty_ident);
}
syn::parse_quote!(#frame_support::traits::GetDefault)
};
let default_max_values: syn::Type = syn::parse_quote!(#frame_support::traits::GetDefault);
let set_result_query_type_parameter = |query_type: &mut syn::Type| -> syn::Result<()> {
if let Some(QueryKind::ResultQuery(error_path, _)) = storage_def.query_kind.as_ref() {
if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) =
query_type
{
if let Some(seg) = segments.last_mut() {
if let syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments { args, .. },
) = &mut seg.arguments
{
args.clear();
args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)));
}
}
} else {
let msg = format!(
"Invalid pallet::storage, unexpected type for query, expected ResultQuery \
with 1 type parameter, found `{}`",
query_type.to_token_stream().to_string()
);
return Err(syn::Error::new(query_type.span(), msg));
}
}
Ok(())
};
if let Some(named_generics) = storage_def.named_generics.clone() {
args.args.clear();
args.args.push(syn::parse_quote!( #prefix_ident<#type_use_gen> ));
match named_generics {
StorageGenerics::Value { value, query_kind, on_empty } => {
args.args.push(syn::GenericArgument::Type(value.clone()));
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
set_result_query_type_parameter(&mut query_kind)?;
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
args.args.push(syn::GenericArgument::Type(on_empty));
},
StorageGenerics::Map { hasher, key, value, query_kind, on_empty, max_values } |
StorageGenerics::CountedMap {
hasher,
key,
value,
query_kind,
on_empty,
max_values,
} => {
args.args.push(syn::GenericArgument::Type(hasher));
args.args.push(syn::GenericArgument::Type(key));
args.args.push(syn::GenericArgument::Type(value.clone()));
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
set_result_query_type_parameter(&mut query_kind)?;
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
args.args.push(syn::GenericArgument::Type(on_empty));
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
args.args.push(syn::GenericArgument::Type(max_values));
},
StorageGenerics::DoubleMap {
hasher1,
key1,
hasher2,
key2,
value,
query_kind,
on_empty,
max_values,
} => {
args.args.push(syn::GenericArgument::Type(hasher1));
args.args.push(syn::GenericArgument::Type(key1));
args.args.push(syn::GenericArgument::Type(hasher2));
args.args.push(syn::GenericArgument::Type(key2));
args.args.push(syn::GenericArgument::Type(value.clone()));
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
set_result_query_type_parameter(&mut query_kind)?;
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
args.args.push(syn::GenericArgument::Type(on_empty));
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
args.args.push(syn::GenericArgument::Type(max_values));
},
StorageGenerics::NMap { keygen, value, query_kind, on_empty, max_values } |
StorageGenerics::CountedNMap {
keygen,
value,
query_kind,
on_empty,
max_values,
} => {
args.args.push(syn::GenericArgument::Type(keygen));
args.args.push(syn::GenericArgument::Type(value.clone()));
let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
set_result_query_type_parameter(&mut query_kind)?;
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
args.args.push(syn::GenericArgument::Type(on_empty));
let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
args.args.push(syn::GenericArgument::Type(max_values));
},
}
} else {
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
let (value_idx, query_idx, on_empty_idx) = match storage_def.metadata {
Metadata::Value { .. } => (1, 2, 3),
Metadata::NMap { .. } | Metadata::CountedNMap { .. } => (2, 3, 4),
Metadata::Map { .. } | Metadata::CountedMap { .. } => (3, 4, 5),
Metadata::DoubleMap { .. } => (5, 6, 7),
};
if storage_def.use_default_hasher {
let hasher_indices: Vec<usize> = match storage_def.metadata {
Metadata::Map { .. } | Metadata::CountedMap { .. } => vec![1],
Metadata::DoubleMap { .. } => vec![1, 3],
_ => vec![],
};
for hasher_idx in hasher_indices {
args.args[hasher_idx] = syn::GenericArgument::Type(
syn::parse_quote!(#frame_support::Blake2_128Concat),
);
}
}
if query_idx < args.args.len() {
if let syn::GenericArgument::Type(query_kind) = args.args.index_mut(query_idx) {
set_result_query_type_parameter(query_kind)?;
}
} else if let Some(QueryKind::ResultQuery(error_path, _)) =
storage_def.query_kind.as_ref()
{
args.args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)))
}
if on_empty_idx >= args.args.len() &&
matches!(storage_def.query_kind.as_ref(), Some(QueryKind::ResultQuery(_, _)))
{
let value_ty = match args.args[value_idx].clone() {
syn::GenericArgument::Type(ty) => ty,
_ => unreachable!(),
};
let on_empty = default_on_empty(value_ty);
args.args.push(syn::GenericArgument::Type(on_empty));
}
}
}
Ok(on_empty_struct_metadata)
}
fn augment_final_docs(def: &mut Def) {
let mut push_string_literal = |doc_line: &str, storage: &mut StorageDef| {
let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage.index];
let typ_item = match item {
syn::Item::Type(t) => t,
_ => unreachable!("Checked by def"),
};
typ_item.attrs.push(syn::parse_quote!(#[doc = ""]));
typ_item.attrs.push(syn::parse_quote!(#[doc = #doc_line]));
};
def.storages.iter_mut().for_each(|storage| match &storage.metadata {
Metadata::Value { value } => {
let doc_line = format!(
"Storage type is [`StorageValue`] with value type `{}`.",
value.to_token_stream()
);
push_string_literal(&doc_line, storage);
},
Metadata::Map { key, value } => {
let doc_line = format!(
"Storage type is [`StorageMap`] with key type `{}` and value type `{}`.",
key.to_token_stream(),
value.to_token_stream()
);
push_string_literal(&doc_line, storage);
},
Metadata::DoubleMap { key1, key2, value } => {
let doc_line = format!(
"Storage type is [`StorageDoubleMap`] with key1 type {}, key2 type {} and value type {}.",
key1.to_token_stream(),
key2.to_token_stream(),
value.to_token_stream()
);
push_string_literal(&doc_line, storage);
},
Metadata::NMap { keys, value, .. } => {
let doc_line = format!(
"Storage type is [`StorageNMap`] with keys type ({}) and value type {}.",
keys.iter()
.map(|k| k.to_token_stream().to_string())
.collect::<Vec<_>>()
.join(", "),
value.to_token_stream()
);
push_string_literal(&doc_line, storage);
},
Metadata::CountedNMap { keys, value, .. } => {
let doc_line = format!(
"Storage type is [`CountedStorageNMap`] with keys type ({}) and value type {}.",
keys.iter()
.map(|k| k.to_token_stream().to_string())
.collect::<Vec<_>>()
.join(", "),
value.to_token_stream()
);
push_string_literal(&doc_line, storage);
},
Metadata::CountedMap { key, value } => {
let doc_line = format!(
"Storage type is [`CountedStorageMap`] with key type {} and value type {}.",
key.to_token_stream(),
value.to_token_stream()
);
push_string_literal(&doc_line, storage);
},
});
}
pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
let on_empty_struct_metadata = match process_generics(def) {
Ok(idents) => idents,
Err(e) => return e.into_compile_error(),
};
augment_final_docs(def);
let mut prefix_set = HashMap::new();
let mut errors = def
.storages
.iter()
.filter_map(|storage_def| check_prefix_duplicates(storage_def, &mut prefix_set).err());
if let Some(mut final_error) = errors.next() {
errors.for_each(|error| final_error.combine(error));
return final_error.into_compile_error();
}
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let pallet_ident = &def.pallet_struct.pallet;
let mut entries_builder = vec![];
for storage in def.storages.iter() {
let no_docs = vec![];
let docs = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &storage.docs };
let ident = &storage.ident;
let gen = &def.type_use_generics(storage.attr_span);
let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
let cfg_attrs = &storage.cfg_attrs;
let deprecation = match crate::deprecation::get_deprecation(
"e::quote! { #frame_support },
&storage.attrs,
) {
Ok(deprecation) => deprecation,
Err(e) => return e.into_compile_error(),
};
entries_builder.push(quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
{
<#full_ident as #frame_support::storage::StorageEntryMetadataBuilder>::build_metadata(
#deprecation,
#frame_support::__private::vec![
#( #docs, )*
],
&mut entries,
);
}
))
}
let getters = def.storages.iter().map(|storage| {
if let Some(getter) = &storage.getter {
let completed_where_clause =
super::merge_where_clauses(&[&storage.where_clause, &def.config.where_clause]);
let ident = &storage.ident;
let gen = &def.type_use_generics(storage.attr_span);
let type_impl_gen = &def.type_impl_generics(storage.attr_span);
let type_use_gen = &def.type_use_generics(storage.attr_span);
let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
let cfg_attrs = &storage.cfg_attrs;
let getter_doc_line = if matches!(storage.vis, syn::Visibility::Public(_)) {
format!("An auto-generated getter for [`{}`].", storage.ident)
} else {
format!("An auto-generated getter for `{}`.", storage.ident)
};
match &storage.metadata {
Metadata::Value { value } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
Option<#value>
),
QueryKind::ResultQuery(error_path, _) => {
quote::quote_spanned!(storage.attr_span =>
Result<#value, #error_path>
)
},
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#[doc = #getter_doc_line]
pub fn #getter() -> #query {
<
#full_ident as #frame_support::storage::StorageValue<#value>
>::get()
}
}
)
},
Metadata::Map { key, value } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
Option<#value>
),
QueryKind::ResultQuery(error_path, _) => {
quote::quote_spanned!(storage.attr_span =>
Result<#value, #error_path>
)
},
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#[doc = #getter_doc_line]
pub fn #getter<KArg>(k: KArg) -> #query where
KArg: #frame_support::__private::codec::EncodeLike<#key>,
{
<
#full_ident as #frame_support::storage::StorageMap<#key, #value>
>::get(k)
}
}
)
},
Metadata::CountedMap { key, value } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
Option<#value>
),
QueryKind::ResultQuery(error_path, _) => {
quote::quote_spanned!(storage.attr_span =>
Result<#value, #error_path>
)
},
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#[doc = #getter_doc_line]
pub fn #getter<KArg>(k: KArg) -> #query where
KArg: #frame_support::__private::codec::EncodeLike<#key>,
{
<#full_ident>::get(k)
}
}
)
},
Metadata::DoubleMap { key1, key2, value } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
Option<#value>
),
QueryKind::ResultQuery(error_path, _) => {
quote::quote_spanned!(storage.attr_span =>
Result<#value, #error_path>
)
},
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#[doc = #getter_doc_line]
pub fn #getter<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #query where
KArg1: #frame_support::__private::codec::EncodeLike<#key1>,
KArg2: #frame_support::__private::codec::EncodeLike<#key2>,
{
<
#full_ident as
#frame_support::storage::StorageDoubleMap<#key1, #key2, #value>
>::get(k1, k2)
}
}
)
},
Metadata::NMap { keygen, value, .. } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
Option<#value>
),
QueryKind::ResultQuery(error_path, _) => {
quote::quote_spanned!(storage.attr_span =>
Result<#value, #error_path>
)
},
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#[doc = #getter_doc_line]
pub fn #getter<KArg>(key: KArg) -> #query
where
KArg: #frame_support::storage::types::EncodeLikeTuple<
<#keygen as #frame_support::storage::types::KeyGenerator>::KArg
>
+ #frame_support::storage::types::TupleToEncodedIter,
{
<
#full_ident as
#frame_support::storage::StorageNMap<#keygen, #value>
>::get(key)
}
}
)
},
Metadata::CountedNMap { keygen, value, .. } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
Option<#value>
),
QueryKind::ResultQuery(error_path, _) => {
quote::quote_spanned!(storage.attr_span =>
Result<#value, #error_path>
)
},
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(storage.attr_span =>
#(#cfg_attrs)*
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#[doc = #getter_doc_line]
pub fn #getter<KArg>(key: KArg) -> #query
where
KArg: #frame_support::storage::types::EncodeLikeTuple<
<#keygen as #frame_support::storage::types::KeyGenerator>::KArg
>
+ #frame_support::storage::types::TupleToEncodedIter,
{
<#full_ident>::get(key)
}
}
)
},
}
} else {
Default::default()
}
});
let prefix_structs = def.storages.iter().map(|storage_def| {
let type_impl_gen = &def.type_impl_generics(storage_def.attr_span);
let type_use_gen = &def.type_use_generics(storage_def.attr_span);
let prefix_struct_ident = prefix_ident(storage_def);
let prefix_struct_vis = &storage_def.vis;
let prefix_struct_const = storage_def.prefix();
let config_where_clause = &def.config.where_clause;
let cfg_attrs = &storage_def.cfg_attrs;
let maybe_counter = match storage_def.metadata {
Metadata::CountedMap { .. } => {
let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span =>
#(#cfg_attrs)*
#[doc(hidden)]
#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
core::marker::PhantomData<(#type_use_gen,)>
);
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::traits::StorageInstance
for #counter_prefix_struct_ident<#type_use_gen>
#config_where_clause
{
fn pallet_prefix() -> &'static str {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
fn pallet_prefix_hash() -> [u8; 16] {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name_hash::<Pallet<#type_use_gen>>()
.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::storage::types::CountedStorageMapInstance
for #prefix_struct_ident<#type_use_gen>
#config_where_clause
{
type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
}
)
},
Metadata::CountedNMap { .. } => {
let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span =>
#(#cfg_attrs)*
#[doc(hidden)]
#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
core::marker::PhantomData<(#type_use_gen,)>
);
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::traits::StorageInstance
for #counter_prefix_struct_ident<#type_use_gen>
#config_where_clause
{
fn pallet_prefix() -> &'static str {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
fn pallet_prefix_hash() -> [u8; 16] {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name_hash::<Pallet<#type_use_gen>>()
.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::storage::types::CountedStorageNMapInstance
for #prefix_struct_ident<#type_use_gen>
#config_where_clause
{
type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
}
)
},
_ => proc_macro2::TokenStream::default(),
};
let storage_prefix_hash = two128_str(&prefix_struct_const);
quote::quote_spanned!(storage_def.attr_span =>
#maybe_counter
#(#cfg_attrs)*
#[doc(hidden)]
#prefix_struct_vis struct #prefix_struct_ident<#type_use_gen>(
core::marker::PhantomData<(#type_use_gen,)>
);
#(#cfg_attrs)*
impl<#type_impl_gen> #frame_support::traits::StorageInstance
for #prefix_struct_ident<#type_use_gen>
#config_where_clause
{
fn pallet_prefix() -> &'static str {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name::<Pallet<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
fn pallet_prefix_hash() -> [u8; 16] {
<
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::name_hash::<Pallet<#type_use_gen>>()
.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
}
const STORAGE_PREFIX: &'static str = #prefix_struct_const;
fn storage_prefix_hash() -> [u8; 16] {
#storage_prefix_hash
}
}
)
});
let on_empty_structs = on_empty_struct_metadata.into_iter().map(|metadata| {
use crate::pallet::parse::GenericKind;
use syn::{GenericArgument, Path, PathArguments, PathSegment, Type, TypePath};
let ResultOnEmptyStructMetadata {
name,
visibility,
value_ty,
error_path,
variant_name,
span,
} = metadata;
let generic_kind = match error_path.segments.last() {
Some(PathSegment { arguments: PathArguments::AngleBracketed(args), .. }) => {
let (has_config, has_instance) =
args.args.iter().fold((false, false), |(has_config, has_instance), arg| {
match arg {
GenericArgument::Type(Type::Path(TypePath {
path: Path { segments, .. },
..
})) => {
let maybe_config =
segments.first().map_or(false, |seg| seg.ident == "T");
let maybe_instance =
segments.first().map_or(false, |seg| seg.ident == "I");
(has_config || maybe_config, has_instance || maybe_instance)
},
_ => (has_config, has_instance),
}
});
GenericKind::from_gens(has_config, has_instance).unwrap_or(GenericKind::None)
},
_ => GenericKind::None,
};
let type_impl_gen = generic_kind.type_impl_gen(proc_macro2::Span::call_site());
let config_where_clause = &def.config.where_clause;
quote::quote_spanned!(span =>
#[doc(hidden)]
#[allow(non_camel_case_types)]
#visibility struct #name;
impl<#type_impl_gen> #frame_support::traits::Get<Result<#value_ty, #error_path>>
for #name
#config_where_clause
{
fn get() -> Result<#value_ty, #error_path> {
Err(<#error_path>::#variant_name)
}
}
)
});
let mut where_clauses = vec![&def.config.where_clause];
where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause));
let completed_where_clause = super::merge_where_clauses(&where_clauses);
let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
let try_decode_entire_state = {
let mut storage_names = def
.storages
.iter()
.filter_map(|storage| {
if storage.try_decode && storage.cfg_attrs.is_empty() {
let ident = &storage.ident;
let gen = &def.type_use_generics(storage.attr_span);
Some(quote::quote_spanned!(storage.attr_span => #ident<#gen> ))
} else {
None
}
})
.collect::<Vec<_>>();
storage_names.sort_by_cached_key(|ident| ident.to_string());
quote::quote!(
#frame_support::try_runtime_enabled! {
impl<#type_impl_gen> #frame_support::traits::TryDecodeEntireStorage
for #pallet_ident<#type_use_gen> #completed_where_clause
{
fn try_decode_entire_state() -> Result<usize, #frame_support::__private::Vec<#frame_support::traits::TryDecodeEntireStorageError>> {
let pallet_name = <<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo>
::name::<#pallet_ident<#type_use_gen>>()
.expect("Every active pallet has a name in the runtime; qed");
#frame_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode pallet: {pallet_name}");
let mut errors = #frame_support::__private::Vec::new();
let mut decoded = 0usize;
#(
#frame_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode storage: \
{pallet_name}::{}", stringify!(#storage_names));
match <#storage_names as #frame_support::traits::TryDecodeEntireStorage>::try_decode_entire_state() {
Ok(count) => {
decoded += count;
},
Err(err) => {
errors.extend(err);
},
}
)*
if errors.is_empty() {
Ok(decoded)
} else {
Err(errors)
}
}
}
}
)
};
quote::quote!(
impl<#type_impl_gen> #pallet_ident<#type_use_gen>
#completed_where_clause
{
#[doc(hidden)]
pub fn storage_metadata() -> #frame_support::__private::metadata_ir::PalletStorageMetadataIR {
#frame_support::__private::metadata_ir::PalletStorageMetadataIR {
prefix: <
<T as #frame_system::Config>::PalletInfo as
#frame_support::traits::PalletInfo
>::name::<#pallet_ident<#type_use_gen>>()
.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`."),
entries: {
#[allow(unused_mut)]
let mut entries = #frame_support::__private::vec![];
#( #entries_builder )*
entries
},
}
}
}
#( #getters )*
#( #prefix_structs )*
#( #on_empty_structs )*
#try_decode_entire_state
)
}