Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 6dddfb8

Browse files
committed
allow pallets to specify an auto_construct_runtime
1 parent c771821 commit 6dddfb8

File tree

7 files changed

+164
-6
lines changed

7 files changed

+164
-6
lines changed

bin/node/runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ construct_runtime!(
819819
TechnicalMembership: pallet_membership::<Instance1>::{Module, Call, Storage, Event<T>, Config<T>},
820820
FinalityTracker: pallet_finality_tracker::{Module, Call, Inherent},
821821
Grandpa: pallet_grandpa::{Module, Call, Storage, Config, Event},
822-
Treasury: pallet_treasury::{Module, Call, Storage, Config, Event<T>},
822+
Treasury: pallet_treasury::{auto},
823823
Contracts: pallet_contracts::{Module, Call, Config, Storage, Event<T>},
824824
Sudo: pallet_sudo::{Module, Call, Config<T>, Storage, Event<T>},
825825
ImOnline: pallet_im_online::{Module, Call, Storage, Event<T>, ValidateUnsigned, Config<T>},

frame/support/procedural/src/construct_runtime/mod.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,62 @@ use frame_support_procedural_tools::{generate_crate_access, generate_hidden_incl
2222
use parse::{ModuleDeclaration, RuntimeDefinition, WhereSection};
2323
use proc_macro::TokenStream;
2424
use proc_macro2::TokenStream as TokenStream2;
25-
use quote::quote;
26-
use syn::{Ident, Result, TypePath};
25+
use quote::{quote, quote_spanned};
26+
use syn::{Ident, Result, TypePath, spanned::Spanned};
2727

2828
/// The fixed name of the system module.
2929
const SYSTEM_MODULE_NAME: &str = "System";
3030

3131
pub fn construct_runtime(input: TokenStream) -> TokenStream {
32+
let input_clone = input.clone().into();
3233
let definition = syn::parse_macro_input!(input as RuntimeDefinition);
34+
35+
if let Some(preprocess) = construct_runtime_preprocess(&definition, input_clone)
36+
.unwrap_or_else(|e| Some(e.to_compile_error()))
37+
{
38+
return preprocess.into()
39+
}
40+
3341
construct_runtime_parsed(definition)
3442
.unwrap_or_else(|e| e.to_compile_error())
3543
.into()
3644
}
3745

46+
fn construct_runtime_preprocess(
47+
definition: &RuntimeDefinition,
48+
input_clone: TokenStream2,
49+
) -> Result<Option<TokenStream2>> {
50+
let mut auto_modules = vec![];
51+
for module in definition.modules.content.inner.iter() {
52+
if module.module_parts.iter().any(|p| p.keyword.name() == "auto") {
53+
if module.module_parts.len() != 1 {
54+
return Err(syn::Error::new(
55+
module.module_parts[0].keyword.span(),
56+
"Module parts must either provide explicit parts or use `auto` keyword but
57+
cannot combine."
58+
))
59+
}
60+
61+
auto_modules.push(module.module.clone());
62+
}
63+
}
64+
65+
if !auto_modules.is_empty() {
66+
let mut expand = input_clone;
67+
68+
while let Some(module) = auto_modules.pop() {
69+
expand = quote_spanned!(module.span() => #module::auto_construct_runtime!{
70+
construct_runtime! { #expand }
71+
}
72+
)
73+
}
74+
75+
Ok(Some(expand))
76+
} else {
77+
Ok(None)
78+
}
79+
}
80+
3881
fn construct_runtime_parsed(definition: RuntimeDefinition) -> Result<TokenStream2> {
3982
let RuntimeDefinition {
4083
name,

frame/support/procedural/src/construct_runtime/parse.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use syn::{
2424
token, Error, Ident, Result, Token,
2525
};
2626

27-
mod keyword {
27+
pub mod keyword {
2828
syn::custom_keyword!(Block);
2929
syn::custom_keyword!(NodeBlock);
3030
syn::custom_keyword!(UncheckedExtrinsic);
@@ -36,6 +36,7 @@ mod keyword {
3636
syn::custom_keyword!(Origin);
3737
syn::custom_keyword!(Inherent);
3838
syn::custom_keyword!(ValidateUnsigned);
39+
syn::custom_keyword!(auto);
3940
}
4041

4142
#[derive(Debug)]
@@ -231,6 +232,7 @@ pub enum ModulePartKeyword {
231232
Origin(keyword::Origin),
232233
Inherent(keyword::Inherent),
233234
ValidateUnsigned(keyword::ValidateUnsigned),
235+
Auto(keyword::auto),
234236
}
235237

236238
impl Parse for ModulePartKeyword {
@@ -253,6 +255,8 @@ impl Parse for ModulePartKeyword {
253255
Ok(Self::Inherent(input.parse()?))
254256
} else if lookahead.peek(keyword::ValidateUnsigned) {
255257
Ok(Self::ValidateUnsigned(input.parse()?))
258+
} else if lookahead.peek(keyword::auto) {
259+
Ok(Self::Auto(input.parse()?))
256260
} else {
257261
Err(lookahead.error())
258262
}
@@ -261,7 +265,7 @@ impl Parse for ModulePartKeyword {
261265

262266
impl ModulePartKeyword {
263267
/// Returns the name of `Self`.
264-
fn name(&self) -> &'static str {
268+
pub fn name(&self) -> &'static str {
265269
match self {
266270
Self::Module(_) => "Module",
267271
Self::Call(_) => "Call",
@@ -271,6 +275,7 @@ impl ModulePartKeyword {
271275
Self::Origin(_) => "Origin",
272276
Self::Inherent(_) => "Inherent",
273277
Self::ValidateUnsigned(_) => "ValidateUnsigned",
278+
Self::Auto(_) => "auto",
274279
}
275280
}
276281

@@ -313,6 +318,7 @@ impl Spanned for ModulePartKeyword {
313318
Self::Origin(inner) => inner.span(),
314319
Self::Inherent(inner) => inner.span(),
315320
Self::ValidateUnsigned(inner) => inner.span(),
321+
Self::Auto(inner) => inner.span(),
316322
}
317323
}
318324
}

frame/support/procedural/src/lib.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
mod storage;
2525
mod construct_runtime;
26+
mod replace_auto_with;
2627

2728
use proc_macro::TokenStream;
2829

@@ -260,6 +261,8 @@ pub fn decl_storage(input: TokenStream) -> TokenStream {
260261
/// // Module with instances
261262
/// Test3_Instance1: test3::<Instance1>::{Module, Call, Storage, Event<T, I>, Config<T, I>, Origin<T, I>},
262263
/// Test3_DefaultInstance: test3::{Module, Call, Storage, Event<T>, Config<T>, Origin<T>},
264+
///
265+
/// TestAuto: pallet_with_auto_construct_runtime::{auto},
263266
/// }
264267
/// )
265268
/// ```
@@ -282,6 +285,9 @@ pub fn decl_storage(input: TokenStream) -> TokenStream {
282285
/// inherent.
283286
/// - `ValidateUnsigned` - If the module validates unsigned extrinsics.
284287
///
288+
/// alternatively if the pallet provide the auto_contruct_runtime macro, parts can be automatically
289+
/// filled using `auto` keyword.
290+
///
285291
/// # Note
286292
///
287293
/// 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 {
291297
pub fn construct_runtime(input: TokenStream) -> TokenStream {
292298
construct_runtime::construct_runtime(input)
293299
}
300+
301+
/// Macro than replace the first found `auto` ident with some specified content.
302+
///
303+
/// # Example:
304+
///
305+
/// ```nocompile
306+
/// replace_auto_with!(
307+
/// { something or else } // content inside braces can be anything.
308+
/// Some content with at some point { an ident named auto } other auto are ignored
309+
/// )
310+
/// ```
311+
///
312+
/// will generate:
313+
///
314+
/// ```nocompile
315+
/// Some content with at some point { an ident named something or else } other auto are ignored
316+
/// ```
317+
#[proc_macro]
318+
pub fn replace_auto_with(input: TokenStream) -> TokenStream {
319+
replace_auto_with::replace_auto_with(input)
320+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use proc_macro2::{TokenStream, TokenTree, Group};
2+
use syn::spanned::Spanned;
3+
use std::iter::once;
4+
5+
pub fn replace_auto_with(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
6+
let def = syn::parse_macro_input!(input as ReplaceAutoWithDef);
7+
let replace_in_span = def.replace_in.span();
8+
9+
match replace_in_stream(&mut Some(def.replace_with), def.replace_in) {
10+
Ok(stream) => stream.into(),
11+
Err(_) => {
12+
syn::Error::new(replace_in_span, "cannot find `auto` ident in given token stream")
13+
.to_compile_error().into()
14+
},
15+
}
16+
}
17+
struct ReplaceAutoWithDef {
18+
replace_with: TokenStream,
19+
replace_in: TokenStream,
20+
}
21+
22+
impl syn::parse::Parse for ReplaceAutoWithDef {
23+
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
24+
let replace_with;
25+
let _replace_with_bracket: syn::token::Brace = syn::braced!(replace_with in input);
26+
let replace_with: TokenStream = replace_with.parse()?;
27+
Ok(Self {
28+
replace_with,
29+
replace_in: input.parse()?,
30+
})
31+
}
32+
}
33+
34+
// Replace the first found `auto` ident by content of `with`. `with` must be some (Option is used
35+
// for internal simplification).
36+
fn replace_in_stream(
37+
with: &mut Option<TokenStream>,
38+
stream: TokenStream
39+
) -> Result<TokenStream, ()> {
40+
assert!(with.is_some(), "`with` must be some, Option is used because `with` is used only once");
41+
42+
let mut stream = stream.into_iter();
43+
let mut builded_replaced = TokenStream::new();
44+
45+
loop {
46+
match stream.next() {
47+
Some(TokenTree::Group(group)) => {
48+
let stream = group.stream();
49+
match replace_in_stream(with, stream) {
50+
Ok(stream) => {
51+
builded_replaced.extend(once(TokenTree::Group(Group::new(group.delimiter(), stream))));
52+
break;
53+
}
54+
Err(_) => {
55+
builded_replaced.extend(once(TokenTree::Group(group)));
56+
}
57+
}
58+
}
59+
Some(TokenTree::Ident(ident)) if ident == "auto" => {
60+
builded_replaced.extend(once(with.take().expect("with is used to replace only once")));
61+
break;
62+
}
63+
Some(other) => builded_replaced.extend(once(other)),
64+
None => return Err(())
65+
}
66+
}
67+
68+
builded_replaced.extend(stream);
69+
70+
Ok(builded_replaced)
71+
}
72+

frame/support/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ macro_rules! ord_parameter_types {
267267
}
268268

269269
#[doc(inline)]
270-
pub use frame_support_procedural::{decl_storage, construct_runtime};
270+
pub use frame_support_procedural::{decl_storage, construct_runtime, replace_auto_with};
271271

272272
/// Return Err of the expression: `return Err($expression);`.
273273
///

frame/treasury/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trai
111111
type PositiveImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::PositiveImbalance;
112112
type NegativeImbalanceOf<T> = <<T as Trait>::Currency as Currency<<T as frame_system::Trait>::AccountId>>::NegativeImbalance;
113113

114+
#[macro_export]
115+
macro_rules! auto_construct_runtime {
116+
( $( $t:tt )* ) => {
117+
frame_support::replace_auto_with! {
118+
{ Module, Call, Storage, Config, Event<T> }
119+
$( $t )*
120+
}
121+
}
122+
}
123+
114124
pub trait Trait: frame_system::Trait {
115125
/// The treasury's module id, used for deriving its sovereign account ID.
116126
type ModuleId: Get<ModuleId>;

0 commit comments

Comments
 (0)