mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-20 10:31:03 +00:00
Default Pallet Config Trait / derive_impl (#13454)
* first draft, probably won't work * first draft, probably won't work * good progress.. * good milestone, still a lot to do. * EVERYTHING WORKS * Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * Update frame/support/procedural/src/derive_impl.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * clean up + cargo fmt * import tokens WIP * export_tokens working with impl Trait * WIP / notes * use macro_magic 0.2.0's export_tokens to access foreign items * token importing working properly using macro_magic 0.2.5 * combine_impls almost working * successfully get foreign path via macro_magic 0.2.6 * combine_impls using implementing_type generics * working + clean up * more clean up * decrease rightwards drift and add docs to combine_impls * add support for macros to impl_item_ident in case we hit that * add docs for impl_item_ident method * fix no_std issues * re-export of macro_magic working in pallets 🎉 * clean up + fully resolve no_std issue with macro_magic with v0.2.11 * remove trait item code for different trait item types since this is now handled directly by combine_impls * clean up * remove dev comments * only generate default trait if #[pallet::default_trait] is attached * authorship and most other pallets now compiling * compiling 🎉 * add check for more than two pallet attributes on Config trait * remove unused import in nomination-pool * clean up debug code * upgrade to macro_magic v0.2.12 * add neater #[register_default_config(SomeIdent)] macro * really just a thin wrapper around #[export_tokens] * upgrade to macro_magic 0.3.1 * rewrite parsing to be compatible with syn 2.x, compiling 🎉 * remove unused keywords * macro stubs for the new pallet:: macros, preliminary docs * upgrade to macro_magic v0.3.2 * rename register_default_config => register_default_impl * bump to macro_magic v0.3.3 * custom disambiguation_path working as 2nd arg to derive_impl * overhaul docs * fixes, ident-style paths shortcut working * remove ident-style shortcut because it makes testing difficult * add passing UI tests for derive_impl * switch to `ForeignPath as DisambiguationPath` syntax + update docs * add UI test for bad foreign path * add UI test for bad disambiguation path * add UI test for missing disambiguation path * add UI test for attached to non impl * fix derive_impl_attr_args_parsing test * move tests to bottom * fix nightly issue * add doc notes on importing/re-exporting * remove explicit use of macro_magic::use_attr Co-authored-by: Bastian Köcher <git@kchr.de> * use explicit macro_magic::use_attr Co-authored-by: Bastian Köcher <git@kchr.de> * remove unneeded {} Co-authored-by: Bastian Köcher <git@kchr.de> * remove unneeded collect Co-authored-by: Bastian Köcher <git@kchr.de> * add docs for TestDefaultConfig * remove unneeded `#[export_tokens]` on `DefaultConfig` * add docs for auto-generated `DefaultConfig` * no need to clone Co-authored-by: Bastian Köcher <git@kchr.de> * clean up combine_impls + compiling again * remove unused dependency * simplify struct definition Co-authored-by: Bastian Köcher <git@kchr.de> * fix register_default_impl docs * reduce rightward drift / refactor Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * fix derive_impl after keith's changes * simplify disambiguation_path calculation Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * compiling again * simplify parsing of trait item Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * rename preludes => prelude Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * fix other places where we used preludes instead of prelude * fix indents * simplify PalletAttr parsing Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> * go back to having no_default and constant as keywords * make it more clear that disambiguation_path is optional * make default_trait_items just a Vec instead of Option<Vec> * rename foreign_path => default_impl_path within substrate * fix docs * Change {} to ; Co-authored-by: Bastian Köcher <git@kchr.de> * highlight full end-to-end example with link * add pallet-default-config-example, start by copying dev mode code * update dev-mode specific docs * use Person and Points instead of Dummy and Bar * add docs to example pallet * revert changes to pallets other than the default config example * fix outdated references to basic example pallet * re-order docs to be a bit more clear * better errors for extra attributes * add UI tests for duplicate/extra attributes on trait items * change `#[pallet::default_config]` to option on `#[pallet::config()]` * update UI tests * add UI test covering missing `#[pallet::config(with_default)]` when `#[pallet::no_default]` is used * add note about new optional conventions * improve docs about `DefaultConfig` and link to these from a few places * fix doc comment * fix old comment referencing `pallet::default_config` * use u32 instead of u64 for block number Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * use () instead of u32 for `AccountData` Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * use ConstU32<10> for BlockHashCount instead of ConstU64<10> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> * people are not dummies Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> * fix wording Co-authored-by: Just van Stam <vstam1@users.noreply.github.com> * Person => People and compiling again * add docs for `prelude` module in frame_system * update Cargo.lock * cleaner example * tweaks * update docs more * update docs more * update docs more * update docs more * fix ui tests * err * Update frame/support/test/tests/pallet_ui.rs * update ui tests --------- Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Sam Johnson <sam@durosoft.com> Co-authored-by: parity-processbot <> Co-authored-by: Bastian Köcher <git@kchr.de> Co-authored-by: Keith Yeung <kungfukeith11@gmail.com> Co-authored-by: Liam Aharon <liam.aharon@hotmail.com> Co-authored-by: Just van Stam <vstam1@users.noreply.github.com>
This commit is contained in:
@@ -16,14 +16,17 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::pallet::Def;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_quote, Item};
|
||||
|
||||
///
|
||||
/// * Generate default rust doc
|
||||
pub fn expand_config(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
pub fn expand_config(def: &mut Def) -> TokenStream {
|
||||
let config = &def.config;
|
||||
let config_item = {
|
||||
let item = &mut def.item.content.as_mut().expect("Checked by def parser").1[config.index];
|
||||
if let syn::Item::Trait(item) = item {
|
||||
if let Item::Trait(item) = item {
|
||||
item
|
||||
} else {
|
||||
unreachable!("Checked by config parser")
|
||||
@@ -32,8 +35,9 @@ pub fn expand_config(def: &mut Def) -> proc_macro2::TokenStream {
|
||||
|
||||
config_item.attrs.insert(
|
||||
0,
|
||||
syn::parse_quote!(
|
||||
#[doc = r"Configuration trait of this pallet.
|
||||
parse_quote!(
|
||||
#[doc = r"
|
||||
Configuration trait of this pallet.
|
||||
|
||||
The main purpose of this trait is to act as an interface between this pallet and the runtime in
|
||||
which it is embedded in. A type, function, or constant in this trait is essentially left to be
|
||||
@@ -44,5 +48,25 @@ Consequently, a runtime that wants to include this pallet must implement this tr
|
||||
),
|
||||
);
|
||||
|
||||
Default::default()
|
||||
// we only emit `DefaultConfig` if there are trait items, so an empty `DefaultConfig` is
|
||||
// impossible consequently
|
||||
if config.default_sub_trait.len() > 0 {
|
||||
let trait_items = &config.default_sub_trait;
|
||||
quote!(
|
||||
/// Based on [`Config`]. Auto-generated by
|
||||
/// [`#[pallet::config(with_default)]`](`frame_support::pallet_macros::config`).
|
||||
/// Can be used in tandem with
|
||||
/// [`#[register_default_config]`](`frame_support::register_default_config`) and
|
||||
/// [`#[derive_impl]`](`frame_support::derive_impl`) to derive test config traits
|
||||
/// based on existing pallet config traits in a safe and developer-friendly way.
|
||||
///
|
||||
/// See [here](`frame_support::pallet_macros::config`) for more information and caveats about
|
||||
/// the auto-generated `DefaultConfig` trait and how it is generated.
|
||||
pub trait DefaultConfig {
|
||||
#(#trait_items)*
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
use super::helper;
|
||||
use frame_support_procedural_tools::get_doc_literals;
|
||||
use quote::ToTokens;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{spanned::Spanned, token, Token};
|
||||
|
||||
/// List of additional token to be used for parsing.
|
||||
mod keyword {
|
||||
@@ -27,12 +27,14 @@ mod keyword {
|
||||
syn::custom_keyword!(T);
|
||||
syn::custom_keyword!(I);
|
||||
syn::custom_keyword!(config);
|
||||
syn::custom_keyword!(pallet);
|
||||
syn::custom_keyword!(IsType);
|
||||
syn::custom_keyword!(RuntimeEvent);
|
||||
syn::custom_keyword!(Event);
|
||||
syn::custom_keyword!(constant);
|
||||
syn::custom_keyword!(frame_system);
|
||||
syn::custom_keyword!(disable_frame_system_supertrait_check);
|
||||
syn::custom_keyword!(no_default);
|
||||
syn::custom_keyword!(constant);
|
||||
}
|
||||
|
||||
/// Input definition for the pallet config.
|
||||
@@ -52,6 +54,12 @@ pub struct ConfigDef {
|
||||
pub where_clause: Option<syn::WhereClause>,
|
||||
/// The span of the pallet::config attribute.
|
||||
pub attr_span: proc_macro2::Span,
|
||||
/// Whether a default sub-trait should be generated.
|
||||
///
|
||||
/// Contains default sub-trait items (instantiated by `#[pallet::config(with_default)]`).
|
||||
/// Vec will be empty if `#[pallet::config(with_default)]` is not specified or if there are
|
||||
/// no trait items
|
||||
pub default_sub_trait: Vec<syn::TraitItem>,
|
||||
}
|
||||
|
||||
/// Input definition for a constant in pallet config.
|
||||
@@ -123,40 +131,28 @@ impl syn::parse::Parse for DisableFrameSystemSupertraitCheck {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse for `#[pallet::constant]`
|
||||
pub struct TypeAttrConst {
|
||||
pound_token: syn::Token![#],
|
||||
bracket_token: syn::token::Bracket,
|
||||
pallet_ident: syn::Ident,
|
||||
path_sep_token: syn::token::PathSep,
|
||||
constant_keyword: keyword::constant,
|
||||
/// Parsing for the `typ` portion of `PalletAttr`
|
||||
#[derive(derive_syn_parse::Parse, PartialEq, Eq)]
|
||||
pub enum PalletAttrType {
|
||||
#[peek(keyword::no_default, name = "no_default")]
|
||||
NoDefault(keyword::no_default),
|
||||
#[peek(keyword::constant, name = "constant")]
|
||||
Constant(keyword::constant),
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for TypeAttrConst {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let pound_token = input.parse::<syn::Token![#]>()?;
|
||||
let content;
|
||||
let bracket_token = syn::bracketed!(content in input);
|
||||
let pallet_ident = content.parse::<syn::Ident>()?;
|
||||
let path_sep_token = content.parse::<syn::Token![::]>()?;
|
||||
let constant_keyword = content.parse::<keyword::constant>()?;
|
||||
|
||||
Ok(Self { pound_token, bracket_token, pallet_ident, path_sep_token, constant_keyword })
|
||||
}
|
||||
/// Parsing for `#[pallet::X]`
|
||||
#[derive(derive_syn_parse::Parse)]
|
||||
pub struct PalletAttr {
|
||||
_pound: Token![#],
|
||||
#[bracket]
|
||||
_bracket: token::Bracket,
|
||||
#[inside(_bracket)]
|
||||
_pallet: keyword::pallet,
|
||||
#[prefix(Token![::] in _bracket)]
|
||||
#[inside(_bracket)]
|
||||
typ: PalletAttrType,
|
||||
}
|
||||
|
||||
impl ToTokens for TypeAttrConst {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
self.pound_token.to_tokens(tokens);
|
||||
self.bracket_token.surround(tokens, |tokens| {
|
||||
self.pallet_ident.to_tokens(tokens);
|
||||
self.path_sep_token.to_tokens(tokens);
|
||||
self.constant_keyword.to_tokens(tokens);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse for `$ident::Config`
|
||||
pub struct ConfigBoundParse(syn::Ident);
|
||||
|
||||
impl syn::parse::Parse for ConfigBoundParse {
|
||||
@@ -307,6 +303,7 @@ impl ConfigDef {
|
||||
attr_span: proc_macro2::Span,
|
||||
index: usize,
|
||||
item: &mut syn::Item,
|
||||
enable_default: bool,
|
||||
) -> syn::Result<Self> {
|
||||
let item = if let syn::Item::Trait(item) = item {
|
||||
item
|
||||
@@ -344,38 +341,59 @@ impl ConfigDef {
|
||||
|
||||
let mut has_event_type = false;
|
||||
let mut consts_metadata = vec![];
|
||||
let mut default_sub_trait = vec![];
|
||||
for trait_item in &mut item.items {
|
||||
// Parse for event
|
||||
has_event_type =
|
||||
has_event_type || check_event_type(frame_system, trait_item, has_instance)?;
|
||||
let is_event = check_event_type(frame_system, trait_item, has_instance)?;
|
||||
has_event_type = has_event_type || is_event;
|
||||
|
||||
// Parse for constant
|
||||
let type_attrs_const: Vec<TypeAttrConst> = helper::take_item_pallet_attrs(trait_item)?;
|
||||
let mut already_no_default = false;
|
||||
let mut already_constant = false;
|
||||
|
||||
if type_attrs_const.len() > 1 {
|
||||
let msg = "Invalid attribute in pallet::config, only one attribute is expected";
|
||||
return Err(syn::Error::new(type_attrs_const[1].span(), msg))
|
||||
}
|
||||
|
||||
if type_attrs_const.len() == 1 {
|
||||
match trait_item {
|
||||
syn::TraitItem::Type(ref type_) => {
|
||||
let constant = ConstMetadataDef::try_from(type_)?;
|
||||
consts_metadata.push(constant);
|
||||
while let Ok(Some(pallet_attr)) =
|
||||
helper::take_first_item_pallet_attr::<PalletAttr>(trait_item)
|
||||
{
|
||||
match (pallet_attr.typ, &trait_item) {
|
||||
(PalletAttrType::Constant(_), syn::TraitItem::Type(ref typ)) => {
|
||||
if already_constant {
|
||||
return Err(syn::Error::new(
|
||||
pallet_attr._bracket.span.join(),
|
||||
"Duplicate #[pallet::constant] attribute not allowed.",
|
||||
))
|
||||
}
|
||||
already_constant = true;
|
||||
consts_metadata.push(ConstMetadataDef::try_from(typ)?);
|
||||
},
|
||||
_ => {
|
||||
let msg =
|
||||
"Invalid pallet::constant in pallet::config, expected type trait \
|
||||
item";
|
||||
return Err(syn::Error::new(trait_item.span(), msg))
|
||||
(PalletAttrType::Constant(_), _) =>
|
||||
return Err(syn::Error::new(
|
||||
trait_item.span(),
|
||||
"Invalid #[pallet::constant] in #[pallet::config], expected type item",
|
||||
)),
|
||||
(PalletAttrType::NoDefault(_), _) => {
|
||||
if !enable_default {
|
||||
return Err(syn::Error::new(
|
||||
pallet_attr._bracket.span.join(),
|
||||
"`#[pallet:no_default]` can only be used if `#[pallet::config(with_default)]` \
|
||||
has been specified"
|
||||
))
|
||||
}
|
||||
if already_no_default {
|
||||
return Err(syn::Error::new(
|
||||
pallet_attr._bracket.span.join(),
|
||||
"Duplicate #[pallet::no_default] attribute not allowed.",
|
||||
))
|
||||
}
|
||||
already_no_default = true;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if !already_no_default && !is_event && enable_default {
|
||||
default_sub_trait.push(trait_item.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let attr: Option<DisableFrameSystemSupertraitCheck> =
|
||||
helper::take_first_item_pallet_attr(&mut item.attrs)?;
|
||||
|
||||
let disable_system_supertrait_check = attr.is_some();
|
||||
|
||||
let has_frame_system_supertrait = item.supertraits.iter().any(|s| {
|
||||
@@ -407,6 +425,14 @@ impl ConfigDef {
|
||||
return Err(syn::Error::new(item.span(), msg))
|
||||
}
|
||||
|
||||
Ok(Self { index, has_instance, consts_metadata, has_event_type, where_clause, attr_span })
|
||||
Ok(Self {
|
||||
index,
|
||||
has_instance,
|
||||
consts_metadata,
|
||||
has_event_type,
|
||||
where_clause,
|
||||
attr_span,
|
||||
default_sub_trait,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ pub trait MutItemAttrs {
|
||||
}
|
||||
|
||||
/// Take the first pallet attribute (e.g. attribute like `#[pallet..]`) and decode it to `Attr`
|
||||
pub fn take_first_item_pallet_attr<Attr>(item: &mut impl MutItemAttrs) -> syn::Result<Option<Attr>>
|
||||
pub(crate) fn take_first_item_pallet_attr<Attr>(
|
||||
item: &mut impl MutItemAttrs,
|
||||
) -> syn::Result<Option<Attr>>
|
||||
where
|
||||
Attr: syn::parse::Parse,
|
||||
{
|
||||
@@ -64,7 +66,7 @@ where
|
||||
}
|
||||
|
||||
/// Take all the pallet attributes (e.g. attribute like `#[pallet..]`) and decode them to `Attr`
|
||||
pub fn take_item_pallet_attrs<Attr>(item: &mut impl MutItemAttrs) -> syn::Result<Vec<Attr>>
|
||||
pub(crate) fn take_item_pallet_attrs<Attr>(item: &mut impl MutItemAttrs) -> syn::Result<Vec<Attr>>
|
||||
where
|
||||
Attr: syn::parse::Parse,
|
||||
{
|
||||
|
||||
@@ -100,8 +100,14 @@ impl Def {
|
||||
let pallet_attr: Option<PalletAttr> = helper::take_first_item_pallet_attr(item)?;
|
||||
|
||||
match pallet_attr {
|
||||
Some(PalletAttr::Config(span)) if config.is_none() =>
|
||||
config = Some(config::ConfigDef::try_from(&frame_system, span, index, item)?),
|
||||
Some(PalletAttr::Config(span, with_default)) if config.is_none() =>
|
||||
config = Some(config::ConfigDef::try_from(
|
||||
&frame_system,
|
||||
span,
|
||||
index,
|
||||
item,
|
||||
with_default,
|
||||
)?),
|
||||
Some(PalletAttr::Pallet(span)) if pallet_struct.is_none() => {
|
||||
let p = pallet_struct::PalletStructDef::try_from(span, index, item)?;
|
||||
pallet_struct = Some(p);
|
||||
@@ -405,6 +411,7 @@ mod keyword {
|
||||
syn::custom_keyword!(weight);
|
||||
syn::custom_keyword!(event);
|
||||
syn::custom_keyword!(config);
|
||||
syn::custom_keyword!(with_default);
|
||||
syn::custom_keyword!(hooks);
|
||||
syn::custom_keyword!(inherent);
|
||||
syn::custom_keyword!(error);
|
||||
@@ -423,7 +430,7 @@ mod keyword {
|
||||
/// Parse attributes for item in pallet module
|
||||
/// syntax must be `pallet::` (e.g. `#[pallet::config]`)
|
||||
enum PalletAttr {
|
||||
Config(proc_macro2::Span),
|
||||
Config(proc_macro2::Span, bool),
|
||||
Pallet(proc_macro2::Span),
|
||||
Hooks(proc_macro2::Span),
|
||||
/// A `#[pallet::call]` with optional attributes to specialize the behaviour.
|
||||
@@ -480,7 +487,7 @@ enum PalletAttr {
|
||||
impl PalletAttr {
|
||||
fn span(&self) -> proc_macro2::Span {
|
||||
match self {
|
||||
Self::Config(span) => *span,
|
||||
Self::Config(span, _) => *span,
|
||||
Self::Pallet(span) => *span,
|
||||
Self::Hooks(span) => *span,
|
||||
Self::RuntimeCall(_, span) => *span,
|
||||
@@ -509,7 +516,14 @@ impl syn::parse::Parse for PalletAttr {
|
||||
|
||||
let lookahead = content.lookahead1();
|
||||
if lookahead.peek(keyword::config) {
|
||||
Ok(PalletAttr::Config(content.parse::<keyword::config>()?.span()))
|
||||
let span = content.parse::<keyword::config>()?.span();
|
||||
let with_default = content.peek(syn::token::Paren);
|
||||
if with_default {
|
||||
let inside_config;
|
||||
let _paren = syn::parenthesized!(inside_config in content);
|
||||
inside_config.parse::<keyword::with_default>()?;
|
||||
}
|
||||
Ok(PalletAttr::Config(span, with_default))
|
||||
} else if lookahead.peek(keyword::pallet) {
|
||||
Ok(PalletAttr::Pallet(content.parse::<keyword::pallet>()?.span()))
|
||||
} else if lookahead.peek(keyword::hooks) {
|
||||
|
||||
Reference in New Issue
Block a user