Remove default expansion from construct_runtime! (#4937)

This removes the following syntactic sugar from `construct_runtime!`:

- Expansion of `default` to the default set of module parts
- Expansion of `System: system` to the default set of module parts

The macro now requires the user to provide all the module parts of a pallet.
This commit is contained in:
Bastian Köcher
2020-02-15 14:40:29 +01:00
committed by GitHub
parent 4053201046
commit 625e963aa2
18 changed files with 158 additions and 221 deletions
@@ -217,8 +217,8 @@ fn decl_runtime_metadata<'a>(
let filtered_names: Vec<_> = module_declaration
.module_parts()
.into_iter()
.filter(|part| part.name != "Module")
.map(|part| part.name.clone())
.filter(|part| part.name() != "Module")
.map(|part| part.ident())
.collect();
(module_declaration, filtered_names)
})
@@ -27,6 +27,14 @@ mod keyword {
syn::custom_keyword!(Block);
syn::custom_keyword!(NodeBlock);
syn::custom_keyword!(UncheckedExtrinsic);
syn::custom_keyword!(Module);
syn::custom_keyword!(Call);
syn::custom_keyword!(Storage);
syn::custom_keyword!(Event);
syn::custom_keyword!(Config);
syn::custom_keyword!(Origin);
syn::custom_keyword!(Inherent);
syn::custom_keyword!(ValidateUnsigned);
}
#[derive(Debug)]
@@ -145,7 +153,7 @@ pub struct ModuleDeclaration {
pub name: Ident,
pub module: Ident,
pub instance: Option<Ident>,
pub details: Option<ext::Braces<ext::Punctuated<ModuleEntry, Token![,]>>>,
pub module_parts: Vec<ModulePart>,
}
impl Parse for ModuleDeclaration {
@@ -162,160 +170,183 @@ impl Parse for ModuleDeclaration {
} else {
None
};
let details = if input.peek(Token![::]) {
let _: Token![::] = input.parse()?;
Some(input.parse()?)
} else {
None
};
let _: Token![::] = input.parse()?;
let module_parts = parse_module_parts(input)?;
let parsed = Self {
name,
module,
instance,
details,
module_parts,
};
if let Some(ref details) = parsed.details {
let parts = &details.content.inner;
let mut resolved = HashSet::new();
let has_default = parts.into_iter().any(|m| m.is_default());
for entry in parts {
match entry {
ModuleEntry::Part(part) => {
if has_default && part.is_included_in_default() {
let msg = format!(
"`{}` is already included in `default`. Either remove `default` or remove `{}`",
part.name,
part.name
);
return Err(Error::new(part.name.span(), msg));
}
if !resolved.insert(part.name.clone()) {
let msg = format!(
"`{}` was already declared before. Please remove the duplicate declaration",
part.name
);
return Err(Error::new(part.name.span(), msg));
}
}
_ => {}
}
}
}
Ok(parsed)
}
}
impl ModuleDeclaration {
/// Get resolved module parts, i.e. after expanding `default` keyword
/// or empty declaration
pub fn module_parts(&self) -> Vec<ModulePart> {
if let Some(ref details) = self.details {
details
.content
.inner
.iter()
.flat_map(|entry| match entry {
ModuleEntry::Default(ref token) => Self::default_modules(token.span()),
ModuleEntry::Part(ref part) => vec![part.clone()],
})
.collect()
} else {
Self::default_modules(self.module.span())
}
/// Get resolved module parts
pub fn module_parts(&self) -> &[ModulePart] {
&self.module_parts
}
pub fn find_part(&self, name: &str) -> Option<ModulePart> {
self.module_parts()
.into_iter()
.find(|part| part.name == name)
pub fn find_part(&self, name: &str) -> Option<&ModulePart> {
self.module_parts.iter().find(|part| part.name() == name)
}
pub fn exists_part(&self, name: &str) -> bool {
self.find_part(name).is_some()
}
}
fn default_modules(span: Span) -> Vec<ModulePart> {
let mut res: Vec<_> = ["Module", "Call", "Storage"]
.iter()
.map(|name| ModulePart::with_name(name, span))
.collect();
res.extend(
["Event", "Config"]
.iter()
.map(|name| ModulePart::with_generics(name, span)),
);
res
/// Parse [`ModulePart`]'s from a braces enclosed list that is split by commas, e.g.
///
/// `{ Call, Event }`
fn parse_module_parts(input: ParseStream) -> Result<Vec<ModulePart>> {
let module_parts :ext::Braces<ext::Punctuated<ModulePart, Token![,]>> = input.parse()?;
let mut resolved = HashSet::new();
for part in module_parts.content.inner.iter() {
if !resolved.insert(part.name()) {
let msg = format!(
"`{}` was already declared before. Please remove the duplicate declaration",
part.name(),
);
return Err(Error::new(part.keyword.span(), msg));
}
}
Ok(module_parts.content.inner.into_iter().collect())
}
#[derive(Debug)]
pub enum ModuleEntry {
Default(Token![default]),
Part(ModulePart),
#[derive(Debug, Clone)]
pub enum ModulePartKeyword {
Module(keyword::Module),
Call(keyword::Call),
Storage(keyword::Storage),
Event(keyword::Event),
Config(keyword::Config),
Origin(keyword::Origin),
Inherent(keyword::Inherent),
ValidateUnsigned(keyword::ValidateUnsigned),
}
impl Parse for ModuleEntry {
impl Parse for ModulePartKeyword {
fn parse(input: ParseStream) -> Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![default]) {
Ok(ModuleEntry::Default(input.parse()?))
} else if lookahead.peek(Ident) {
Ok(ModuleEntry::Part(input.parse()?))
if lookahead.peek(keyword::Module) {
Ok(Self::Module(input.parse()?))
} else if lookahead.peek(keyword::Call) {
Ok(Self::Call(input.parse()?))
} else if lookahead.peek(keyword::Storage) {
Ok(Self::Storage(input.parse()?))
} else if lookahead.peek(keyword::Event) {
Ok(Self::Event(input.parse()?))
} else if lookahead.peek(keyword::Config) {
Ok(Self::Config(input.parse()?))
} else if lookahead.peek(keyword::Origin) {
Ok(Self::Origin(input.parse()?))
} else if lookahead.peek(keyword::Inherent) {
Ok(Self::Inherent(input.parse()?))
} else if lookahead.peek(keyword::ValidateUnsigned) {
Ok(Self::ValidateUnsigned(input.parse()?))
} else {
Err(lookahead.error())
}
}
}
impl ModuleEntry {
pub fn is_default(&self) -> bool {
impl ModulePartKeyword {
/// Returns the name of `Self`.
fn name(&self) -> &'static str {
match self {
ModuleEntry::Default(_) => true,
_ => false,
Self::Module(_) => "Module",
Self::Call(_) => "Call",
Self::Storage(_) => "Storage",
Self::Event(_) => "Event",
Self::Config(_) => "Config",
Self::Origin(_) => "Origin",
Self::Inherent(_) => "Inherent",
Self::ValidateUnsigned(_) => "ValidateUnsigned",
}
}
/// Returns the name as `Ident`.
fn ident(&self) -> Ident {
Ident::new(self.name(), self.span())
}
/// Returns `true` if this module part allows to have an argument.
///
/// For example `Inherent(Timestamp)`.
fn allows_arg(&self) -> bool {
Self::all_allow_arg().iter().any(|n| *n == self.name())
}
/// Returns the names of all module parts that allow to have an argument.
fn all_allow_arg() -> &'static [&'static str] {
&["Inherent"]
}
/// Returns `true` if this module part is allowed to have generic arguments.
fn allows_generic(&self) -> bool {
Self::all_generic_arg().iter().any(|n| *n == self.name())
}
/// Returns the names of all module parts that allow to have a generic argument.
fn all_generic_arg() -> &'static [&'static str] {
&["Event", "Origin", "Config"]
}
}
impl Spanned for ModulePartKeyword {
fn span(&self) -> Span {
match self {
Self::Module(inner) => inner.span(),
Self::Call(inner) => inner.span(),
Self::Storage(inner) => inner.span(),
Self::Event(inner) => inner.span(),
Self::Config(inner) => inner.span(),
Self::Origin(inner) => inner.span(),
Self::Inherent(inner) => inner.span(),
Self::ValidateUnsigned(inner) => inner.span(),
}
}
}
#[derive(Debug, Clone)]
pub struct ModulePart {
pub name: Ident,
pub keyword: ModulePartKeyword,
pub generics: syn::Generics,
pub args: Option<ext::Parens<ext::Punctuated<Ident, Token![,]>>>,
}
impl Parse for ModulePart {
fn parse(input: ParseStream) -> Result<Self> {
let name: Ident = input.parse()?;
if !ModulePart::all_allowed().iter().any(|n| name == n) {
return Err(syn::Error::new(
name.span(),
format!(
"Only the following modules are allowed: {}",
ModulePart::format_names(ModulePart::all_allowed()),
),
))
}
let keyword: ModulePartKeyword = input.parse()?;
let generics: syn::Generics = input.parse()?;
if !generics.params.is_empty() && !Self::is_allowed_generic(&name) {
let valid_generics = ModulePart::format_names(ModulePart::allowed_generics());
if !generics.params.is_empty() && !keyword.allows_generic() {
let valid_generics = ModulePart::format_names(ModulePartKeyword::all_generic_arg());
let msg = format!(
"`{}` is not allowed to have generics. \
Only the following modules are allowed to have generics: {}.",
name, valid_generics
keyword.name(),
valid_generics,
);
return Err(syn::Error::new(name.span(), msg));
return Err(syn::Error::new(keyword.span(), msg));
}
let args = if input.peek(token::Paren) {
if !Self::is_allowed_arg(&name) {
if !keyword.allows_arg() {
let syn::group::Parens { token: parens, .. } = syn::group::parse_parens(input)?;
let valid_names = ModulePart::format_names(ModulePart::allowed_args());
let valid_names = ModulePart::format_names(ModulePartKeyword::all_allow_arg());
let msg = format!(
"`{}` is not allowed to have arguments in parens. \
Only the following modules are allowed to have arguments in parens: {}.",
name, valid_names
keyword.name(),
valid_names,
);
return Err(syn::Error::new(parens.span, msg));
}
@@ -325,7 +356,7 @@ impl Parse for ModulePart {
};
Ok(Self {
name,
keyword,
generics,
args,
})
@@ -333,70 +364,19 @@ impl Parse for ModulePart {
}
impl ModulePart {
pub fn is_allowed_generic(ident: &Ident) -> bool {
Self::allowed_generics().into_iter().any(|n| ident == n)
}
pub fn is_allowed_arg(ident: &Ident) -> bool {
Self::allowed_args().into_iter().any(|n| ident == n)
}
pub fn allowed_generics() -> &'static [&'static str] {
&["Event", "Origin", "Config"]
}
pub fn allowed_args() -> &'static [&'static str] {
&["Inherent"]
}
/// Returns all allowed names for module parts.
pub fn all_allowed() -> &'static [&'static str] {
&["Module", "Call", "Storage", "Event", "Config", "Origin", "Inherent", "ValidateUnsigned"]
}
pub fn format_names(names: &[&'static str]) -> String {
let res: Vec<_> = names.into_iter().map(|s| format!("`{}`", s)).collect();
res.join(", ")
}
pub fn is_included_in_default(&self) -> bool {
["Module", "Call", "Storage", "Event", "Config"]
.iter()
.any(|name| self.name == name)
/// The name of this module part.
pub fn name(&self) -> &'static str {
self.keyword.name()
}
/// Plain module name like `Event` or `Call`, etc.
pub fn with_name(name: &str, span: Span) -> Self {
let name = Ident::new(name, span);
Self {
name,
generics: syn::Generics {
lt_token: None,
gt_token: None,
where_clause: None,
..Default::default()
},
args: None,
}
}
/// Module name with generic like `Event<T>` or `Call<T>`, etc.
pub fn with_generics(name: &str, span: Span) -> Self {
let name = Ident::new(name, span);
let typ = Ident::new("T", span);
let generic_param = syn::GenericParam::Type(typ.into());
let generic_params = vec![generic_param].into_iter().collect();
let generics = syn::Generics {
lt_token: Some(syn::token::Lt { spans: [span] }),
params: generic_params,
gt_token: Some(syn::token::Gt { spans: [span] }),
where_clause: None,
};
Self {
name,
generics,
args: None,
}
/// The name of this module part as `Ident`.
pub fn ident(&self) -> Ident {
self.keyword.ident()
}
}