Add pallet attribute macro to declare pallets (#6877)

* rename system Config to system Trait.

command used:
```
find frame/ bin/ test-utils/ utils/ -name *.rs -exec sed -i 's/system::Trait>::/system::Config>::/g' {} \;
find frame/ bin/ test-utils/ utils/ -name *.rs -exec sed -i 's/impl frame_system::Trait for /impl frame_system::Config for /g' {} \;
find frame/ bin/ test-utils/ utils/ -name *.rs -exec sed -i 's/impl system::Trait for /impl system::Config for /g' {} \;
```
plus some manual ones especially for frame-support tests and frame-system

* make construct_runtime handle Pallet and Module

pallets can now be implemented on struct named Pallet or Module, both
definition are valid.
This is because next macro will generate only Pallet placeholder.

* introduce pallet attribute macro

currently just with tests, frame_system and other example hasn't been
upgraded

* allow to print some upgrade helper from decl_storage

* Improved error msg, typo.

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Improved error msg, typo.

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>

* Improved error message on unexpected attributes + ui test

* add test for transactional

* various typo

* some tips when spans are lost

* allow pallet to depend on other pallet instances

* make event type metadata consistent with call and constant

* error messages

* ignore doc example

* fix pallet upgrade template

* fixup

* fix doc

* fix indentation

* Apply suggestions code formatting

Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>

* some renames + fix compilation

* remove unsupported genesis config type alias

* merge fixup

* fix ui tests

* additional doc

* implement StorageInstance with new syntax

* fix line width

* fix doc: because pallet doc goes below reexport doc

* Update frame/support/procedural/src/pallet/parse/event.rs

Co-authored-by: Andrew Jones <ascjones@gmail.com>

* Update frame/system/src/lib.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Update frame/support/test/tests/pallet_ui.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* improve doc as suggested

* revert construct_runtime Pallet part.

This revert the changes on construct_runtime. Now construct_runtime is
unchanged and instead pallet macro create a type alias
`type Module<..> = Pallet<..>` to be used by construct_runtime

* refactor with less intricated code

* fix ui test with new image

* fix ui tests

* add minor tests

Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: Andrew Jones <ascjones@gmail.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Guillaume Thiolliere
2020-12-24 12:33:40 +01:00
committed by GitHub
parent 8e3d8a6a09
commit 6dfad0921b
131 changed files with 9610 additions and 31 deletions
@@ -0,0 +1,201 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use frame_support_procedural_tools::clean_type_string;
use syn::spanned::Spanned;
/// * Generate enum call and implement various trait on it.
/// * Implement Callable and call_function on `Pallet`
pub fn expand_call(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let type_impl_gen = &def.type_impl_generics();
let type_decl_bounded_gen = &def.type_decl_bounded_generics();
let type_use_gen = &def.type_use_generics();
let call_ident = syn::Ident::new("Call", def.call.attr_span.clone());
let pallet_ident = &def.pallet_struct.pallet;
let where_clause = &def.call.where_clause;
let fn_name = def.call.methods.iter().map(|method| &method.name).collect::<Vec<_>>();
let fn_weight = def.call.methods.iter().map(|method| &method.weight);
let fn_doc = def.call.methods.iter().map(|method| &method.docs).collect::<Vec<_>>();
let args_name = def.call.methods.iter()
.map(|method| method.args.iter().map(|(_, name, _)| name.clone()).collect::<Vec<_>>())
.collect::<Vec<_>>();
let args_type = def.call.methods.iter()
.map(|method| method.args.iter().map(|(_, _, type_)| type_.clone()).collect::<Vec<_>>())
.collect::<Vec<_>>();
let args_compact_attr = def.call.methods.iter().map(|method| {
method.args.iter()
.map(|(is_compact, _, type_)| {
if *is_compact {
quote::quote_spanned!(type_.span() => #[codec(compact)] )
} else {
quote::quote!()
}
})
.collect::<Vec<_>>()
});
let args_metadata_type = def.call.methods.iter().map(|method| {
method.args.iter()
.map(|(is_compact, _, type_)| {
let final_type = if *is_compact {
quote::quote!(Compact<#type_>)
} else {
quote::quote!(#type_)
};
clean_type_string(&final_type.to_string())
})
.collect::<Vec<_>>()
});
quote::quote_spanned!(def.call.attr_span =>
#[derive(
#frame_support::RuntimeDebugNoBound,
#frame_support::CloneNoBound,
#frame_support::EqNoBound,
#frame_support::PartialEqNoBound,
#frame_support::codec::Encode,
#frame_support::codec::Decode,
)]
#[allow(non_camel_case_types)]
pub enum #call_ident<#type_decl_bounded_gen> #where_clause {
#[doc(hidden)]
#[codec(skip)]
__Ignore(
#frame_support::sp_std::marker::PhantomData<(#type_use_gen,)>,
#frame_support::Never,
),
#( #fn_name( #( #args_compact_attr #args_type ),* ), )*
}
impl<#type_impl_gen> #frame_support::dispatch::GetDispatchInfo
for #call_ident<#type_use_gen>
#where_clause
{
fn get_dispatch_info(&self) -> #frame_support::dispatch::DispatchInfo {
match *self {
#(
Self::#fn_name ( #( ref #args_name, )* ) => {
let base_weight = #fn_weight;
let weight = <
dyn #frame_support::dispatch::WeighData<( #( & #args_type, )* )>
>::weigh_data(&base_weight, ( #( #args_name, )* ));
let class = <
dyn #frame_support::dispatch::ClassifyDispatch<
( #( & #args_type, )* )
>
>::classify_dispatch(&base_weight, ( #( #args_name, )* ));
let pays_fee = <
dyn #frame_support::dispatch::PaysFee<( #( & #args_type, )* )>
>::pays_fee(&base_weight, ( #( #args_name, )* ));
#frame_support::dispatch::DispatchInfo {
weight,
class,
pays_fee,
}
},
)*
Self::__Ignore(_, _) => unreachable!("__Ignore cannot be used"),
}
}
}
impl<#type_impl_gen> #frame_support::dispatch::GetCallName for #call_ident<#type_use_gen>
#where_clause
{
fn get_call_name(&self) -> &'static str {
match *self {
#( Self::#fn_name(..) => stringify!(#fn_name), )*
Self::__Ignore(_, _) => unreachable!("__PhantomItem cannot be used."),
}
}
fn get_call_names() -> &'static [&'static str] {
&[ #( stringify!(#fn_name), )* ]
}
}
impl<#type_impl_gen> #frame_support::traits::UnfilteredDispatchable
for #call_ident<#type_use_gen>
#where_clause
{
type Origin = #frame_system::pallet_prelude::OriginFor<T>;
fn dispatch_bypass_filter(
self,
origin: Self::Origin
) -> #frame_support::dispatch::DispatchResultWithPostInfo {
match self {
#(
Self::#fn_name( #( #args_name, )* ) =>
<#pallet_ident<#type_use_gen>>::#fn_name(origin, #( #args_name, )* )
.map(Into::into).map_err(Into::into),
)*
Self::__Ignore(_, _) => {
let _ = origin; // Use origin for empty Call enum
unreachable!("__PhantomItem cannot be used.");
},
}
}
}
impl<#type_impl_gen> #frame_support::dispatch::Callable<T> for #pallet_ident<#type_use_gen>
#where_clause
{
type Call = #call_ident<#type_use_gen>;
}
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause {
#[doc(hidden)]
pub fn call_functions() -> &'static [#frame_support::dispatch::FunctionMetadata] {
&[ #(
#frame_support::dispatch::FunctionMetadata {
name: #frame_support::dispatch::DecodeDifferent::Encode(
stringify!(#fn_name)
),
arguments: #frame_support::dispatch::DecodeDifferent::Encode(
&[ #(
#frame_support::dispatch::FunctionArgumentMetadata {
name: #frame_support::dispatch::DecodeDifferent::Encode(
stringify!(#args_name)
),
ty: #frame_support::dispatch::DecodeDifferent::Encode(
#args_metadata_type
),
},
)* ]
),
documentation: #frame_support::dispatch::DecodeDifferent::Encode(
&[ #( #fn_doc ),* ]
),
},
)* ]
}
}
)
}
@@ -0,0 +1,138 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use frame_support_procedural_tools::clean_type_string;
use quote::ToTokens;
struct ConstDef {
/// Name of the associated type.
pub ident: syn::Ident,
/// The type in Get, e.g. `u32` in `type Foo: Get<u32>;`, but `Self` is replaced by `T`
pub type_: syn::Type,
/// The doc associated
pub doc: Vec<syn::Lit>,
/// default_byte implementation
pub default_byte_impl: proc_macro2::TokenStream,
}
/// * Impl fn module_constant_metadata for pallet.
pub fn expand_constants(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let type_impl_gen = &def.type_impl_generics();
let type_decl_gen = &def.type_decl_generics();
let type_use_gen = &def.type_use_generics();
let pallet_ident = &def.pallet_struct.pallet;
let mut where_clauses = vec![&def.config.where_clause];
where_clauses.extend(def.extra_constants.iter().map(|d| &d.where_clause));
let completed_where_clause = super::merge_where_clauses(&where_clauses);
let config_consts = def.config.consts_metadata.iter().map(|const_| {
let ident = &const_.ident;
let const_type = &const_.type_;
ConstDef {
ident: const_.ident.clone(),
type_: const_.type_.clone(),
doc: const_.doc.clone(),
default_byte_impl: quote::quote!(
let value = <T::#ident as #frame_support::traits::Get<#const_type>>::get();
#frame_support::codec::Encode::encode(&value)
),
}
});
let extra_consts = def.extra_constants.iter().flat_map(|d| &d.extra_constants).map(|const_| {
let ident = &const_.ident;
ConstDef {
ident: const_.ident.clone(),
type_: const_.type_.clone(),
doc: const_.doc.clone(),
default_byte_impl: quote::quote!(
let value = <Pallet<#type_use_gen>>::#ident();
#frame_support::codec::Encode::encode(&value)
),
}
});
let consts = config_consts.chain(extra_consts)
.map(|const_| {
let const_type = &const_.type_;
let const_type_str = clean_type_string(&const_type.to_token_stream().to_string());
let ident = &const_.ident;
let ident_str = format!("{}", ident);
let doc = const_.doc.clone().into_iter();
let default_byte_impl = &const_.default_byte_impl;
let default_byte_getter = syn::Ident::new(
&format!("{}DefaultByteGetter", ident),
ident.span()
);
quote::quote!({
#[allow(non_upper_case_types)]
#[allow(non_camel_case_types)]
struct #default_byte_getter<#type_decl_gen>(
#frame_support::sp_std::marker::PhantomData<(#type_use_gen)>
);
impl<#type_impl_gen> #frame_support::dispatch::DefaultByte for
#default_byte_getter<#type_use_gen>
#completed_where_clause
{
fn default_byte(&self) -> #frame_support::sp_std::vec::Vec<u8> {
#default_byte_impl
}
}
unsafe impl<#type_impl_gen> Send for #default_byte_getter<#type_use_gen>
#completed_where_clause
{}
unsafe impl<#type_impl_gen> Sync for #default_byte_getter<#type_use_gen>
#completed_where_clause
{}
#frame_support::dispatch::ModuleConstantMetadata {
name: #frame_support::dispatch::DecodeDifferent::Encode(#ident_str),
ty: #frame_support::dispatch::DecodeDifferent::Encode(#const_type_str),
value: #frame_support::dispatch::DecodeDifferent::Encode(
#frame_support::dispatch::DefaultByteGetter(
&#default_byte_getter::<#type_use_gen>(
#frame_support::sp_std::marker::PhantomData
)
)
),
documentation: #frame_support::dispatch::DecodeDifferent::Encode(
&[ #( #doc ),* ]
),
}
})
});
quote::quote!(
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause{
#[doc(hidden)]
pub fn module_constants_metadata()
-> &'static [#frame_support::dispatch::ModuleConstantMetadata]
{
&[ #( #consts ),* ]
}
}
)
}
@@ -0,0 +1,141 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use syn::spanned::Spanned;
/// * impl various trait on Error
/// * impl ModuleErrorMetadata for Error
pub fn expand_error(def: &mut Def) -> proc_macro2::TokenStream {
let error = if let Some(error) = &def.error {
error
} else {
return Default::default()
};
let error_item_span =
def.item.content.as_mut().expect("Checked by def parser").1[error.index].span();
let error_ident = &error.error;
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let type_impl_gen = &def.type_impl_generics();
let type_use_gen = &def.type_use_generics();
let config_where_clause = &def.config.where_clause;
let phantom_variant: syn::Variant = syn::parse_quote!(
#[doc(hidden)]
__Ignore(
#frame_support::sp_std::marker::PhantomData<(#type_use_gen)>,
#frame_support::Never,
)
);
let as_u8_matches = error.variants.iter().enumerate()
.map(|(i, (variant, _))| quote::quote!(Self::#variant => #i as u8,));
let as_str_matches = error.variants.iter()
.map(|(variant, _)| {
let variant_str = format!("{}", variant);
quote::quote!(Self::#variant => #variant_str,)
});
let metadata = error.variants.iter()
.map(|(variant, doc)| {
let variant_str = format!("{}", variant);
quote::quote!(
#frame_support::error::ErrorMetadata {
name: #frame_support::error::DecodeDifferent::Encode(#variant_str),
documentation: #frame_support::error::DecodeDifferent::Encode(&[ #( #doc, )* ]),
},
)
});
let error_item = {
let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[error.index];
if let syn::Item::Enum(item) = item {
item
} else {
unreachable!("Checked by event parser")
}
};
error_item.variants.insert(0, phantom_variant);
quote::quote_spanned!(error_item_span =>
impl<#type_impl_gen> #frame_support::sp_std::fmt::Debug for #error_ident<#type_use_gen>
#config_where_clause
{
fn fmt(&self, f: &mut #frame_support::sp_std::fmt::Formatter<'_>)
-> #frame_support::sp_std::fmt::Result
{
f.write_str(self.as_str())
}
}
impl<#type_impl_gen> #error_ident<#type_use_gen> #config_where_clause {
pub fn as_u8(&self) -> u8 {
match &self {
Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"),
#( #as_u8_matches )*
}
}
pub fn as_str(&self) -> &'static str {
match &self {
Self::__Ignore(_, _) => unreachable!("`__Ignore` can never be constructed"),
#( #as_str_matches )*
}
}
}
impl<#type_impl_gen> From<#error_ident<#type_use_gen>> for &'static str
#config_where_clause
{
fn from(err: #error_ident<#type_use_gen>) -> &'static str {
err.as_str()
}
}
impl<#type_impl_gen> From<#error_ident<#type_use_gen>>
for #frame_support::sp_runtime::DispatchError
#config_where_clause
{
fn from(err: #error_ident<#type_use_gen>) -> Self {
let index = <
<T as #frame_system::Config>::PalletInfo
as #frame_support::traits::PalletInfo
>::index::<Pallet<#type_use_gen>>()
.expect("Every active module has an index in the runtime; qed") as u8;
#frame_support::sp_runtime::DispatchError::Module {
index,
error: err.as_u8(),
message: Some(err.as_str()),
}
}
}
impl<#type_impl_gen> #frame_support::error::ModuleErrorMetadata
for #error_ident<#type_use_gen>
#config_where_clause
{
fn metadata() -> &'static [#frame_support::error::ErrorMetadata] {
&[ #( #metadata )* ]
}
}
)
}
@@ -0,0 +1,143 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use syn::spanned::Spanned;
/// * Add __Ignore variant on Event
/// * Impl various trait on Event including metadata
/// * if deposit_event is defined, implement deposit_event on module.
pub fn expand_event(def: &mut Def) -> proc_macro2::TokenStream {
let event = if let Some(event) = &def.event {
event
} else {
return Default::default()
};
let event_where_clause = &event.where_clause;
// NOTE: actually event where clause must be a subset of config where clause because of
// `type Event: From<Event<Self>>`. But we merge either way for potential better error message
let completed_where_clause = super::merge_where_clauses(&[
&event.where_clause,
&def.config.where_clause,
]);
let event_ident = &event.event;
let frame_system = &def.frame_system;
let frame_support = &def.frame_support;
let event_use_gen = &event.gen_kind.type_use_gen();
let event_impl_gen= &event.gen_kind.type_impl_gen();
let metadata = event.metadata.iter()
.map(|(ident, args, docs)| {
let name = format!("{}", ident);
quote::quote!(
#frame_support::event::EventMetadata {
name: #frame_support::event::DecodeDifferent::Encode(#name),
arguments: #frame_support::event::DecodeDifferent::Encode(&[
#( #args, )*
]),
documentation: #frame_support::event::DecodeDifferent::Encode(&[
#( #docs, )*
]),
},
)
});
let event_item_span =
def.item.content.as_mut().expect("Checked by def parser").1[event.index].span();
let event_item = {
let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[event.index];
if let syn::Item::Enum(item) = item {
item
} else {
unreachable!("Checked by event parser")
}
};
// Phantom data is added for generic event.
if event.gen_kind.is_generic() {
let variant = syn::parse_quote!(
#[doc(hidden)]
#[codec(skip)]
__Ignore(
#frame_support::sp_std::marker::PhantomData<(#event_use_gen)>,
#frame_support::Never,
)
);
// Push ignore variant at the end.
event_item.variants.push(variant);
}
// derive some traits because system event require Clone, FullCodec, Eq, PartialEq and Debug
event_item.attrs.push(syn::parse_quote!(
#[derive(
#frame_support::CloneNoBound,
#frame_support::EqNoBound,
#frame_support::PartialEqNoBound,
#frame_support::RuntimeDebugNoBound,
#frame_support::codec::Encode,
#frame_support::codec::Decode,
)]
));
let deposit_event = if let Some((fn_vis, fn_span)) = &event.deposit_event {
let event_use_gen = &event.gen_kind.type_use_gen();
let trait_use_gen = &def.trait_use_generics();
let type_impl_gen = &def.type_impl_generics();
let type_use_gen = &def.type_use_generics();
quote::quote_spanned!(*fn_span =>
impl<#type_impl_gen> Pallet<#type_use_gen> #completed_where_clause {
#fn_vis fn deposit_event(event: Event<#event_use_gen>) {
let event = <
<T as Config#trait_use_gen>::Event as
From<Event<#event_use_gen>>
>::from(event);
let event = <
<T as Config#trait_use_gen>::Event as
Into<<T as #frame_system::Config>::Event>
>::into(event);
<#frame_system::Pallet<T>>::deposit_event(event)
}
}
)
} else {
Default::default()
};
quote::quote_spanned!(event_item_span =>
#deposit_event
impl<#event_impl_gen> From<#event_ident<#event_use_gen>> for () #event_where_clause {
fn from(_: #event_ident<#event_use_gen>) -> () { () }
}
impl<#event_impl_gen> #event_ident<#event_use_gen> #event_where_clause {
#[allow(dead_code)]
#[doc(hidden)]
pub fn metadata() -> &'static [#frame_support::event::EventMetadata] {
&[ #( #metadata )* ]
}
}
)
}
@@ -0,0 +1,72 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use syn::spanned::Spanned;
/// * implement the trait `sp_runtime::BuildModuleGenesisStorage`
/// * add #[cfg(features = "std")] to GenesisBuild implementation.
pub fn expand_genesis_build(def: &mut Def) -> proc_macro2::TokenStream {
let genesis_config = if let Some(genesis_config) = &def.genesis_config {
genesis_config
} else {
return Default::default()
};
let frame_support = &def.frame_support;
let type_impl_gen = &def.type_impl_generics();
let type_use_gen = &def.type_use_generics();
let trait_use_gen = if def.config.has_instance {
quote::quote!(T, I)
} else {
// `__InherentHiddenInstance` used by construct_runtime here is alias for `()`
quote::quote!(T, ())
};
let gen_cfg_ident = &genesis_config.genesis_config;
let gen_cfg_use_gen = genesis_config.gen_kind.type_use_gen();
let genesis_build = def.genesis_build.as_ref().expect("Checked by def parser");
let genesis_build_item = &mut def.item.content.as_mut()
.expect("Checked by def parser").1[genesis_build.index];
let genesis_build_item_impl = if let syn::Item::Impl(impl_) = genesis_build_item {
impl_
} else {
unreachable!("Checked by genesis_build parser")
};
genesis_build_item_impl.attrs.push(syn::parse_quote!( #[cfg(feature = "std")] ));
let where_clause = &genesis_build.where_clause;
quote::quote_spanned!(genesis_build_item.span() =>
#[cfg(feature = "std")]
impl<#type_impl_gen> #frame_support::sp_runtime::BuildModuleGenesisStorage<#trait_use_gen>
for #gen_cfg_ident<#gen_cfg_use_gen> #where_clause
{
fn build_module_genesis_storage(
&self,
storage: &mut #frame_support::sp_runtime::Storage,
) -> std::result::Result<(), std::string::String> {
#frame_support::BasicExternalities::execute_with_storage(storage, || {
<Self as #frame_support::traits::GenesisBuild<#type_use_gen>>::build(self);
Ok(())
})
}
}
)
}
@@ -0,0 +1,49 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
/// * add various derive trait on GenesisConfig struct.
pub fn expand_genesis_config(def: &mut Def) -> proc_macro2::TokenStream {
let genesis_config = if let Some(genesis_config) = &def.genesis_config {
genesis_config
} else {
return Default::default()
};
let frame_support = &def.frame_support;
let genesis_config_item = &mut def.item.content.as_mut()
.expect("Checked by def parser").1[genesis_config.index];
match genesis_config_item {
syn::Item::Enum(syn::ItemEnum { attrs, ..}) |
syn::Item::Struct(syn::ItemStruct { attrs, .. }) |
syn::Item::Type(syn::ItemType { attrs, .. }) => {
attrs.push(syn::parse_quote!( #[cfg(feature = "std")] ));
attrs.push(syn::parse_quote!(
#[derive(#frame_support::Serialize, #frame_support::Deserialize)]
));
attrs.push(syn::parse_quote!( #[serde(rename_all = "camelCase")] ));
attrs.push(syn::parse_quote!( #[serde(deny_unknown_fields)] ));
attrs.push(syn::parse_quote!( #[serde(bound(serialize = ""))] ));
attrs.push(syn::parse_quote!( #[serde(bound(deserialize = ""))] ));
},
_ => unreachable!("Checked by genesis_config parser"),
}
Default::default()
}
@@ -0,0 +1,110 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use syn::spanned::Spanned;
/// * implement the individual traits using the Hooks trait
pub fn expand_hooks(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let type_impl_gen = &def.type_impl_generics();
let type_use_gen = &def.type_use_generics();
let pallet_ident = &def.pallet_struct.pallet;
let where_clause = &def.hooks.where_clause;
let frame_system = &def.frame_system;
let hooks_item_span = def.item.content.as_mut()
.expect("Checked by def parser").1[def.hooks.index].span();
quote::quote_spanned!(hooks_item_span =>
impl<#type_impl_gen>
#frame_support::traits::OnFinalize<<T as #frame_system::Config>::BlockNumber>
for #pallet_ident<#type_use_gen> #where_clause
{
fn on_finalize(n: <T as #frame_system::Config>::BlockNumber) {
<
Self as #frame_support::traits::Hooks<
<T as #frame_system::Config>::BlockNumber
>
>::on_finalize(n)
}
}
impl<#type_impl_gen>
#frame_support::traits::OnInitialize<<T as #frame_system::Config>::BlockNumber>
for #pallet_ident<#type_use_gen> #where_clause
{
fn on_initialize(
n: <T as #frame_system::Config>::BlockNumber
) -> #frame_support::weights::Weight {
<
Self as #frame_support::traits::Hooks<
<T as #frame_system::Config>::BlockNumber
>
>::on_initialize(n)
}
}
impl<#type_impl_gen>
#frame_support::traits::OnRuntimeUpgrade
for #pallet_ident<#type_use_gen> #where_clause
{
fn on_runtime_upgrade() -> #frame_support::weights::Weight {
let result = <
Self as #frame_support::traits::Hooks<
<T as #frame_system::Config>::BlockNumber
>
>::on_runtime_upgrade();
#frame_support::crate_to_pallet_version!()
.put_into_storage::<<T as #frame_system::Config>::PalletInfo, Self>();
let additional_write = <
<T as #frame_system::Config>::DbWeight as #frame_support::traits::Get<_>
>::get().writes(1);
result.saturating_add(additional_write)
}
}
impl<#type_impl_gen>
#frame_support::traits::OffchainWorker<<T as #frame_system::Config>::BlockNumber>
for #pallet_ident<#type_use_gen> #where_clause
{
fn offchain_worker(n: <T as #frame_system::Config>::BlockNumber) {
<
Self as #frame_support::traits::Hooks<
<T as #frame_system::Config>::BlockNumber
>
>::offchain_worker(n)
}
}
impl<#type_impl_gen>
#frame_support::traits::IntegrityTest
for #pallet_ident<#type_use_gen> #where_clause
{
fn integrity_test() {
<
Self as #frame_support::traits::Hooks<
<T as #frame_system::Config>::BlockNumber
>
>::integrity_test()
}
}
)
}
@@ -0,0 +1,40 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use proc_macro2::Span;
use crate::pallet::Def;
/// * Provide inherent instance to be used by construct_runtime
/// * Provide Instance0 .. Instance16 for instantiable pallet
pub fn expand_instances(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let inherent_ident = syn::Ident::new(crate::INHERENT_INSTANCE_NAME, Span::call_site());
let instances = if def.config.has_instance {
(0..16).map(|i| syn::Ident::new(&format!("Instance{}", i), Span::call_site())).collect()
} else {
vec![]
};
quote::quote!(
/// Hidden instance generated to be internally used when module is used without
/// instance.
#[doc(hidden)]
pub type #inherent_ident = ();
#( pub use #frame_support::instances::#instances; )*
)
}
@@ -0,0 +1,81 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
mod constants;
mod pallet_struct;
mod call;
mod error;
mod event;
mod storage;
mod hooks;
mod store_trait;
mod instances;
mod genesis_build;
mod genesis_config;
mod type_value;
use crate::pallet::Def;
use quote::ToTokens;
/// Merge where clause together, `where` token span is taken from the first not none one.
pub fn merge_where_clauses(clauses: &[&Option<syn::WhereClause>]) -> Option<syn::WhereClause> {
let mut clauses = clauses.iter().filter_map(|f| f.as_ref());
let mut res = clauses.next()?.clone();
for other in clauses {
res.predicates.extend(other.predicates.iter().cloned())
}
Some(res)
}
/// Expand definition, in particular:
/// * add some bounds and variants to type defined,
/// * create some new types,
/// * impl stuff on them.
pub fn expand(mut def: Def) -> proc_macro2::TokenStream {
let constants = constants::expand_constants(&mut def);
let pallet_struct = pallet_struct::expand_pallet_struct(&mut def);
let call = call::expand_call(&mut def);
let error = error::expand_error(&mut def);
let event = event::expand_event(&mut def);
let storages = storage::expand_storages(&mut def);
let instances = instances::expand_instances(&mut def);
let store_trait = store_trait::expand_store_trait(&mut def);
let hooks = hooks::expand_hooks(&mut def);
let genesis_build = genesis_build::expand_genesis_build(&mut def);
let genesis_config = genesis_config::expand_genesis_config(&mut def);
let type_values = type_value::expand_type_values(&mut def);
let new_items = quote::quote!(
#constants
#pallet_struct
#call
#error
#event
#storages
#instances
#store_trait
#hooks
#genesis_build
#genesis_config
#type_values
);
def.item.content.as_mut().expect("This is checked by parsing").1
.push(syn::Item::Verbatim(new_items));
def.item.into_token_stream()
}
@@ -0,0 +1,117 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
/// * Add derive trait on Pallet
/// * Implement GetPalletVersion on Pallet
/// * Implement OnGenesis on Pallet
/// * Implement ModuleErrorMetadata on Pallet
/// * declare Module type alias for construct_runtime
pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let type_impl_gen = &def.type_impl_generics();
let type_use_gen = &def.type_use_generics();
let type_decl_gen = &def.type_decl_generics();
let pallet_ident = &def.pallet_struct.pallet;
let config_where_clause = &def.config.where_clause;
let pallet_item = {
let pallet_module_items = &mut def.item.content.as_mut().expect("Checked by def").1;
let item = &mut pallet_module_items[def.pallet_struct.index];
if let syn::Item::Struct(item) = item {
item
} else {
unreachable!("Checked by pallet struct parser")
}
};
pallet_item.attrs.push(syn::parse_quote!(
#[derive(
#frame_support::CloneNoBound,
#frame_support::EqNoBound,
#frame_support::PartialEqNoBound,
#frame_support::RuntimeDebugNoBound,
)]
));
let module_error_metadata = if let Some(error_def) = &def.error {
let error_ident = &error_def.error;
quote::quote!(
impl<#type_impl_gen> #frame_support::error::ModuleErrorMetadata
for #pallet_ident<#type_use_gen>
#config_where_clause
{
fn metadata() -> &'static [#frame_support::error::ErrorMetadata] {
<
#error_ident<#type_use_gen> as #frame_support::error::ModuleErrorMetadata
>::metadata()
}
}
)
} else {
quote::quote!(
impl<#type_impl_gen> #frame_support::error::ModuleErrorMetadata
for #pallet_ident<#type_use_gen>
#config_where_clause
{
fn metadata() -> &'static [#frame_support::error::ErrorMetadata] {
&[]
}
}
)
};
quote::quote!(
#module_error_metadata
/// Type alias to `Pallet`, to be used by `construct_runtime`.
///
/// Generated by `pallet` attribute macro.
pub type Module<#type_decl_gen> = #pallet_ident<#type_use_gen>;
// Implement `GetPalletVersion` for `Pallet`
impl<#type_impl_gen> #frame_support::traits::GetPalletVersion
for #pallet_ident<#type_use_gen>
#config_where_clause
{
fn current_version() -> #frame_support::traits::PalletVersion {
#frame_support::crate_to_pallet_version!()
}
fn storage_version() -> Option<#frame_support::traits::PalletVersion> {
let key = #frame_support::traits::PalletVersion::storage_key::<
<T as #frame_system::Config>::PalletInfo, Self
>().expect("Every active pallet has a name in the runtime; qed");
#frame_support::storage::unhashed::get(&key)
}
}
// Implement `OnGenesis` for `Pallet`
impl<#type_impl_gen> #frame_support::traits::OnGenesis
for #pallet_ident<#type_use_gen>
#config_where_clause
{
fn on_genesis() {
#frame_support::crate_to_pallet_version!()
.put_into_storage::<<T as #frame_system::Config>::PalletInfo, Self>();
}
}
)
}
@@ -0,0 +1,267 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use crate::pallet::parse::storage::{Metadata, QueryKind};
use frame_support_procedural_tools::clean_type_string;
/// Generate the prefix_ident related the the storage.
/// prefix_ident is used for the prefix struct to be given to storage as first generic param.
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 {
let frame_support = &def.frame_support;
let frame_system = &def.frame_system;
let type_impl_gen = &def.type_impl_generics();
let type_use_gen = &def.type_use_generics();
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");
};
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 args = if let syn::PathArguments::AngleBracketed(args) =
&mut typ_path.path.segments[0].arguments
{
args
} else {
unreachable!("Checked by def");
};
let prefix_ident = prefix_ident(&storage_def.ident);
args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
}
let entries = def.storages.iter()
.map(|storage| {
let docs = &storage.docs;
let ident = &storage.ident;
let gen = &def.type_use_generics();
let full_ident = quote::quote!( #ident<#gen> );
let metadata_trait = match &storage.metadata {
Metadata::Value { .. } =>
quote::quote!(#frame_support::storage::types::StorageValueMetadata),
Metadata::Map { .. } =>
quote::quote!(#frame_support::storage::types::StorageMapMetadata),
Metadata::DoubleMap { .. } =>
quote::quote!(#frame_support::storage::types::StorageDoubleMapMetadata),
};
let ty = match &storage.metadata {
Metadata::Value { value } => {
let value = clean_type_string(&quote::quote!(#value).to_string());
quote::quote!(
#frame_support::metadata::StorageEntryType::Plain(
#frame_support::metadata::DecodeDifferent::Encode(#value)
)
)
},
Metadata::Map { key, value } => {
let value = clean_type_string(&quote::quote!(#value).to_string());
let key = clean_type_string(&quote::quote!(#key).to_string());
quote::quote!(
#frame_support::metadata::StorageEntryType::Map {
hasher: <#full_ident as #metadata_trait>::HASHER,
key: #frame_support::metadata::DecodeDifferent::Encode(#key),
value: #frame_support::metadata::DecodeDifferent::Encode(#value),
unused: false,
}
)
},
Metadata::DoubleMap { key1, key2, value } => {
let value = clean_type_string(&quote::quote!(#value).to_string());
let key1 = clean_type_string(&quote::quote!(#key1).to_string());
let key2 = clean_type_string(&quote::quote!(#key2).to_string());
quote::quote!(
#frame_support::metadata::StorageEntryType::DoubleMap {
hasher: <#full_ident as #metadata_trait>::HASHER1,
key2_hasher: <#full_ident as #metadata_trait>::HASHER2,
key1: #frame_support::metadata::DecodeDifferent::Encode(#key1),
key2: #frame_support::metadata::DecodeDifferent::Encode(#key2),
value: #frame_support::metadata::DecodeDifferent::Encode(#value),
}
)
}
};
quote::quote_spanned!(storage.ident.span() =>
#frame_support::metadata::StorageEntryMetadata {
name: #frame_support::metadata::DecodeDifferent::Encode(
<#full_ident as #metadata_trait>::NAME
),
modifier: <#full_ident as #metadata_trait>::MODIFIER,
ty: #ty,
default: #frame_support::metadata::DecodeDifferent::Encode(
<#full_ident as #metadata_trait>::DEFAULT
),
documentation: #frame_support::metadata::DecodeDifferent::Encode(&[
#( #docs, )*
]),
}
)
});
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 docs = storage.docs.iter().map(|d| quote::quote!(#[doc = #d]));
let ident = &storage.ident;
let gen = &def.type_use_generics();
let full_ident = quote::quote!( #ident<#gen> );
match &storage.metadata {
Metadata::Value { value } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote!(Option<#value>),
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(getter.span() =>
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#( #docs )*
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!(Option<#value>),
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(getter.span() =>
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#( #docs )*
pub fn #getter<KArg>(k: KArg) -> #query where
KArg: #frame_support::codec::EncodeLike<#key>,
{
<
#full_ident as #frame_support::storage::StorageMap<#key, #value>
>::get(k)
}
}
)
},
Metadata::DoubleMap { key1, key2, value } => {
let query = match storage.query_kind.as_ref().expect("Checked by def") {
QueryKind::OptionQuery => quote::quote!(Option<#value>),
QueryKind::ValueQuery => quote::quote!(#value),
};
quote::quote_spanned!(getter.span() =>
impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
#( #docs )*
pub fn #getter<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #query where
KArg1: #frame_support::codec::EncodeLike<#key1>,
KArg2: #frame_support::codec::EncodeLike<#key2>,
{
<
#full_ident as
#frame_support::storage::StorageDoubleMap<#key1, #key2, #value>
>::get(k1, k2)
}
}
)
},
}
} else {
Default::default()
});
let prefix_structs = def.storages.iter().map(|storage_def| {
let prefix_struct_ident = prefix_ident(&storage_def.ident);
let prefix_struct_vis = &storage_def.vis;
let prefix_struct_const = storage_def.ident.to_string();
let config_where_clause = &def.config.where_clause;
quote::quote_spanned!(storage_def.ident.span() =>
#prefix_struct_vis struct #prefix_struct_ident<#type_use_gen>(
core::marker::PhantomData<(#type_use_gen,)>
);
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("Every active pallet has a name in the runtime; qed")
}
const STORAGE_PREFIX: &'static str = #prefix_struct_const;
}
)
});
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);
quote::quote!(
impl<#type_impl_gen> #pallet_ident<#type_use_gen>
#completed_where_clause
{
#[doc(hidden)]
pub fn storage_metadata() -> #frame_support::metadata::StorageMetadata {
#frame_support::metadata::StorageMetadata {
prefix: #frame_support::metadata::DecodeDifferent::Encode(
<
<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")
),
entries: #frame_support::metadata::DecodeDifferent::Encode(
&[ #( #entries, )* ]
),
}
}
}
#( #getters )*
#( #prefix_structs )*
)
}
@@ -0,0 +1,55 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use syn::spanned::Spanned;
/// If attribute `#[pallet::generate_store(..)]` is defined then:
/// * generate Store trait with all storages,
/// * implement Store trait for Pallet.
pub fn expand_store_trait(def: &mut Def) -> proc_macro2::TokenStream {
let (trait_vis, trait_store) = if let Some(store) = &def.pallet_struct.store {
store
} else {
return Default::default()
};
let type_impl_gen = &def.type_impl_generics();
let type_use_gen = &def.type_use_generics();
let pallet_ident = &def.pallet_struct.pallet;
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 storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::<Vec<_>>();
quote::quote_spanned!(trait_store.span() =>
#trait_vis trait #trait_store {
#(
type #storage_names;
)*
}
impl<#type_impl_gen> #trait_store for #pallet_ident<#type_use_gen>
#completed_where_clause
{
#(
type #storage_names = #storage_names<#type_use_gen>;
)*
}
)
}
@@ -0,0 +1,55 @@
// This file is part of Substrate.
// Copyright (C) 2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::pallet::Def;
use syn::spanned::Spanned;
/// * Generate the struct
/// * implement the `Get<..>` on it
pub fn expand_type_values(def: &mut Def) -> proc_macro2::TokenStream {
let mut expand = quote::quote!();
let frame_support = &def.frame_support;
for type_value in &def.type_values {
// Remove item from module content
let item = &mut def.item.content.as_mut().expect("Checked by def").1[type_value.index];
let span = item.span();
*item = syn::Item::Verbatim(Default::default());
let vis = &type_value.vis;
let ident = &type_value.ident;
let block = &type_value.block;
let type_ = &type_value.type_;
let where_clause = &type_value.where_clause;
let (struct_impl_gen, struct_use_gen) = if type_value.is_generic {
(def.type_impl_generics(), def.type_use_generics())
} else {
(Default::default(), Default::default())
};
expand.extend(quote::quote_spanned!(span =>
#vis struct #ident<#struct_use_gen>(core::marker::PhantomData<((), #struct_use_gen)>);
impl<#struct_impl_gen> #frame_support::traits::Get<#type_> for #ident<#struct_use_gen>
#where_clause
{
fn get() -> #type_ #block
}
));
}
expand
}