Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Allow to name the generic for storages in #[pallet::storage] #8751

Merged
4 commits merged into from
May 19, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 73 additions & 27 deletions frame/support/procedural/src/pallet/expand/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// limitations under the License.

use crate::pallet::Def;
use crate::pallet::parse::storage::{Metadata, QueryKind};
use crate::pallet::parse::storage::{Metadata, QueryKind, StorageGenerics};
use frame_support_procedural_tools::clean_type_string;

/// Generate the prefix_ident related the the storage.
Expand All @@ -25,50 +25,96 @@ fn prefix_ident(storage_ident: &syn::Ident) -> syn::Ident {
syn::Ident::new(&format!("_GeneratedPrefixForStorage{}", storage_ident), storage_ident.span())
}

/// * generate StoragePrefix structs (e.g. for a storage `MyStorage` a struct with the name
/// `_GeneratedPrefixForStorage$NameOfStorage` is generated) and implements StorageInstance trait.
/// * replace the first generic `_` by the generated prefix structure
/// * generate metadatas
pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
/// * Add `#[allow(type_alias_bounds)]`
pub fn process_generics(def: &mut Def) {
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let pallet_ident = &def.pallet_struct.pallet;

// Replace first arg `_` by the generated prefix structure.
// Add `#[allow(type_alias_bounds)]`
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 = if let syn::Item::Type(t) = item {
t
} else {
unreachable!("Checked by def");
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 = if let syn::Type::Path(p) = &mut *typ_item.ty {
p
} else {
unreachable!("Checked by def");
let typ_path = match &mut *typ_item.ty {
syn::Type::Path(p) => p,
_ => unreachable!("Checked by def"),
};

let args = if let syn::PathArguments::AngleBracketed(args) =
&mut typ_path.path.segments[0].arguments
{
args
} else {
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.ident);
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 prefix_ident = prefix_ident(&storage_def.ident);
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );

let default_query_kind: syn::Type =
syn::parse_quote!(#frame_support::storage::types::OptionQuery);
let default_on_empty: syn::Type =
syn::parse_quote!(#frame_support::traits::GetDefault);

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));
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
args.args.push(syn::GenericArgument::Type(on_empty));
}
StorageGenerics::Map { hasher, key, value, query_kind, on_empty } => {
args.args.push(syn::GenericArgument::Type(hasher));
args.args.push(syn::GenericArgument::Type(key));
args.args.push(syn::GenericArgument::Type(value));
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
args.args.push(syn::GenericArgument::Type(on_empty));
}
StorageGenerics::DoubleMap {
hasher1, key1, hasher2, key2, value, query_kind, on_empty,
} => {
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));
let query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
args.args.push(syn::GenericArgument::Type(query_kind));
let on_empty = on_empty.unwrap_or_else(|| default_on_empty.clone());
args.args.push(syn::GenericArgument::Type(on_empty));
}
}
} else {
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
}
}
}

/// * generate StoragePrefix structs (e.g. for a storage `MyStorage` a struct with the name
/// `_GeneratedPrefixForStorage$NameOfStorage` is generated) and implements StorageInstance trait.
/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
/// * Add `#[allow(type_alias_bounds)]` on storages type alias
/// * generate metadatas
pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
process_generics(def);

let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let pallet_ident = &def.pallet_struct.pallet;


let entries = def.storages.iter()
.map(|storage| {
Expand Down
Loading