mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-22 10:21:04 +00:00
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:
committed by
GitHub
parent
8e3d8a6a09
commit
6dfad0921b
@@ -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("e::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("e::quote!(#value).to_string());
|
||||
let key = clean_type_string("e::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("e::quote!(#value).to_string());
|
||||
let key1 = clean_type_string("e::quote!(#key1).to_string());
|
||||
let key2 = clean_type_string("e::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
|
||||
}
|
||||
Reference in New Issue
Block a user