referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/pallet/parse/
pallet_struct.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 quote::ToTokens;
20use syn::spanned::Spanned;
21
22/// List of additional token to be used for parsing.
23mod keyword {
24	syn::custom_keyword!(pallet);
25	syn::custom_keyword!(Pallet);
26	syn::custom_keyword!(without_storage_info);
27	syn::custom_keyword!(storage_version);
28}
29
30/// Definition of the pallet pallet.
31pub struct PalletStructDef {
32	/// The index of item in pallet pallet.
33	pub index: usize,
34	/// A set of usage of instance, must be check for consistency with config trait.
35	pub instances: Vec<helper::InstanceUsage>,
36	/// The keyword Pallet used (contains span).
37	pub pallet: keyword::Pallet,
38	/// The span of the pallet::pallet attribute.
39	pub attr_span: proc_macro2::Span,
40	/// Whether to specify the storages max encoded len when implementing `StorageInfoTrait`.
41	/// Contains the span of the attribute.
42	pub without_storage_info: Option<proc_macro2::Span>,
43	/// The in-code storage version of the pallet.
44	pub storage_version: Option<syn::Path>,
45}
46
47/// Parse for one variant of:
48/// * `#[pallet::without_storage_info]`
49/// * `#[pallet::storage_version(STORAGE_VERSION)]`
50pub enum PalletStructAttr {
51	WithoutStorageInfoTrait(proc_macro2::Span),
52	StorageVersion { storage_version: syn::Path, span: proc_macro2::Span },
53}
54
55impl PalletStructAttr {
56	fn span(&self) -> proc_macro2::Span {
57		match self {
58			Self::WithoutStorageInfoTrait(span) | Self::StorageVersion { span, .. } => *span,
59		}
60	}
61}
62
63impl syn::parse::Parse for PalletStructAttr {
64	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
65		input.parse::<syn::Token![#]>()?;
66		let content;
67		syn::bracketed!(content in input);
68		content.parse::<keyword::pallet>()?;
69		content.parse::<syn::Token![::]>()?;
70
71		let lookahead = content.lookahead1();
72		if lookahead.peek(keyword::without_storage_info) {
73			let span = content.parse::<keyword::without_storage_info>()?.span();
74			Ok(Self::WithoutStorageInfoTrait(span))
75		} else if lookahead.peek(keyword::storage_version) {
76			let span = content.parse::<keyword::storage_version>()?.span();
77
78			let version_content;
79			syn::parenthesized!(version_content in content);
80			let storage_version = version_content.parse::<syn::Path>()?;
81
82			Ok(Self::StorageVersion { storage_version, span })
83		} else {
84			Err(lookahead.error())
85		}
86	}
87}
88
89impl PalletStructDef {
90	pub fn try_from(
91		attr_span: proc_macro2::Span,
92		index: usize,
93		item: &mut syn::Item,
94	) -> syn::Result<Self> {
95		let item = if let syn::Item::Struct(item) = item {
96			item
97		} else {
98			let msg = "Invalid pallet::pallet, expected struct definition";
99			return Err(syn::Error::new(item.span(), msg))
100		};
101
102		let mut without_storage_info = None;
103		let mut storage_version_found = None;
104
105		let struct_attrs: Vec<PalletStructAttr> = helper::take_item_pallet_attrs(&mut item.attrs)?;
106		for attr in struct_attrs {
107			match attr {
108				PalletStructAttr::WithoutStorageInfoTrait(span)
109					if without_storage_info.is_none() =>
110				{
111					without_storage_info = Some(span);
112				},
113				PalletStructAttr::StorageVersion { storage_version, .. }
114					if storage_version_found.is_none() =>
115				{
116					storage_version_found = Some(storage_version);
117				},
118				attr => {
119					let msg = "Unexpected duplicated attribute";
120					return Err(syn::Error::new(attr.span(), msg))
121				},
122			}
123		}
124
125		let pallet = syn::parse2::<keyword::Pallet>(item.ident.to_token_stream())?;
126
127		if !matches!(item.vis, syn::Visibility::Public(_)) {
128			let msg = "Invalid pallet::pallet, Pallet must be public";
129			return Err(syn::Error::new(item.span(), msg))
130		}
131
132		if item.generics.where_clause.is_some() {
133			let msg = "Invalid pallet::pallet, where clause not supported on Pallet declaration";
134			return Err(syn::Error::new(item.generics.where_clause.span(), msg))
135		}
136
137		let instances =
138			vec![helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?];
139
140		Ok(Self {
141			index,
142			instances,
143			pallet,
144			attr_span,
145			without_storage_info,
146			storage_version: storage_version_found,
147		})
148	}
149}