referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/pallet/expand/
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 crate::pallet::{expand::merge_where_clauses, Def};
19use frame_support_procedural_tools::get_doc_literals;
20
21///
22/// * Add derive trait on Pallet
23/// * Implement GetStorageVersion on Pallet
24/// * Implement OnGenesis on Pallet
25/// * Implement `fn error_metadata` on Pallet
26/// * declare Module type alias for construct_runtime
27/// * replace the first field type of `struct Pallet` with `PhantomData` if it is `_`
28/// * implementation of `PalletInfoAccess` information
29/// * implementation of `StorageInfoTrait` on Pallet
30pub fn expand_pallet_struct(def: &mut Def) -> proc_macro2::TokenStream {
31	let frame_support = &def.frame_support;
32	let frame_system = &def.frame_system;
33	let type_impl_gen = &def.type_impl_generics(def.pallet_struct.attr_span);
34	let type_use_gen = &def.type_use_generics(def.pallet_struct.attr_span);
35	let type_decl_gen = &def.type_decl_generics(def.pallet_struct.attr_span);
36	let pallet_ident = &def.pallet_struct.pallet;
37	let config_where_clause = &def.config.where_clause;
38	let deprecation_status =
39		match crate::deprecation::get_deprecation(&quote::quote! {#frame_support}, &def.item.attrs)
40		{
41			Ok(deprecation) => deprecation,
42			Err(e) => return e.into_compile_error(),
43		};
44
45	let mut storages_where_clauses = vec![&def.config.where_clause];
46	storages_where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause));
47	let storages_where_clauses = merge_where_clauses(&storages_where_clauses);
48
49	let pallet_item = {
50		let pallet_module_items = &mut def.item.content.as_mut().expect("Checked by def").1;
51		let item = &mut pallet_module_items[def.pallet_struct.index];
52		if let syn::Item::Struct(item) = item {
53			item
54		} else {
55			unreachable!("Checked by pallet struct parser")
56		}
57	};
58
59	// If the first field type is `_` then we replace with `PhantomData`
60	if let Some(field) = pallet_item.fields.iter_mut().next() {
61		if field.ty == syn::parse_quote!(_) {
62			field.ty = syn::parse_quote!(
63				core::marker::PhantomData<(#type_use_gen)>
64			);
65		}
66	}
67
68	if get_doc_literals(&pallet_item.attrs).is_empty() {
69		pallet_item.attrs.push(syn::parse_quote!(
70			#[doc = r"
71				The `Pallet` struct, the main type that implements traits and standalone
72				functions within the pallet.
73			"]
74		));
75	}
76
77	pallet_item.attrs.push(syn::parse_quote!(
78		#[derive(
79			#frame_support::CloneNoBound,
80			#frame_support::EqNoBound,
81			#frame_support::PartialEqNoBound,
82			#frame_support::RuntimeDebugNoBound,
83		)]
84	));
85
86	let pallet_error_metadata = if let Some(error_def) = &def.error {
87		let error_ident = &error_def.error;
88		quote::quote_spanned!(def.pallet_struct.attr_span =>
89			impl<#type_impl_gen> #pallet_ident<#type_use_gen> #config_where_clause {
90				#[doc(hidden)]
91				#[allow(deprecated)]
92				pub fn error_metadata() -> Option<#frame_support::__private::metadata_ir::PalletErrorMetadataIR> {
93					Some(<#error_ident<#type_use_gen>>::error_metadata())
94				}
95			}
96		)
97	} else {
98		quote::quote_spanned!(def.pallet_struct.attr_span =>
99			impl<#type_impl_gen> #pallet_ident<#type_use_gen> #config_where_clause {
100				#[doc(hidden)]
101				pub fn error_metadata() -> Option<#frame_support::__private::metadata_ir::PalletErrorMetadataIR> {
102					None
103				}
104			}
105		)
106	};
107
108	let storage_info_span =
109		def.pallet_struct.without_storage_info.unwrap_or(def.pallet_struct.attr_span);
110
111	let storage_names = &def.storages.iter().map(|storage| &storage.ident).collect::<Vec<_>>();
112	let storage_cfg_attrs =
113		&def.storages.iter().map(|storage| &storage.cfg_attrs).collect::<Vec<_>>();
114	let storage_maybe_allow_attrs = &def
115		.storages
116		.iter()
117		.map(|storage| crate::deprecation::extract_or_return_allow_attrs(&storage.attrs).collect())
118		.collect::<Vec<Vec<_>>>();
119	// Depending on the flag `without_storage_info` and the storage attribute `unbounded`, we use
120	// partial or full storage info from storage.
121	let storage_info_traits = &def
122		.storages
123		.iter()
124		.map(|storage| {
125			if storage.unbounded || def.pallet_struct.without_storage_info.is_some() {
126				quote::quote_spanned!(storage_info_span => PartialStorageInfoTrait)
127			} else {
128				quote::quote_spanned!(storage_info_span => StorageInfoTrait)
129			}
130		})
131		.collect::<Vec<_>>();
132
133	let storage_info_methods = &def
134		.storages
135		.iter()
136		.map(|storage| {
137			if storage.unbounded || def.pallet_struct.without_storage_info.is_some() {
138				quote::quote_spanned!(storage_info_span => partial_storage_info)
139			} else {
140				quote::quote_spanned!(storage_info_span => storage_info)
141			}
142		})
143		.collect::<Vec<_>>();
144
145	let storage_info = quote::quote_spanned!(storage_info_span =>
146		impl<#type_impl_gen> #frame_support::traits::StorageInfoTrait
147			for #pallet_ident<#type_use_gen>
148			#storages_where_clauses
149		{
150			fn storage_info()
151				-> #frame_support::__private::Vec<#frame_support::traits::StorageInfo>
152			{
153				#[allow(unused_mut)]
154				let mut res = #frame_support::__private::vec![];
155
156				#(
157					#(#storage_cfg_attrs)*
158					#(#storage_maybe_allow_attrs)*
159					{
160						let mut storage_info = <
161							#storage_names<#type_use_gen>
162							as #frame_support::traits::#storage_info_traits
163						>::#storage_info_methods();
164						res.append(&mut storage_info);
165					}
166				)*
167
168				res
169			}
170		}
171	);
172
173	let (storage_version, in_code_storage_version_ty) =
174		if let Some(v) = def.pallet_struct.storage_version.as_ref() {
175			(quote::quote! { #v }, quote::quote! { #frame_support::traits::StorageVersion })
176		} else {
177			(
178				quote::quote! { core::default::Default::default() },
179				quote::quote! { #frame_support::traits::NoStorageVersionSet },
180			)
181		};
182
183	let whitelisted_storage_idents: Vec<syn::Ident> = def
184		.storages
185		.iter()
186		.filter_map(|s| s.whitelisted.then(|| s.ident.clone()))
187		.collect();
188
189	let whitelisted_storage_keys_impl = quote::quote![
190		use #frame_support::traits::{StorageInfoTrait, TrackedStorageKey, WhitelistedStorageKeys};
191		impl<#type_impl_gen> WhitelistedStorageKeys for #pallet_ident<#type_use_gen> #storages_where_clauses {
192			fn whitelisted_storage_keys() -> #frame_support::__private::Vec<TrackedStorageKey> {
193				use #frame_support::__private::vec;
194				vec![#(
195					TrackedStorageKey::new(#whitelisted_storage_idents::<#type_use_gen>::hashed_key().to_vec())
196				),*]
197			}
198		}
199	];
200
201	quote::quote_spanned!(def.pallet_struct.attr_span =>
202		#pallet_error_metadata
203
204		/// Type alias to `Pallet`, to be used by `construct_runtime`.
205		///
206		/// Generated by `pallet` attribute macro.
207		#[deprecated(note = "use `Pallet` instead")]
208		#[allow(dead_code)]
209		pub type Module<#type_decl_gen> = #pallet_ident<#type_use_gen>;
210
211		// Implement `GetStorageVersion` for `Pallet`
212		impl<#type_impl_gen> #frame_support::traits::GetStorageVersion
213			for #pallet_ident<#type_use_gen>
214			#config_where_clause
215		{
216			type InCodeStorageVersion = #in_code_storage_version_ty;
217
218			fn in_code_storage_version() -> Self::InCodeStorageVersion {
219				#storage_version
220			}
221
222			fn on_chain_storage_version() -> #frame_support::traits::StorageVersion {
223				#frame_support::traits::StorageVersion::get::<Self>()
224			}
225		}
226
227		// Implement `OnGenesis` for `Pallet`
228		impl<#type_impl_gen> #frame_support::traits::OnGenesis
229			for #pallet_ident<#type_use_gen>
230			#config_where_clause
231		{
232			fn on_genesis() {
233				let storage_version: #frame_support::traits::StorageVersion = #storage_version;
234				storage_version.put::<Self>();
235			}
236		}
237
238		// Implement `PalletInfoAccess` for `Pallet`
239		impl<#type_impl_gen> #frame_support::traits::PalletInfoAccess
240			for #pallet_ident<#type_use_gen>
241			#config_where_clause
242		{
243			fn index() -> usize {
244				<
245					<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
246				>::index::<Self>()
247					.expect("Pallet is part of the runtime because pallet `Config` trait is \
248						implemented by the runtime")
249			}
250
251			fn name() -> &'static str {
252				<
253					<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
254				>::name::<Self>()
255					.expect("Pallet is part of the runtime because pallet `Config` trait is \
256						implemented by the runtime")
257			}
258
259			fn name_hash() -> [u8; 16] {
260				<
261					<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
262				>::name_hash::<Self>()
263					.expect("Pallet is part of the runtime because pallet `Config` trait is \
264						implemented by the runtime")
265			}
266
267			fn module_name() -> &'static str {
268				<
269					<T as #frame_system::Config>::PalletInfo as #frame_support::traits::PalletInfo
270				>::module_name::<Self>()
271					.expect("Pallet is part of the runtime because pallet `Config` trait is \
272						implemented by the runtime")
273			}
274
275			fn crate_version() -> #frame_support::traits::CrateVersion {
276				#frame_support::crate_to_crate_version!()
277			}
278		}
279
280		impl<#type_impl_gen> #frame_support::traits::PalletsInfoAccess
281			for #pallet_ident<#type_use_gen>
282			#config_where_clause
283		{
284			fn count() -> usize { 1 }
285			fn infos() -> #frame_support::__private::Vec<#frame_support::traits::PalletInfoData> {
286				use #frame_support::traits::PalletInfoAccess;
287				let item = #frame_support::traits::PalletInfoData {
288					index: Self::index(),
289					name: Self::name(),
290					module_name: Self::module_name(),
291					crate_version: Self::crate_version(),
292				};
293				#frame_support::__private::vec![item]
294			}
295		}
296
297		#storage_info
298		#whitelisted_storage_keys_impl
299
300		impl<#type_use_gen> #pallet_ident<#type_use_gen> {
301			#[allow(dead_code)]
302			#[doc(hidden)]
303			pub fn deprecation_info() -> #frame_support::__private::metadata_ir::ItemDeprecationInfoIR {
304				#deprecation_status
305			}
306		}
307	)
308}