Allow where bounds on decl_module! and decl_storage! (#3000)

* Introduces a `where` bound to `decl_macro!` and `decl_storage!`

* More fixes

* Adds documentation
This commit is contained in:
Bastian Köcher
2019-07-03 21:07:39 +02:00
committed by GitHub
parent 5dc8792d8f
commit e9864b94a3
6 changed files with 328 additions and 99 deletions
@@ -139,6 +139,14 @@ use proc_macro::TokenStream;
/// Accessing the structure no requires the instance as generic parameter:
/// * `Foo::<I>` if the value type is not generic
/// * `Foo::<T, I>` if the value type is generic
///
/// ## Where clause
///
/// This macro supports a where clause which will be replicated to all generated types.
///
/// ```nocompile
/// trait Store for Module<T: Trait> as Example where T::AccountId: std::fmt::Display {}
/// ```
#[proc_macro]
pub fn decl_storage(input: TokenStream) -> TokenStream {
storage::transformation::decl_storage_impl(input)
@@ -47,6 +47,7 @@ pub(crate) struct Impls<'a, I: Iterator<Item=syn::Meta>> {
pub cratename: &'a syn::Ident,
pub name: &'a syn::Ident,
pub attrs: I,
pub where_clause: &'a Option<syn::WhereClause>,
}
impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
@@ -62,6 +63,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
prefix,
name,
attrs,
where_clause,
..
} = self;
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
@@ -94,19 +96,21 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
quote!{ #prefix.as_bytes() }
};
let (struct_trait, impl_trait, trait_and_instance) = if ext::type_contains_ident(
let (struct_trait, impl_trait, trait_and_instance, where_clause) = if ext::type_contains_ident(
value_type, traitinstance
) {
(
quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance),
quote!(#traitinstance: #traittype, #instance #bound_instantiable),
quote!(#traitinstance, #instance),
where_clause.clone(),
)
} else {
(
quote!(#instance #bound_instantiable #equal_default_instance),
quote!(#instance #bound_instantiable),
quote!(#instance)
quote!(#instance),
None,
)
};
@@ -115,10 +119,10 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#( #[ #attrs ] )*
#visibility struct #name<#struct_trait>(
#scrate::rstd::marker::PhantomData<(#trait_and_instance)>
);
) #where_clause;
impl<#impl_trait> #scrate::storage::hashed::generator::StorageValue<#typ>
for #name<#trait_and_instance>
for #name<#trait_and_instance> #where_clause
{
type Query = #value_type;
@@ -167,6 +171,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
prefix,
name,
attrs,
where_clause,
..
} = self;
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
@@ -201,19 +206,22 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
quote!{ #prefix.as_bytes() }
};
let (struct_trait, impl_trait, trait_and_instance) = if ext::type_contains_ident(value_type, traitinstance)
|| ext::type_contains_ident(kty, traitinstance)
{
let trait_required = ext::type_contains_ident(value_type, traitinstance)
|| ext::type_contains_ident(kty, traitinstance);
let (struct_trait, impl_trait, trait_and_instance, where_clause) = if trait_required {
(
quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance),
quote!(#traitinstance: #traittype, #instance #bound_instantiable),
quote!(#traitinstance, #instance),
where_clause.clone(),
)
} else {
(
quote!(#instance #bound_instantiable #equal_default_instance),
quote!(#instance #bound_instantiable),
quote!(#instance)
quote!(#instance),
None,
)
};
@@ -222,10 +230,10 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#( #[ #attrs ] )*
#visibility struct #name<#struct_trait>(
#scrate::rstd::marker::PhantomData<(#trait_and_instance)>
);
) #where_clause;
impl<#impl_trait>
#scrate::storage::hashed::generator::StorageMap<#kty, #typ> for #name<#trait_and_instance>
impl<#impl_trait> #scrate::storage::hashed::generator::StorageMap<#kty, #typ>
for #name<#trait_and_instance> #where_clause
{
type Query = #value_type;
@@ -270,7 +278,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
}
impl<#impl_trait> #scrate::storage::hashed::generator::AppendableStorageMap<#kty, #typ>
for #name<#trait_and_instance>
for #name<#trait_and_instance> #where_clause
{}
}
}
@@ -287,6 +295,7 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
prefix,
name,
attrs,
where_clause,
..
} = self;
@@ -298,7 +307,9 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} = instance_opts;
let final_prefix = if let Some(instance) = instance {
let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site());
let const_name = Ident::new(
&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()
);
quote!{ #instance::#const_name.as_bytes() }
} else {
quote!{ #prefix.as_bytes() }
@@ -306,7 +317,9 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
// make sure to use different prefix for head and elements.
let final_head_key = if let Some(instance) = instance {
let const_name = syn::Ident::new(&format!("{}{}", HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site());
let const_name = Ident::new(
&format!("{}{}", HEAD_KEY_FOR, name.to_string()), proc_macro2::Span::call_site()
);
quote!{ #instance::#const_name.as_bytes() }
} else {
let final_head_key = format!("head of {}", prefix);
@@ -316,8 +329,10 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
let option_simple_1 = option_unwrap(is_option);
let name_lowercase = name.to_string().to_lowercase();
let inner_module = syn::Ident::new(&format!("__linked_map_details_for_{}_do_not_use", name_lowercase), name.span());
let linkage = syn::Ident::new(&format!("__LinkageFor{}DoNotUse", name), name.span());
let inner_module = Ident::new(
&format!("__linked_map_details_for_{}_do_not_use", name_lowercase), name.span()
);
let linkage = Ident::new(&format!("__LinkageFor{}DoNotUse", name), name.span());
let phantom_data = quote! { #scrate::rstd::marker::PhantomData };
let as_map = quote!{ <Self as #scrate::storage::hashed::generator::StorageMap<#kty, #typ>> };
let put_or_insert = quote! {
@@ -337,23 +352,35 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
}
};
let (struct_trait, impl_trait, trait_and_instance, trait_lifetime) = if ext::type_contains_ident(
value_type,
traitinstance
) || ext::type_contains_ident(kty, traitinstance)
{
let trait_required = ext::type_contains_ident(value_type, traitinstance)
|| ext::type_contains_ident(kty, traitinstance);
let (struct_trait, impl_trait, trait_and_instance) = if trait_required {
(
quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance),
quote!(#traitinstance: #traittype, #instance #bound_instantiable),
quote!(#traitinstance, #instance),
quote!(#traitinstance: 'static),
)
} else {
(
quote!(#instance #bound_instantiable #equal_default_instance),
quote!(#instance #bound_instantiable),
quote!(#instance),
quote!()
)
};
let (where_clause, trait_where_clause) = if trait_required {
(
where_clause.clone(),
where_clause.clone().map(|mut wc| {
wc.predicates.push(syn::parse_quote!(#traitinstance: 'static));
wc
}).or_else(|| syn::parse_quote!(where #traitinstance: 'static)),
)
} else {
(
None,
None,
)
};
@@ -390,8 +417,8 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
pub _data: #phantom_data<V>,
}
impl<'a, S: #scrate::HashedStorage<#scrate::#hasher>, #impl_trait>
Iterator for Enumerator<'a, S, #kty, (#typ, #trait_and_instance)>
impl<'a, S: #scrate::HashedStorage<#scrate::#hasher>, #impl_trait> Iterator
for Enumerator<'a, S, #kty, (#typ, #trait_and_instance)> #where_clause
{
type Item = (#kty, #typ);
@@ -442,7 +469,9 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#( #[ #attrs ] )*
#visibility struct #name<#struct_trait>(#phantom_data<(#trait_and_instance)>);
impl<#impl_trait> self::#inner_module::Utils<#trait_and_instance> for #name<#trait_and_instance> {
impl<#impl_trait> self::#inner_module::Utils<#trait_and_instance>
for #name<#trait_and_instance> #where_clause
{
fn remove_linkage<S: #scrate::HashedStorage<#scrate::#hasher>>(
linkage: self::#inner_module::Linkage<#kty>,
storage: &mut S,
@@ -529,8 +558,8 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#structure
impl<#impl_trait>
#scrate::storage::hashed::generator::StorageMap<#kty, #typ> for #name<#trait_and_instance>
impl<#impl_trait> #scrate::storage::hashed::generator::StorageMap<#kty, #typ>
for #name<#trait_and_instance> #where_clause
{
type Query = #value_type;
@@ -605,10 +634,8 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
}
}
impl<#impl_trait>
#scrate::storage::hashed::generator::EnumerableStorageMap<#kty, #typ> for #name<#trait_and_instance>
where
#trait_lifetime
impl<#impl_trait> #scrate::storage::hashed::generator::EnumerableStorageMap<#kty, #typ>
for #name<#trait_and_instance> #trait_where_clause
{
fn head<S: #scrate::HashedStorage<#scrate::#hasher>>(storage: &S) -> Option<#kty> {
use self::#inner_module::Utils;
@@ -654,13 +681,16 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
name,
attrs,
instance_opts,
where_clause,
..
} = self;
let DeclStorageTypeInfos { typ, value_type, is_option, .. } = type_infos;
let option_simple_1 = option_unwrap(is_option);
let as_double_map = quote!{ <Self as #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ>> };
let as_double_map = quote!{
<Self as #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ>>
};
let mutate_impl = if !is_option {
quote!{
@@ -683,26 +713,30 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
} = instance_opts;
let final_prefix = if let Some(instance) = instance {
let const_name = syn::Ident::new(&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site());
let const_name = Ident::new(
&format!("{}{}", PREFIX_FOR, name.to_string()), proc_macro2::Span::call_site()
);
quote!{ #instance::#const_name.as_bytes() }
} else {
quote!{ #prefix.as_bytes() }
};
let (struct_trait, impl_trait, trait_and_instance) = if ext::type_contains_ident(value_type, traitinstance)
|| ext::type_contains_ident(k1ty, traitinstance)
|| ext::type_contains_ident(k2ty, traitinstance)
let (struct_trait, impl_trait, trait_and_instance, where_clause) = if ext::type_contains_ident(
value_type, traitinstance
) || ext::type_contains_ident(k1ty, traitinstance) || ext::type_contains_ident(k2ty, traitinstance)
{
(
quote!(#traitinstance: #traittype, #instance #bound_instantiable #equal_default_instance),
quote!(#traitinstance: #traittype, #instance #bound_instantiable),
quote!(#traitinstance, #instance),
where_clause.clone(),
)
} else {
(
quote!(#instance #bound_instantiable #equal_default_instance),
quote!(#instance #bound_instantiable),
quote!(#instance)
quote!(#instance),
None,
)
};
@@ -712,8 +746,8 @@ impl<'a, I: Iterator<Item=syn::Meta>> Impls<'a, I> {
#visibility struct #name<#struct_trait>
(#scrate::rstd::marker::PhantomData<(#trait_and_instance)>);
impl<#impl_trait>
#scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ> for #name<#trait_and_instance>
impl<#impl_trait> #scrate::storage::unhashed::generator::StorageDoubleMap<#k1ty, #k2ty, #typ>
for #name<#trait_and_instance> #where_clause
{
type Query = #value_type;
@@ -65,6 +65,7 @@ struct StorageDefinition {
pub mod_gt_token: Token![>],
pub as_token: Token![as],
pub crate_ident: Ident,
pub where_clause: Option<syn::WhereClause>,
pub content: ext::Braces<ext::Punctuated<DeclStorageLine, Token![;]>>,
pub extra_genesis: ext::Opt<AddExtraGenesis>,
}
@@ -27,6 +27,7 @@ use proc_macro2::{TokenStream as TokenStream2, Span};
use syn::{
Ident,
GenericParam,
WhereClause,
spanned::Spanned,
parse::{
Error,
@@ -68,6 +69,7 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream {
crate_ident: cratename,
content: ext::Braces { content: storage_lines, ..},
extra_genesis,
where_clause,
..
} = def;
@@ -110,6 +112,7 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream {
&instance_opts,
&storage_lines,
&extra_genesis.inner,
&where_clause,
));
let decl_storage_items = decl_storage_items(
&scrate,
@@ -118,6 +121,7 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream {
&instance_opts,
&cratename,
&storage_lines,
&where_clause,
);
let decl_store_items = decl_store_items(
@@ -140,6 +144,7 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream {
&traittype,
&instance_opts,
&storage_lines,
&where_clause,
);
let InstanceOpts {
@@ -156,10 +161,14 @@ pub fn decl_storage_impl(input: TokenStream) -> TokenStream {
#decl_store_items
}
#store_default_struct
impl<#traitinstance: #traittype, #instance #bound_instantiable> #storetype for #module_ident<#traitinstance, #instance> {
impl<#traitinstance: #traittype, #instance #bound_instantiable> #storetype
for #module_ident<#traitinstance, #instance> #where_clause
{
#impl_store_items
}
impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable> #module_ident<#traitinstance, #instance> {
impl<#traitinstance: 'static + #traittype, #instance #bound_instantiable>
#module_ident<#traitinstance, #instance> #where_clause
{
#impl_store_fns
#[doc(hidden)]
pub fn store_metadata_functions() -> &'static [#scrate::metadata::StorageEntryMetadata] {
@@ -184,6 +193,7 @@ fn decl_store_extra_genesis(
instance_opts: &InstanceOpts,
storage_lines: &ext::Punctuated<DeclStorageLine, Token![;]>,
extra_genesis: &Option<AddExtraGenesis>,
where_clause: &Option<syn::WhereClause>,
) -> Result<TokenStream2> {
let InstanceOpts {
@@ -479,7 +489,26 @@ fn decl_store_extra_genesis(
let impl_trait = quote!(BuildModuleGenesisStorage<#traitinstance, #inherent_instance>);
let builders_clone_bound = quote!( #( #builders_clone_bound: Clone ),* );
let extend_where_clause = |to_extend: &mut WhereClause| {
if let Some(where_clause) = where_clause {
to_extend.predicates.extend(where_clause.predicates.iter().cloned());
}
};
let mut genesis_where_clause: WhereClause = syn::parse_quote!(
where #( #builders_clone_bound: Clone ),*
);
let mut fn_where_clause = genesis_where_clause.clone();
let mut build_storage_where_clause = genesis_where_clause.clone();
extend_where_clause(&mut build_storage_where_clause);
if is_trait_needed {
extend_where_clause(&mut genesis_where_clause);
} else if assimilate_require_generic {
extend_where_clause(&mut fn_where_clause);
}
let res = quote!{
#[derive(#scrate::Serialize, #scrate::Deserialize)]
@@ -487,13 +516,13 @@ fn decl_store_extra_genesis(
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
#serde_bug_bound
pub struct GenesisConfig#fparam_struct {
pub struct GenesisConfig#fparam_struct #genesis_where_clause {
#config_field
#genesis_extrafields
}
#[cfg(feature = "std")]
impl#fparam_impl Default for GenesisConfig#sparam {
impl#fparam_impl Default for GenesisConfig#sparam #genesis_where_clause {
fn default() -> Self {
GenesisConfig {
#config_field_default
@@ -503,14 +532,14 @@ fn decl_store_extra_genesis(
}
#[cfg(feature = "std")]
impl#fparam_impl GenesisConfig#sparam where #builders_clone_bound {
impl#fparam_impl GenesisConfig#sparam #genesis_where_clause {
pub fn build_storage #fn_generic (self) -> std::result::Result<
(
#scrate::runtime_primitives::StorageOverlay,
#scrate::runtime_primitives::ChildrenStorageOverlay,
),
String
> {
> #fn_where_clause {
let mut storage = Default::default();
let mut child_storage = Default::default();
self.assimilate_storage::<#fn_traitinstance>(&mut storage, &mut child_storage)?;
@@ -522,7 +551,7 @@ fn decl_store_extra_genesis(
self,
r: &mut #scrate::runtime_primitives::StorageOverlay,
c: &mut #scrate::runtime_primitives::ChildrenStorageOverlay,
) -> std::result::Result<(), String> {
) -> std::result::Result<(), String> #fn_where_clause {
let storage = r;
#builders
@@ -535,7 +564,7 @@ fn decl_store_extra_genesis(
#[cfg(feature = "std")]
impl#build_storage_impl #scrate::runtime_primitives::#impl_trait
for GenesisConfig#sparam where #builders_clone_bound
for GenesisConfig#sparam #build_storage_where_clause
{
fn build_module_genesis_storage(
self,
@@ -589,6 +618,7 @@ fn decl_storage_items(
instance_opts: &InstanceOpts,
cratename: &Ident,
storage_lines: &ext::Punctuated<DeclStorageLine, Token![;]>,
where_clause: &Option<WhereClause>,
) -> TokenStream2 {
let mut impls = TokenStream2::new();
@@ -728,6 +758,7 @@ fn decl_storage_items(
prefix: build_prefix(cratename, name),
name,
attrs,
where_clause,
};
let implementation = match kind {
@@ -899,6 +930,7 @@ fn store_functions_to_metadata (
traittype: &syn::TypeParamBound,
instance_opts: &InstanceOpts,
storage_lines: &ext::Punctuated<DeclStorageLine, Token![;]>,
where_clause: &Option<WhereClause>,
) -> (TokenStream2, TokenStream2) {
let InstanceOpts {
@@ -1008,12 +1040,18 @@ fn store_functions_to_metadata (
let def_get = quote! {
#[doc(hidden)]
pub struct #struct_name<#traitinstance, #instance #bound_instantiable #equal_default_instance>(pub #scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>);
pub struct #struct_name<
#traitinstance, #instance #bound_instantiable #equal_default_instance
>(pub #scrate::rstd::marker::PhantomData<(#traitinstance #comma_instance)>);
#[cfg(feature = "std")]
#[allow(non_upper_case_globals)]
static #cache_name: #scrate::once_cell::sync::OnceCell<#scrate::rstd::vec::Vec<u8>> = #scrate::once_cell::sync::OnceCell::INIT;
#[cfg(feature = "std")]
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte for #struct_name<#traitinstance, #instance> {
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte
for #struct_name<#traitinstance, #instance> #where_clause
{
fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> {
use #scrate::codec::Encode;
#cache_name.get_or_init(|| {
@@ -1022,8 +1060,11 @@ fn store_functions_to_metadata (
}).clone()
}
}
#[cfg(not(feature = "std"))]
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte for #struct_name<#traitinstance, #instance> {
impl<#traitinstance: #traittype, #instance #bound_instantiable> #scrate::metadata::DefaultByte
for #struct_name<#traitinstance, #instance> #where_clause
{
fn default_byte(&self) -> #scrate::rstd::vec::Vec<u8> {
use #scrate::codec::Encode;
let def_val: #value_type = #default;