From 261695075e3d7b97f9a985c63b45f684658d01b1 Mon Sep 17 00:00:00 2001 From: thiolliere Date: Wed, 24 Jun 2020 15:37:27 +0200 Subject: [PATCH] allow pallets to specify an auto_construct_runtime --- bin/node/runtime/src/lib.rs | 2 +- .../procedural/src/construct_runtime/mod.rs | 47 ++++++++++++++++++- .../procedural/src/construct_runtime/parse.rs | 10 +++- frame/support/procedural/src/lib.rs | 27 +++++++++++ frame/support/src/lib.rs | 2 +- frame/treasury/src/lib.rs | 10 ++++ 6 files changed, 92 insertions(+), 6 deletions(-) diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index cf1b0de8f7922..ce5c553a1c4ff 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -819,7 +819,7 @@ construct_runtime!( TechnicalMembership: pallet_membership::::{Module, Call, Storage, Event, Config}, FinalityTracker: pallet_finality_tracker::{Module, Call, Inherent}, Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event}, - Treasury: pallet_treasury::{Module, Call, Storage, Config, Event}, + Treasury: pallet_treasury::{auto}, Contracts: pallet_contracts::{Module, Call, Config, Storage, Event}, Sudo: pallet_sudo::{Module, Call, Config, Storage, Event}, ImOnline: pallet_im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, diff --git a/frame/support/procedural/src/construct_runtime/mod.rs b/frame/support/procedural/src/construct_runtime/mod.rs index cac75490621aa..66085fee5e5f8 100644 --- a/frame/support/procedural/src/construct_runtime/mod.rs +++ b/frame/support/procedural/src/construct_runtime/mod.rs @@ -22,19 +22,62 @@ use frame_support_procedural_tools::{generate_crate_access, generate_hidden_incl use parse::{ModuleDeclaration, RuntimeDefinition, WhereSection}; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; -use quote::quote; -use syn::{Ident, Result, TypePath}; +use quote::{quote, quote_spanned}; +use syn::{Ident, Result, TypePath, spanned::Spanned}; /// The fixed name of the system module. const SYSTEM_MODULE_NAME: &str = "System"; pub fn construct_runtime(input: TokenStream) -> TokenStream { + let input_clone = input.clone().into(); let definition = syn::parse_macro_input!(input as RuntimeDefinition); + + if let Some(preprocess) = construct_runtime_preprocess(&definition, input_clone) + .unwrap_or_else(|e| Some(e.to_compile_error())) + { + return preprocess.into() + } + construct_runtime_parsed(definition) .unwrap_or_else(|e| e.to_compile_error()) .into() } +fn construct_runtime_preprocess( + definition: &RuntimeDefinition, + input_clone: TokenStream2, +) -> Result> { + let mut auto_modules = vec![]; + for module in definition.modules.content.inner.iter() { + if module.module_parts.iter().any(|p| p.keyword.name() == "auto") { + if module.module_parts.len() != 1 { + return Err(syn::Error::new( + module.module_parts[0].keyword.span(), + "Module parts must either provide explicit parts or use `auto` keyword but + cannot combine." + )) + } + + auto_modules.push(module.module.clone()); + } + } + + if !auto_modules.is_empty() { + let mut expand = input_clone; + + while let Some(module) = auto_modules.pop() { + expand = quote_spanned!(module.span() => #module::auto_construct_runtime!{ + construct_runtime! { #expand } + } + ) + } + + Ok(Some(expand)) + } else { + Ok(None) + } +} + fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result { let RuntimeDefinition { name, diff --git a/frame/support/procedural/src/construct_runtime/parse.rs b/frame/support/procedural/src/construct_runtime/parse.rs index 92a71687cc102..ada8d05bd6b4e 100644 --- a/frame/support/procedural/src/construct_runtime/parse.rs +++ b/frame/support/procedural/src/construct_runtime/parse.rs @@ -24,7 +24,7 @@ use syn::{ token, Error, Ident, Result, Token, }; -mod keyword { +pub mod keyword { syn::custom_keyword!(Block); syn::custom_keyword!(NodeBlock); syn::custom_keyword!(UncheckedExtrinsic); @@ -36,6 +36,7 @@ mod keyword { syn::custom_keyword!(Origin); syn::custom_keyword!(Inherent); syn::custom_keyword!(ValidateUnsigned); + syn::custom_keyword!(auto); } #[derive(Debug)] @@ -231,6 +232,7 @@ pub enum ModulePartKeyword { Origin(keyword::Origin), Inherent(keyword::Inherent), ValidateUnsigned(keyword::ValidateUnsigned), + Auto(keyword::auto), } impl Parse for ModulePartKeyword { @@ -253,6 +255,8 @@ impl Parse for ModulePartKeyword { Ok(Self::Inherent(input.parse()?)) } else if lookahead.peek(keyword::ValidateUnsigned) { Ok(Self::ValidateUnsigned(input.parse()?)) + } else if lookahead.peek(keyword::auto) { + Ok(Self::Auto(input.parse()?)) } else { Err(lookahead.error()) } @@ -261,7 +265,7 @@ impl Parse for ModulePartKeyword { impl ModulePartKeyword { /// Returns the name of `Self`. - fn name(&self) -> &'static str { + pub fn name(&self) -> &'static str { match self { Self::Module(_) => "Module", Self::Call(_) => "Call", @@ -271,6 +275,7 @@ impl ModulePartKeyword { Self::Origin(_) => "Origin", Self::Inherent(_) => "Inherent", Self::ValidateUnsigned(_) => "ValidateUnsigned", + Self::Auto(_) => "auto", } } @@ -313,6 +318,7 @@ impl Spanned for ModulePartKeyword { Self::Origin(inner) => inner.span(), Self::Inherent(inner) => inner.span(), Self::ValidateUnsigned(inner) => inner.span(), + Self::Auto(inner) => inner.span(), } } } diff --git a/frame/support/procedural/src/lib.rs b/frame/support/procedural/src/lib.rs index df5665ec48a2f..4e28a5c652d98 100644 --- a/frame/support/procedural/src/lib.rs +++ b/frame/support/procedural/src/lib.rs @@ -23,6 +23,7 @@ mod storage; mod construct_runtime; +mod replace_auto_with; use proc_macro::TokenStream; @@ -260,6 +261,8 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// // Module with instances /// Test3_Instance1: test3::::{Module, Call, Storage, Event, Config, Origin}, /// Test3_DefaultInstance: test3::{Module, Call, Storage, Event, Config, Origin}, +/// +/// TestAuto: pallet_with_auto_construct_runtime::{auto}, /// } /// ) /// ``` @@ -282,6 +285,9 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { /// inherent. /// - `ValidateUnsigned` - If the module validates unsigned extrinsics. /// +/// alternatively if the pallet provide the auto_contruct_runtime macro, parts can be automatically +/// filled using `auto` keyword. +/// /// # Note /// /// The population of the genesis storage depends on the order of modules. So, if one of your @@ -291,3 +297,24 @@ pub fn decl_storage(input: TokenStream) -> TokenStream { pub fn construct_runtime(input: TokenStream) -> TokenStream { construct_runtime::construct_runtime(input) } + +/// Macro than replace the first found `auto` ident with some specified content. +/// +/// # Example: +/// +/// ```nocompile +/// replace_auto_with!( +/// { something or else } // content inside braces can be anything. +/// Some content with at some point { an ident named auto } other auto are ignored +/// ) +/// ``` +/// +/// will generate: +/// +/// ```nocompile +/// Some content with at some point { an ident named something or else } other auto are ignored +/// ``` +#[proc_macro] +pub fn replace_auto_with(input: TokenStream) -> TokenStream { + replace_auto_with::replace_auto_with(input) +} diff --git a/frame/support/src/lib.rs b/frame/support/src/lib.rs index 196bddbdf5bce..7ba6066626437 100644 --- a/frame/support/src/lib.rs +++ b/frame/support/src/lib.rs @@ -267,7 +267,7 @@ macro_rules! ord_parameter_types { } #[doc(inline)] -pub use frame_support_procedural::{decl_storage, construct_runtime}; +pub use frame_support_procedural::{decl_storage, construct_runtime, replace_auto_with}; /// Return Err of the expression: `return Err($expression);`. /// diff --git a/frame/treasury/src/lib.rs b/frame/treasury/src/lib.rs index 861a652e52995..84b2c21c96dc5 100644 --- a/frame/treasury/src/lib.rs +++ b/frame/treasury/src/lib.rs @@ -111,6 +111,16 @@ type BalanceOf = <::Currency as Currency< = <::Currency as Currency<::AccountId>>::PositiveImbalance; type NegativeImbalanceOf = <::Currency as Currency<::AccountId>>::NegativeImbalance; +#[macro_export] +macro_rules! auto_construct_runtime { + ( $( $t:tt )* ) => { + frame_support::replace_auto_with! { + { Module, Call, Storage, Config, Event } + $( $t )* + } + } +} + pub trait Trait: frame_system::Trait { /// The treasury's module id, used for deriving its sovereign account ID. type ModuleId: Get;