referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/pallet/parse/
helper.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 proc_macro2::TokenStream;
19use quote::{quote, ToTokens};
20use syn::spanned::Spanned;
21
22/// List of additional token to be used for parsing.
23mod keyword {
24	syn::custom_keyword!(I);
25	syn::custom_keyword!(compact);
26	syn::custom_keyword!(GenesisBuild);
27	syn::custom_keyword!(BuildGenesisConfig);
28	syn::custom_keyword!(Config);
29	syn::custom_keyword!(T);
30	syn::custom_keyword!(Pallet);
31	syn::custom_keyword!(origin);
32	syn::custom_keyword!(DispatchResult);
33	syn::custom_keyword!(DispatchResultWithPostInfo);
34}
35
36/// A usage of instance, either the trait `Config` has been used with instance or without instance.
37/// Used to check for consistency.
38#[derive(Clone)]
39pub struct InstanceUsage {
40	pub has_instance: bool,
41	pub span: proc_macro2::Span,
42}
43
44/// Trait implemented for syn items to get mutable references on their attributes.
45///
46/// NOTE: verbatim variants are not supported.
47pub trait MutItemAttrs {
48	fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>>;
49}
50
51/// Take the first pallet attribute (e.g. attribute like `#[pallet..]`) and decode it to `Attr`
52pub(crate) fn take_first_item_pallet_attr<Attr>(
53	item: &mut impl MutItemAttrs,
54) -> syn::Result<Option<Attr>>
55where
56	Attr: syn::parse::Parse,
57{
58	let Some(attrs) = item.mut_item_attrs() else { return Ok(None) };
59
60	let Some(index) = attrs.iter().position(|attr| {
61		attr.path().segments.first().map_or(false, |segment| segment.ident == "pallet")
62	}) else {
63		return Ok(None)
64	};
65
66	let pallet_attr = attrs.remove(index);
67	Ok(Some(syn::parse2(pallet_attr.into_token_stream())?))
68}
69
70/// Take all the pallet attributes (e.g. attribute like `#[pallet..]`) and decode them to `Attr`
71pub(crate) fn take_item_pallet_attrs<Attr>(item: &mut impl MutItemAttrs) -> syn::Result<Vec<Attr>>
72where
73	Attr: syn::parse::Parse,
74{
75	let mut pallet_attrs = Vec::new();
76
77	while let Some(attr) = take_first_item_pallet_attr(item)? {
78		pallet_attrs.push(attr)
79	}
80
81	Ok(pallet_attrs)
82}
83
84/// Get all the cfg attributes (e.g. attribute like `#[cfg..]`) and decode them to `Attr`
85pub fn get_item_cfg_attrs(attrs: &[syn::Attribute]) -> Vec<syn::Attribute> {
86	attrs
87		.iter()
88		.filter_map(|attr| {
89			if attr.path().segments.first().map_or(false, |segment| segment.ident == "cfg") {
90				Some(attr.clone())
91			} else {
92				None
93			}
94		})
95		.collect::<Vec<_>>()
96}
97
98impl MutItemAttrs for syn::Item {
99	fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>> {
100		match self {
101			Self::Const(item) => Some(item.attrs.as_mut()),
102			Self::Enum(item) => Some(item.attrs.as_mut()),
103			Self::ExternCrate(item) => Some(item.attrs.as_mut()),
104			Self::Fn(item) => Some(item.attrs.as_mut()),
105			Self::ForeignMod(item) => Some(item.attrs.as_mut()),
106			Self::Impl(item) => Some(item.attrs.as_mut()),
107			Self::Macro(item) => Some(item.attrs.as_mut()),
108			Self::Mod(item) => Some(item.attrs.as_mut()),
109			Self::Static(item) => Some(item.attrs.as_mut()),
110			Self::Struct(item) => Some(item.attrs.as_mut()),
111			Self::Trait(item) => Some(item.attrs.as_mut()),
112			Self::TraitAlias(item) => Some(item.attrs.as_mut()),
113			Self::Type(item) => Some(item.attrs.as_mut()),
114			Self::Union(item) => Some(item.attrs.as_mut()),
115			Self::Use(item) => Some(item.attrs.as_mut()),
116			_ => None,
117		}
118	}
119}
120
121impl MutItemAttrs for syn::TraitItem {
122	fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>> {
123		match self {
124			Self::Const(item) => Some(item.attrs.as_mut()),
125			Self::Fn(item) => Some(item.attrs.as_mut()),
126			Self::Type(item) => Some(item.attrs.as_mut()),
127			Self::Macro(item) => Some(item.attrs.as_mut()),
128			_ => None,
129		}
130	}
131}
132
133impl MutItemAttrs for Vec<syn::Attribute> {
134	fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>> {
135		Some(self)
136	}
137}
138
139impl MutItemAttrs for syn::ItemMod {
140	fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>> {
141		Some(&mut self.attrs)
142	}
143}
144
145impl MutItemAttrs for syn::ImplItemFn {
146	fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>> {
147		Some(&mut self.attrs)
148	}
149}
150
151impl MutItemAttrs for syn::ItemType {
152	fn mut_item_attrs(&mut self) -> Option<&mut Vec<syn::Attribute>> {
153		Some(&mut self.attrs)
154	}
155}
156
157/// Parse for `()`
158struct Unit;
159impl syn::parse::Parse for Unit {
160	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
161		let content;
162		syn::parenthesized!(content in input);
163		if !content.is_empty() {
164			let msg = "unexpected tokens, expected nothing inside parenthesis as `()`";
165			return Err(syn::Error::new(content.span(), msg))
166		}
167		Ok(Self)
168	}
169}
170
171/// Parse for `'static`
172struct StaticLifetime;
173impl syn::parse::Parse for StaticLifetime {
174	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
175		let lifetime = input.parse::<syn::Lifetime>()?;
176		if lifetime.ident != "static" {
177			let msg = "unexpected tokens, expected `static`";
178			return Err(syn::Error::new(lifetime.ident.span(), msg))
179		}
180		Ok(Self)
181	}
182}
183
184/// Check the syntax: `I: 'static = ()`
185///
186/// `span` is used in case generics is empty (empty generics has span == call_site).
187///
188/// return the instance if found.
189pub fn check_config_def_gen(gen: &syn::Generics, span: proc_macro2::Span) -> syn::Result<()> {
190	let expected = "expected `I: 'static = ()`";
191	pub struct CheckTraitDefGenerics;
192	impl syn::parse::Parse for CheckTraitDefGenerics {
193		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
194			input.parse::<keyword::I>()?;
195			input.parse::<syn::Token![:]>()?;
196			input.parse::<StaticLifetime>()?;
197			input.parse::<syn::Token![=]>()?;
198			input.parse::<Unit>()?;
199
200			Ok(Self)
201		}
202	}
203
204	syn::parse2::<CheckTraitDefGenerics>(gen.params.to_token_stream()).map_err(|e| {
205		let msg = format!("Invalid generics: {}", expected);
206		let mut err = syn::Error::new(span, msg);
207		err.combine(e);
208		err
209	})?;
210
211	Ok(())
212}
213
214/// Check the syntax:
215/// * either `T`
216/// * or `T, I = ()`
217///
218/// `span` is used in case generics is empty (empty generics has span == call_site).
219///
220/// return the instance if found.
221pub fn check_type_def_gen_no_bounds(
222	gen: &syn::Generics,
223	span: proc_macro2::Span,
224) -> syn::Result<InstanceUsage> {
225	let expected = "expected `T` or `T, I = ()`";
226	pub struct Checker(InstanceUsage);
227	impl syn::parse::Parse for Checker {
228		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
229			let mut instance_usage = InstanceUsage { has_instance: false, span: input.span() };
230
231			input.parse::<keyword::T>()?;
232			if input.peek(syn::Token![,]) {
233				instance_usage.has_instance = true;
234				input.parse::<syn::Token![,]>()?;
235				input.parse::<keyword::I>()?;
236				input.parse::<syn::Token![=]>()?;
237				input.parse::<Unit>()?;
238			}
239
240			Ok(Self(instance_usage))
241		}
242	}
243
244	let i = syn::parse2::<Checker>(gen.params.to_token_stream())
245		.map_err(|e| {
246			let msg = format!("Invalid type def generics: {}", expected);
247			let mut err = syn::Error::new(span, msg);
248			err.combine(e);
249			err
250		})?
251		.0;
252
253	Ok(i)
254}
255
256/// Check the syntax:
257/// * either `` (no generics
258/// * or `T`
259/// * or `T: Config`
260/// * or `T, I = ()`
261/// * or `T: Config<I>, I: 'static = ()`
262///
263/// `span` is used in case generics is empty (empty generics has span == call_site).
264///
265/// return some instance usage if there is some generic, or none otherwise.
266pub fn check_type_def_optional_gen(
267	gen: &syn::Generics,
268	span: proc_macro2::Span,
269) -> syn::Result<Option<InstanceUsage>> {
270	let expected = "expected `` or `T` or `T: Config` or `T, I = ()` or \
271		`T: Config<I>, I: 'static = ()`";
272	pub struct Checker(Option<InstanceUsage>);
273	impl syn::parse::Parse for Checker {
274		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
275			if input.is_empty() {
276				return Ok(Self(None))
277			}
278
279			let mut instance_usage = InstanceUsage { span: input.span(), has_instance: false };
280
281			input.parse::<keyword::T>()?;
282
283			if input.is_empty() {
284				return Ok(Self(Some(instance_usage)))
285			}
286
287			let lookahead = input.lookahead1();
288			if lookahead.peek(syn::Token![,]) {
289				instance_usage.has_instance = true;
290				input.parse::<syn::Token![,]>()?;
291				input.parse::<keyword::I>()?;
292				input.parse::<syn::Token![=]>()?;
293				input.parse::<Unit>()?;
294
295				Ok(Self(Some(instance_usage)))
296			} else if lookahead.peek(syn::Token![:]) {
297				input.parse::<syn::Token![:]>()?;
298				input.parse::<keyword::Config>()?;
299
300				if input.is_empty() {
301					return Ok(Self(Some(instance_usage)))
302				}
303
304				instance_usage.has_instance = true;
305				input.parse::<syn::Token![<]>()?;
306				input.parse::<keyword::I>()?;
307				input.parse::<syn::Token![>]>()?;
308				input.parse::<syn::Token![,]>()?;
309				input.parse::<keyword::I>()?;
310				input.parse::<syn::Token![:]>()?;
311				input.parse::<StaticLifetime>()?;
312				input.parse::<syn::Token![=]>()?;
313				input.parse::<Unit>()?;
314
315				Ok(Self(Some(instance_usage)))
316			} else {
317				Err(lookahead.error())
318			}
319		}
320	}
321
322	let i = syn::parse2::<Checker>(gen.params.to_token_stream())
323		.map_err(|e| {
324			let msg = format!("Invalid type def generics: {}", expected);
325			let mut err = syn::Error::new(span, msg);
326			err.combine(e);
327			err
328		})?
329		.0
330		// Span can be call_site if generic is empty. Thus we replace it.
331		.map(|mut i| {
332			i.span = span;
333			i
334		});
335
336	Ok(i)
337}
338
339/// Check the syntax:
340/// * either `Pallet<T>`
341/// * or `Pallet<T, I>`
342///
343/// return the instance if found.
344pub fn check_pallet_struct_usage(type_: &Box<syn::Type>) -> syn::Result<InstanceUsage> {
345	let expected = "expected `Pallet<T>` or `Pallet<T, I>`";
346	pub struct Checker(InstanceUsage);
347	impl syn::parse::Parse for Checker {
348		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
349			let mut instance_usage = InstanceUsage { span: input.span(), has_instance: false };
350
351			input.parse::<keyword::Pallet>()?;
352			input.parse::<syn::Token![<]>()?;
353			input.parse::<keyword::T>()?;
354			if input.peek(syn::Token![,]) {
355				instance_usage.has_instance = true;
356				input.parse::<syn::Token![,]>()?;
357				input.parse::<keyword::I>()?;
358			}
359			input.parse::<syn::Token![>]>()?;
360
361			Ok(Self(instance_usage))
362		}
363	}
364
365	let i = syn::parse2::<Checker>(type_.to_token_stream())
366		.map_err(|e| {
367			let msg = format!("Invalid pallet struct: {}", expected);
368			let mut err = syn::Error::new(type_.span(), msg);
369			err.combine(e);
370			err
371		})?
372		.0;
373
374	Ok(i)
375}
376
377/// Check the generic is:
378/// * either `T: Config`
379/// * or `T: Config<I>, I: 'static`
380///
381/// `span` is used in case generics is empty (empty generics has span == call_site).
382///
383/// return whether it contains instance.
384pub fn check_impl_gen(gen: &syn::Generics, span: proc_macro2::Span) -> syn::Result<InstanceUsage> {
385	let expected = "expected `impl<T: Config>` or `impl<T: Config<I>, I: 'static>`";
386	pub struct Checker(InstanceUsage);
387	impl syn::parse::Parse for Checker {
388		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
389			let mut instance_usage = InstanceUsage { span: input.span(), has_instance: false };
390
391			input.parse::<keyword::T>()?;
392			input.parse::<syn::Token![:]>()?;
393			input.parse::<keyword::Config>()?;
394			if input.peek(syn::Token![<]) {
395				instance_usage.has_instance = true;
396				input.parse::<syn::Token![<]>()?;
397				input.parse::<keyword::I>()?;
398				input.parse::<syn::Token![>]>()?;
399				input.parse::<syn::Token![,]>()?;
400				input.parse::<keyword::I>()?;
401				input.parse::<syn::Token![:]>()?;
402				input.parse::<StaticLifetime>()?;
403			}
404
405			Ok(Self(instance_usage))
406		}
407	}
408
409	let i = syn::parse2::<Checker>(gen.params.to_token_stream())
410		.map_err(|e| {
411			let mut err = syn::Error::new(span, format!("Invalid generics: {}", expected));
412			err.combine(e);
413			err
414		})?
415		.0;
416
417	Ok(i)
418}
419
420/// Check the syntax:
421/// * or `T`
422/// * or `T: Config`
423/// * or `T, I = ()`
424/// * or `T: Config<I>, I: 'static = ()`
425///
426/// `span` is used in case generics is empty (empty generics has span == call_site).
427///
428/// return the instance if found.
429pub fn check_type_def_gen(
430	gen: &syn::Generics,
431	span: proc_macro2::Span,
432) -> syn::Result<InstanceUsage> {
433	let expected = "expected `T` or `T: Config` or `T, I = ()` or \
434		`T: Config<I>, I: 'static = ()`";
435	pub struct Checker(InstanceUsage);
436	impl syn::parse::Parse for Checker {
437		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
438			let mut instance_usage = InstanceUsage { span: input.span(), has_instance: false };
439
440			input.parse::<keyword::T>()?;
441
442			if input.is_empty() {
443				return Ok(Self(instance_usage))
444			}
445
446			let lookahead = input.lookahead1();
447			if lookahead.peek(syn::Token![,]) {
448				instance_usage.has_instance = true;
449				input.parse::<syn::Token![,]>()?;
450				input.parse::<keyword::I>()?;
451				input.parse::<syn::Token![=]>()?;
452				input.parse::<Unit>()?;
453
454				Ok(Self(instance_usage))
455			} else if lookahead.peek(syn::Token![:]) {
456				input.parse::<syn::Token![:]>()?;
457				input.parse::<keyword::Config>()?;
458
459				if input.is_empty() {
460					return Ok(Self(instance_usage))
461				}
462
463				instance_usage.has_instance = true;
464				input.parse::<syn::Token![<]>()?;
465				input.parse::<keyword::I>()?;
466				input.parse::<syn::Token![>]>()?;
467				input.parse::<syn::Token![,]>()?;
468				input.parse::<keyword::I>()?;
469				input.parse::<syn::Token![:]>()?;
470				input.parse::<StaticLifetime>()?;
471				input.parse::<syn::Token![=]>()?;
472				input.parse::<Unit>()?;
473
474				Ok(Self(instance_usage))
475			} else {
476				Err(lookahead.error())
477			}
478		}
479	}
480
481	let mut i = syn::parse2::<Checker>(gen.params.to_token_stream())
482		.map_err(|e| {
483			let msg = format!("Invalid type def generics: {}", expected);
484			let mut err = syn::Error::new(span, msg);
485			err.combine(e);
486			err
487		})?
488		.0;
489
490	// Span can be call_site if generic is empty. Thus we replace it.
491	i.span = span;
492
493	Ok(i)
494}
495
496/// Check the syntax:
497/// * either `GenesisBuild<T>`
498/// * or `GenesisBuild<T, I>`
499/// * or `BuildGenesisConfig`
500///
501/// return the instance if found for `GenesisBuild`
502/// return None for BuildGenesisConfig
503pub fn check_genesis_builder_usage(type_: &syn::Path) -> syn::Result<Option<InstanceUsage>> {
504	let expected = "expected `BuildGenesisConfig` (or the deprecated `GenesisBuild<T>` or `GenesisBuild<T, I>`)";
505	pub struct Checker(Option<InstanceUsage>);
506	impl syn::parse::Parse for Checker {
507		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
508			let mut instance_usage = InstanceUsage { span: input.span(), has_instance: false };
509
510			if input.peek(keyword::GenesisBuild) {
511				input.parse::<keyword::GenesisBuild>()?;
512				input.parse::<syn::Token![<]>()?;
513				input.parse::<keyword::T>()?;
514				if input.peek(syn::Token![,]) {
515					instance_usage.has_instance = true;
516					input.parse::<syn::Token![,]>()?;
517					input.parse::<keyword::I>()?;
518				}
519				input.parse::<syn::Token![>]>()?;
520				return Ok(Self(Some(instance_usage)))
521			} else {
522				input.parse::<keyword::BuildGenesisConfig>()?;
523				return Ok(Self(None))
524			}
525		}
526	}
527
528	let i = syn::parse2::<Checker>(type_.to_token_stream())
529		.map_err(|e| {
530			let msg = format!("Invalid genesis builder: {}", expected);
531			let mut err = syn::Error::new(type_.span(), msg);
532			err.combine(e);
533			err
534		})?
535		.0;
536
537	Ok(i)
538}
539
540/// Check the syntax:
541/// * either `` (no generics)
542/// * or `T: Config`
543/// * or `T: Config<I>, I: 'static`
544///
545/// `span` is used in case generics is empty (empty generics has span == call_site).
546///
547/// return the instance if found.
548pub fn check_type_value_gen(
549	gen: &syn::Generics,
550	span: proc_macro2::Span,
551) -> syn::Result<Option<InstanceUsage>> {
552	let expected = "expected `` or `T: Config` or `T: Config<I>, I: 'static`";
553	pub struct Checker(Option<InstanceUsage>);
554	impl syn::parse::Parse for Checker {
555		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
556			if input.is_empty() {
557				return Ok(Self(None))
558			}
559
560			input.parse::<keyword::T>()?;
561			input.parse::<syn::Token![:]>()?;
562			input.parse::<keyword::Config>()?;
563
564			let mut instance_usage = InstanceUsage { span: input.span(), has_instance: false };
565
566			if input.is_empty() {
567				return Ok(Self(Some(instance_usage)))
568			}
569
570			instance_usage.has_instance = true;
571			input.parse::<syn::Token![<]>()?;
572			input.parse::<keyword::I>()?;
573			input.parse::<syn::Token![>]>()?;
574			input.parse::<syn::Token![,]>()?;
575			input.parse::<keyword::I>()?;
576			input.parse::<syn::Token![:]>()?;
577			input.parse::<StaticLifetime>()?;
578
579			Ok(Self(Some(instance_usage)))
580		}
581	}
582
583	let i = syn::parse2::<Checker>(gen.params.to_token_stream())
584		.map_err(|e| {
585			let msg = format!("Invalid type def generics: {}", expected);
586			let mut err = syn::Error::new(span, msg);
587			err.combine(e);
588			err
589		})?
590		.0
591		// Span can be call_site if generic is empty. Thus we replace it.
592		.map(|mut i| {
593			i.span = span;
594			i
595		});
596
597	Ok(i)
598}
599
600/// The possible return type of a dispatchable.
601#[derive(Clone)]
602pub enum CallReturnType {
603	DispatchResult,
604	DispatchResultWithPostInfo,
605}
606
607/// Check the keyword `DispatchResultWithPostInfo` or `DispatchResult`.
608pub fn check_pallet_call_return_type(sig: &syn::Signature) -> syn::Result<CallReturnType> {
609	let syn::ReturnType::Type(_, type_) = &sig.output else {
610		let msg = "Invalid pallet::call, require return type \
611			DispatchResultWithPostInfo";
612		return Err(syn::Error::new(sig.span(), msg))
613	};
614
615	pub struct Checker(CallReturnType);
616	impl syn::parse::Parse for Checker {
617		fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
618			let lookahead = input.lookahead1();
619			if lookahead.peek(keyword::DispatchResultWithPostInfo) {
620				input.parse::<keyword::DispatchResultWithPostInfo>()?;
621				Ok(Self(CallReturnType::DispatchResultWithPostInfo))
622			} else if lookahead.peek(keyword::DispatchResult) {
623				input.parse::<keyword::DispatchResult>()?;
624				Ok(Self(CallReturnType::DispatchResult))
625			} else {
626				Err(lookahead.error())
627			}
628		}
629	}
630
631	syn::parse2::<Checker>(type_.to_token_stream()).map(|c| c.0)
632}
633
634pub(crate) fn two128_str(s: &str) -> TokenStream {
635	bytes_to_array(sp_crypto_hashing::twox_128(s.as_bytes()).into_iter())
636}
637
638pub(crate) fn bytes_to_array(bytes: impl IntoIterator<Item = u8>) -> TokenStream {
639	let bytes = bytes.into_iter();
640
641	quote!(
642		[ #( #bytes ),* ]
643	)
644	.into()
645}