referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/pallet/parse/
extra_constants.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use super::helper;
19use frame_support_procedural_tools::get_doc_literals;
20use syn::spanned::Spanned;
21
22/// List of additional token to be used for parsing.
23mod keyword {
24	syn::custom_keyword!(DispatchResultWithPostInfo);
25	syn::custom_keyword!(Call);
26	syn::custom_keyword!(OriginFor);
27	syn::custom_keyword!(weight);
28	syn::custom_keyword!(compact);
29	syn::custom_keyword!(T);
30	syn::custom_keyword!(pallet);
31	syn::custom_keyword!(constant_name);
32}
33
34/// Definition of extra constants typically `impl<T: Config> Pallet<T> { ... }`
35pub struct ExtraConstantsDef {
36	/// The where_clause used.
37	pub where_clause: Option<syn::WhereClause>,
38	/// A set of usage of instance, must be check for consistency with trait.
39	pub instances: Vec<helper::InstanceUsage>,
40	/// The extra constant defined.
41	pub extra_constants: Vec<ExtraConstantDef>,
42}
43
44/// Input definition for an constant in pallet.
45pub struct ExtraConstantDef {
46	/// Name of the function
47	pub ident: syn::Ident,
48	/// The type returned by the function
49	pub type_: syn::Type,
50	/// The doc associated
51	pub doc: Vec<syn::Expr>,
52	/// Optional MetaData Name
53	pub metadata_name: Option<syn::Ident>,
54	/// Attributes
55	pub attrs: Vec<syn::Attribute>,
56}
57
58/// Attributes for functions in extra_constants impl block.
59/// Parse for `#[pallet::constant_name(ConstantName)]`
60pub struct ExtraConstAttr {
61	metadata_name: syn::Ident,
62}
63
64impl syn::parse::Parse for ExtraConstAttr {
65	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
66		input.parse::<syn::Token![#]>()?;
67		let content;
68		syn::bracketed!(content in input);
69		content.parse::<keyword::pallet>()?;
70		content.parse::<syn::Token![::]>()?;
71		content.parse::<keyword::constant_name>()?;
72
73		let metadata_name;
74		syn::parenthesized!(metadata_name in content);
75		Ok(ExtraConstAttr { metadata_name: metadata_name.parse::<syn::Ident>()? })
76	}
77}
78
79impl ExtraConstantsDef {
80	pub fn try_from(item: &mut syn::Item) -> syn::Result<Self> {
81		let item = if let syn::Item::Impl(item) = item {
82			item
83		} else {
84			return Err(syn::Error::new(
85				item.span(),
86				"Invalid pallet::extra_constants, expected item impl",
87			));
88		};
89
90		let instances = vec![
91			helper::check_impl_gen(&item.generics, item.impl_token.span())?,
92			helper::check_pallet_struct_usage(&item.self_ty)?,
93		];
94
95		if let Some((_, _, for_)) = item.trait_ {
96			let msg = "Invalid pallet::call, expected no trait ident as in \
97				`impl<..> Pallet<..> { .. }`";
98			return Err(syn::Error::new(for_.span(), msg));
99		}
100
101		let mut extra_constants = vec![];
102		for impl_item in &mut item.items {
103			let method = if let syn::ImplItem::Fn(method) = impl_item {
104				method
105			} else {
106				let msg = "Invalid pallet::call, only method accepted";
107				return Err(syn::Error::new(impl_item.span(), msg));
108			};
109
110			if !method.sig.inputs.is_empty() {
111				let msg = "Invalid pallet::extra_constants, method must have 0 args";
112				return Err(syn::Error::new(method.sig.span(), msg));
113			}
114
115			if !method.sig.generics.params.is_empty() {
116				let msg = "Invalid pallet::extra_constants, method must have 0 generics";
117				return Err(syn::Error::new(method.sig.generics.params[0].span(), msg));
118			}
119
120			if method.sig.generics.where_clause.is_some() {
121				let msg = "Invalid pallet::extra_constants, method must have no where clause";
122				return Err(syn::Error::new(method.sig.generics.where_clause.span(), msg));
123			}
124
125			let type_ = match &method.sig.output {
126				syn::ReturnType::Default => {
127					let msg = "Invalid pallet::extra_constants, method must have a return type";
128					return Err(syn::Error::new(method.span(), msg));
129				},
130				syn::ReturnType::Type(_, type_) => *type_.clone(),
131			};
132
133			// parse metadata_name
134			let mut extra_constant_attrs: Vec<ExtraConstAttr> =
135				helper::take_item_pallet_attrs(method)?;
136
137			if extra_constant_attrs.len() > 1 {
138				let msg =
139					"Invalid attribute in pallet::constant_name, only one attribute is expected";
140				return Err(syn::Error::new(extra_constant_attrs[1].metadata_name.span(), msg));
141			}
142
143			let metadata_name = extra_constant_attrs.pop().map(|attr| attr.metadata_name);
144
145			extra_constants.push(ExtraConstantDef {
146				ident: method.sig.ident.clone(),
147				type_,
148				doc: get_doc_literals(&method.attrs),
149				metadata_name,
150				attrs: method.attrs.clone(),
151			});
152		}
153
154		Ok(Self { instances, where_clause: item.generics.where_clause.clone(), extra_constants })
155	}
156}