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