frame_support_procedural/pallet/expand/
storage.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::{
19	counter_prefix,
20	pallet::{
21		parse::{
22			helper::two128_str,
23			storage::{Metadata, QueryKind, StorageDef, StorageGenerics},
24		},
25		Def,
26	},
27};
28use quote::ToTokens;
29use std::{collections::HashMap, ops::IndexMut};
30use syn::spanned::Spanned;
31
32/// Generate the prefix_ident related to the storage.
33/// prefix_ident is used for the prefix struct to be given to storage as first generic param.
34fn prefix_ident(storage: &StorageDef) -> syn::Ident {
35	let storage_ident = &storage.ident;
36	syn::Ident::new(&format!("_GeneratedPrefixForStorage{}", storage_ident), storage_ident.span())
37}
38
39/// Generate the counter_prefix_ident related to the storage.
40/// counter_prefix_ident is used for the prefix struct to be given to counted storage map.
41fn counter_prefix_ident(storage_ident: &syn::Ident) -> syn::Ident {
42	syn::Ident::new(
43		&format!("_GeneratedCounterPrefixForStorage{}", storage_ident),
44		storage_ident.span(),
45	)
46}
47
48/// Check for duplicated storage prefixes. This step is necessary since users can specify an
49/// alternative storage prefix using the #[pallet::storage_prefix] syntax, and we need to ensure
50/// that the prefix specified by the user is not a duplicate of an existing one.
51fn check_prefix_duplicates(
52	storage_def: &StorageDef,
53	// A hashmap of all already used prefix and their associated error if duplication
54	used_prefixes: &mut HashMap<String, syn::Error>,
55) -> syn::Result<()> {
56	let prefix = storage_def.prefix();
57	let dup_err = syn::Error::new(
58		storage_def.prefix_span(),
59		format!("Duplicate storage prefixes found for `{}`", prefix),
60	);
61
62	if let Some(other_dup_err) = used_prefixes.insert(prefix.clone(), dup_err.clone()) {
63		let mut err = dup_err;
64		err.combine(other_dup_err);
65		return Err(err);
66	}
67
68	if let Metadata::CountedMap { .. } = storage_def.metadata {
69		let counter_prefix = counter_prefix(&prefix);
70		let counter_dup_err = syn::Error::new(
71			storage_def.prefix_span(),
72			format!(
73				"Duplicate storage prefixes found for `{}`, used for counter associated to \
74				counted storage map",
75				counter_prefix,
76			),
77		);
78
79		if let Some(other_dup_err) = used_prefixes.insert(counter_prefix, counter_dup_err.clone()) {
80			let mut err = counter_dup_err;
81			err.combine(other_dup_err);
82			return Err(err);
83		}
84	}
85
86	Ok(())
87}
88
89pub struct ResultOnEmptyStructMetadata {
90	/// The Rust ident that is going to be used as the name of the OnEmpty struct.
91	pub name: syn::Ident,
92	/// The path to the error type being returned by the ResultQuery.
93	pub error_path: syn::Path,
94	/// The visibility of the OnEmpty struct.
95	pub visibility: syn::Visibility,
96	/// The type of the storage item.
97	pub value_ty: syn::Type,
98	/// The name of the pallet error enum variant that is going to be returned.
99	pub variant_name: syn::Ident,
100	/// The span used to report compilation errors about the OnEmpty struct.
101	pub span: proc_macro2::Span,
102}
103
104///
105/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
106/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
107/// * Add `#[allow(type_alias_bounds)]`
108pub fn process_generics(def: &mut Def) -> syn::Result<Vec<ResultOnEmptyStructMetadata>> {
109	let frame_support = &def.frame_support;
110	let mut on_empty_struct_metadata = Vec::new();
111
112	for storage_def in def.storages.iter_mut() {
113		let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage_def.index];
114
115		let typ_item = match item {
116			syn::Item::Type(t) => t,
117			_ => unreachable!("Checked by def"),
118		};
119
120		typ_item.attrs.push(syn::parse_quote!(#[allow(type_alias_bounds)]));
121
122		let typ_path = match &mut *typ_item.ty {
123			syn::Type::Path(p) => p,
124			_ => unreachable!("Checked by def"),
125		};
126
127		let args = match &mut typ_path.path.segments[0].arguments {
128			syn::PathArguments::AngleBracketed(args) => args,
129			_ => unreachable!("Checked by def"),
130		};
131
132		let prefix_ident = prefix_ident(storage_def);
133		let type_use_gen = if def.config.has_instance {
134			quote::quote_spanned!(storage_def.attr_span => T, I)
135		} else {
136			quote::quote_spanned!(storage_def.attr_span => T)
137		};
138
139		let default_query_kind: syn::Type =
140			syn::parse_quote!(#frame_support::storage::types::OptionQuery);
141		let mut default_on_empty = |value_ty: syn::Type| -> syn::Type {
142			if let Some(QueryKind::ResultQuery(error_path, variant_name)) =
143				storage_def.query_kind.as_ref()
144			{
145				let on_empty_ident =
146					quote::format_ident!("__Frame_Internal_Get{}Result", storage_def.ident);
147				on_empty_struct_metadata.push(ResultOnEmptyStructMetadata {
148					name: on_empty_ident.clone(),
149					visibility: storage_def.vis.clone(),
150					value_ty,
151					error_path: error_path.clone(),
152					variant_name: variant_name.clone(),
153					span: storage_def.attr_span,
154				});
155				return syn::parse_quote!(#on_empty_ident);
156			}
157			syn::parse_quote!(#frame_support::traits::GetDefault)
158		};
159		let default_max_values: syn::Type = syn::parse_quote!(#frame_support::traits::GetDefault);
160
161		let set_result_query_type_parameter = |query_type: &mut syn::Type| -> syn::Result<()> {
162			if let Some(QueryKind::ResultQuery(error_path, _)) = storage_def.query_kind.as_ref() {
163				if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) =
164					query_type
165				{
166					if let Some(seg) = segments.last_mut() {
167						if let syn::PathArguments::AngleBracketed(
168							syn::AngleBracketedGenericArguments { args, .. },
169						) = &mut seg.arguments
170						{
171							args.clear();
172							args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)));
173						}
174					}
175				} else {
176					let msg = format!(
177						"Invalid pallet::storage, unexpected type for query, expected ResultQuery \
178						with 1 type parameter, found `{}`",
179						query_type.to_token_stream().to_string()
180					);
181					return Err(syn::Error::new(query_type.span(), msg));
182				}
183			}
184			Ok(())
185		};
186
187		if let Some(named_generics) = storage_def.named_generics.clone() {
188			args.args.clear();
189			args.args.push(syn::parse_quote!( #prefix_ident<#type_use_gen> ));
190			match named_generics {
191				StorageGenerics::Value { value, query_kind, on_empty } => {
192					args.args.push(syn::GenericArgument::Type(value.clone()));
193					let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
194					set_result_query_type_parameter(&mut query_kind)?;
195					args.args.push(syn::GenericArgument::Type(query_kind));
196					let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
197					args.args.push(syn::GenericArgument::Type(on_empty));
198				},
199				StorageGenerics::Map { hasher, key, value, query_kind, on_empty, max_values } |
200				StorageGenerics::CountedMap {
201					hasher,
202					key,
203					value,
204					query_kind,
205					on_empty,
206					max_values,
207				} => {
208					args.args.push(syn::GenericArgument::Type(hasher));
209					args.args.push(syn::GenericArgument::Type(key));
210					args.args.push(syn::GenericArgument::Type(value.clone()));
211					let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
212					set_result_query_type_parameter(&mut query_kind)?;
213					args.args.push(syn::GenericArgument::Type(query_kind));
214					let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
215					args.args.push(syn::GenericArgument::Type(on_empty));
216					let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
217					args.args.push(syn::GenericArgument::Type(max_values));
218				},
219				StorageGenerics::DoubleMap {
220					hasher1,
221					key1,
222					hasher2,
223					key2,
224					value,
225					query_kind,
226					on_empty,
227					max_values,
228				} => {
229					args.args.push(syn::GenericArgument::Type(hasher1));
230					args.args.push(syn::GenericArgument::Type(key1));
231					args.args.push(syn::GenericArgument::Type(hasher2));
232					args.args.push(syn::GenericArgument::Type(key2));
233					args.args.push(syn::GenericArgument::Type(value.clone()));
234					let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
235					set_result_query_type_parameter(&mut query_kind)?;
236					args.args.push(syn::GenericArgument::Type(query_kind));
237					let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
238					args.args.push(syn::GenericArgument::Type(on_empty));
239					let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
240					args.args.push(syn::GenericArgument::Type(max_values));
241				},
242				StorageGenerics::NMap { keygen, value, query_kind, on_empty, max_values } |
243				StorageGenerics::CountedNMap {
244					keygen,
245					value,
246					query_kind,
247					on_empty,
248					max_values,
249				} => {
250					args.args.push(syn::GenericArgument::Type(keygen));
251					args.args.push(syn::GenericArgument::Type(value.clone()));
252					let mut query_kind = query_kind.unwrap_or_else(|| default_query_kind.clone());
253					set_result_query_type_parameter(&mut query_kind)?;
254					args.args.push(syn::GenericArgument::Type(query_kind));
255					let on_empty = on_empty.unwrap_or_else(|| default_on_empty(value));
256					args.args.push(syn::GenericArgument::Type(on_empty));
257					let max_values = max_values.unwrap_or_else(|| default_max_values.clone());
258					args.args.push(syn::GenericArgument::Type(max_values));
259				},
260			}
261		} else {
262			args.args[0] = syn::parse_quote!( #prefix_ident<#type_use_gen> );
263
264			let (value_idx, query_idx, on_empty_idx) = match storage_def.metadata {
265				Metadata::Value { .. } => (1, 2, 3),
266				Metadata::NMap { .. } | Metadata::CountedNMap { .. } => (2, 3, 4),
267				Metadata::Map { .. } | Metadata::CountedMap { .. } => (3, 4, 5),
268				Metadata::DoubleMap { .. } => (5, 6, 7),
269			};
270
271			if storage_def.use_default_hasher {
272				let hasher_indices: Vec<usize> = match storage_def.metadata {
273					Metadata::Map { .. } | Metadata::CountedMap { .. } => vec![1],
274					Metadata::DoubleMap { .. } => vec![1, 3],
275					_ => vec![],
276				};
277				for hasher_idx in hasher_indices {
278					args.args[hasher_idx] = syn::GenericArgument::Type(
279						syn::parse_quote!(#frame_support::Blake2_128Concat),
280					);
281				}
282			}
283
284			if query_idx < args.args.len() {
285				if let syn::GenericArgument::Type(query_kind) = args.args.index_mut(query_idx) {
286					set_result_query_type_parameter(query_kind)?;
287				}
288			} else if let Some(QueryKind::ResultQuery(error_path, _)) =
289				storage_def.query_kind.as_ref()
290			{
291				args.args.push(syn::GenericArgument::Type(syn::parse_quote!(#error_path)))
292			}
293
294			// Here, we only need to check if OnEmpty is *not* specified, and if so, then we have to
295			// generate a default OnEmpty struct for it.
296			if on_empty_idx >= args.args.len() &&
297				matches!(storage_def.query_kind.as_ref(), Some(QueryKind::ResultQuery(_, _)))
298			{
299				let value_ty = match args.args[value_idx].clone() {
300					syn::GenericArgument::Type(ty) => ty,
301					_ => unreachable!(),
302				};
303				let on_empty = default_on_empty(value_ty);
304				args.args.push(syn::GenericArgument::Type(on_empty));
305			}
306		}
307	}
308
309	Ok(on_empty_struct_metadata)
310}
311
312fn augment_final_docs(def: &mut Def) {
313	// expand the docs with a new line showing the storage type (value, map, double map, etc), and
314	// the key/value type(s).
315	let mut push_string_literal = |doc_line: &str, storage: &mut StorageDef| {
316		let item = &mut def.item.content.as_mut().expect("Checked by def").1[storage.index];
317		let typ_item = match item {
318			syn::Item::Type(t) => t,
319			_ => unreachable!("Checked by def"),
320		};
321		typ_item.attrs.push(syn::parse_quote!(#[doc = ""]));
322		typ_item.attrs.push(syn::parse_quote!(#[doc = #doc_line]));
323	};
324	def.storages.iter_mut().for_each(|storage| match &storage.metadata {
325		Metadata::Value { value } => {
326			let doc_line = format!(
327				"Storage type is [`StorageValue`] with value type `{}`.",
328				value.to_token_stream()
329			);
330			push_string_literal(&doc_line, storage);
331		},
332		Metadata::Map { key, value } => {
333			let doc_line = format!(
334				"Storage type is [`StorageMap`] with key type `{}` and value type `{}`.",
335				key.to_token_stream(),
336				value.to_token_stream()
337			);
338			push_string_literal(&doc_line, storage);
339		},
340		Metadata::DoubleMap { key1, key2, value } => {
341			let doc_line = format!(
342				"Storage type is [`StorageDoubleMap`] with key1 type {}, key2 type {} and value type {}.",
343				key1.to_token_stream(),
344				key2.to_token_stream(),
345				value.to_token_stream()
346			);
347			push_string_literal(&doc_line, storage);
348		},
349		Metadata::NMap { keys, value, .. } => {
350			let doc_line = format!(
351				"Storage type is [`StorageNMap`] with keys type ({}) and value type {}.",
352				keys.iter()
353					.map(|k| k.to_token_stream().to_string())
354					.collect::<Vec<_>>()
355					.join(", "),
356				value.to_token_stream()
357			);
358			push_string_literal(&doc_line, storage);
359		},
360		Metadata::CountedNMap { keys, value, .. } => {
361			let doc_line = format!(
362				"Storage type is [`CountedStorageNMap`] with keys type ({}) and value type {}.",
363				keys.iter()
364					.map(|k| k.to_token_stream().to_string())
365					.collect::<Vec<_>>()
366					.join(", "),
367				value.to_token_stream()
368			);
369			push_string_literal(&doc_line, storage);
370		},
371		Metadata::CountedMap { key, value } => {
372			let doc_line = format!(
373				"Storage type is [`CountedStorageMap`] with key type {} and value type {}.",
374				key.to_token_stream(),
375				value.to_token_stream()
376			);
377			push_string_literal(&doc_line, storage);
378		},
379	});
380}
381
382///
383/// * generate StoragePrefix structs (e.g. for a storage `MyStorage` a struct with the name
384///   `_GeneratedPrefixForStorage$NameOfStorage` is generated) and implements StorageInstance trait.
385/// * if generics are unnamed: replace the first generic `_` by the generated prefix structure
386/// * if generics are named: reorder the generic, remove their name, and add the missing ones.
387/// * Add `#[allow(type_alias_bounds)]` on storages type alias
388/// * generate metadatas
389pub fn expand_storages(def: &mut Def) -> proc_macro2::TokenStream {
390	let on_empty_struct_metadata = match process_generics(def) {
391		Ok(idents) => idents,
392		Err(e) => return e.into_compile_error(),
393	};
394
395	augment_final_docs(def);
396
397	// Check for duplicate prefixes
398	let mut prefix_set = HashMap::new();
399	let mut errors = def
400		.storages
401		.iter()
402		.filter_map(|storage_def| check_prefix_duplicates(storage_def, &mut prefix_set).err());
403	if let Some(mut final_error) = errors.next() {
404		errors.for_each(|error| final_error.combine(error));
405		return final_error.into_compile_error();
406	}
407
408	let frame_support = &def.frame_support;
409	let frame_system = &def.frame_system;
410	let pallet_ident = &def.pallet_struct.pallet;
411	let mut entries_builder = vec![];
412	for storage in def.storages.iter() {
413		let no_docs = vec![];
414		let docs = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &storage.docs };
415
416		let ident = &storage.ident;
417		let gen = &def.type_use_generics(storage.attr_span);
418		let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
419
420		let cfg_attrs = &storage.cfg_attrs;
421		let deprecation = match crate::deprecation::get_deprecation(
422			&quote::quote! { #frame_support },
423			&storage.attrs,
424		) {
425			Ok(deprecation) => deprecation,
426			Err(e) => return e.into_compile_error(),
427		};
428		entries_builder.push(quote::quote_spanned!(storage.attr_span =>
429			#(#cfg_attrs)*
430			{
431				<#full_ident as #frame_support::storage::StorageEntryMetadataBuilder>::build_metadata(
432					#deprecation,
433					#frame_support::__private::vec![
434						#( #docs, )*
435					],
436					&mut entries,
437				);
438			}
439		))
440	}
441
442	let getters = def.storages.iter().map(|storage| {
443		if let Some(getter) = &storage.getter {
444			let completed_where_clause =
445				super::merge_where_clauses(&[&storage.where_clause, &def.config.where_clause]);
446
447			let ident = &storage.ident;
448			let gen = &def.type_use_generics(storage.attr_span);
449			let type_impl_gen = &def.type_impl_generics(storage.attr_span);
450			let type_use_gen = &def.type_use_generics(storage.attr_span);
451			let full_ident = quote::quote_spanned!(storage.attr_span => #ident<#gen> );
452
453			let cfg_attrs = &storage.cfg_attrs;
454
455			// If the storage item is public, link it and otherwise just mention it.
456			//
457			// We can not just copy the docs from a non-public type as it may links to internal
458			// types which makes the compiler very unhappy :(
459			let getter_doc_line = if matches!(storage.vis, syn::Visibility::Public(_)) {
460				format!("An auto-generated getter for [`{}`].", storage.ident)
461			} else {
462				format!("An auto-generated getter for `{}`.", storage.ident)
463			};
464
465			match &storage.metadata {
466				Metadata::Value { value } => {
467					let query = match storage.query_kind.as_ref().expect("Checked by def") {
468						QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
469							Option<#value>
470						),
471						QueryKind::ResultQuery(error_path, _) => {
472							quote::quote_spanned!(storage.attr_span =>
473								Result<#value, #error_path>
474							)
475						},
476						QueryKind::ValueQuery => quote::quote!(#value),
477					};
478					quote::quote_spanned!(storage.attr_span =>
479						#(#cfg_attrs)*
480						impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
481							#[doc = #getter_doc_line]
482							pub fn #getter() -> #query {
483								<
484									#full_ident as #frame_support::storage::StorageValue<#value>
485								>::get()
486							}
487						}
488					)
489				},
490				Metadata::Map { key, value } => {
491					let query = match storage.query_kind.as_ref().expect("Checked by def") {
492						QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
493							Option<#value>
494						),
495						QueryKind::ResultQuery(error_path, _) => {
496							quote::quote_spanned!(storage.attr_span =>
497								Result<#value, #error_path>
498							)
499						},
500						QueryKind::ValueQuery => quote::quote!(#value),
501					};
502					quote::quote_spanned!(storage.attr_span =>
503						#(#cfg_attrs)*
504						impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
505							#[doc = #getter_doc_line]
506							pub fn #getter<KArg>(k: KArg) -> #query where
507								KArg: #frame_support::__private::codec::EncodeLike<#key>,
508							{
509								<
510									#full_ident as #frame_support::storage::StorageMap<#key, #value>
511								>::get(k)
512							}
513						}
514					)
515				},
516				Metadata::CountedMap { key, value } => {
517					let query = match storage.query_kind.as_ref().expect("Checked by def") {
518						QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
519							Option<#value>
520						),
521						QueryKind::ResultQuery(error_path, _) => {
522							quote::quote_spanned!(storage.attr_span =>
523								Result<#value, #error_path>
524							)
525						},
526						QueryKind::ValueQuery => quote::quote!(#value),
527					};
528					quote::quote_spanned!(storage.attr_span =>
529						#(#cfg_attrs)*
530						impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
531							#[doc = #getter_doc_line]
532							pub fn #getter<KArg>(k: KArg) -> #query where
533								KArg: #frame_support::__private::codec::EncodeLike<#key>,
534							{
535								// NOTE: we can't use any trait here because CountedStorageMap
536								// doesn't implement any.
537								<#full_ident>::get(k)
538							}
539						}
540					)
541				},
542				Metadata::DoubleMap { key1, key2, value } => {
543					let query = match storage.query_kind.as_ref().expect("Checked by def") {
544						QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
545							Option<#value>
546						),
547						QueryKind::ResultQuery(error_path, _) => {
548							quote::quote_spanned!(storage.attr_span =>
549								Result<#value, #error_path>
550							)
551						},
552						QueryKind::ValueQuery => quote::quote!(#value),
553					};
554					quote::quote_spanned!(storage.attr_span =>
555						#(#cfg_attrs)*
556						impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
557							#[doc = #getter_doc_line]
558							pub fn #getter<KArg1, KArg2>(k1: KArg1, k2: KArg2) -> #query where
559								KArg1: #frame_support::__private::codec::EncodeLike<#key1>,
560								KArg2: #frame_support::__private::codec::EncodeLike<#key2>,
561							{
562								<
563									#full_ident as
564									#frame_support::storage::StorageDoubleMap<#key1, #key2, #value>
565								>::get(k1, k2)
566							}
567						}
568					)
569				},
570				Metadata::NMap { keygen, value, .. } => {
571					let query = match storage.query_kind.as_ref().expect("Checked by def") {
572						QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
573							Option<#value>
574						),
575						QueryKind::ResultQuery(error_path, _) => {
576							quote::quote_spanned!(storage.attr_span =>
577								Result<#value, #error_path>
578							)
579						},
580						QueryKind::ValueQuery => quote::quote!(#value),
581					};
582					quote::quote_spanned!(storage.attr_span =>
583						#(#cfg_attrs)*
584						impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
585							#[doc = #getter_doc_line]
586							pub fn #getter<KArg>(key: KArg) -> #query
587							where
588								KArg: #frame_support::storage::types::EncodeLikeTuple<
589									<#keygen as #frame_support::storage::types::KeyGenerator>::KArg
590								>
591									+ #frame_support::storage::types::TupleToEncodedIter,
592							{
593								<
594									#full_ident as
595									#frame_support::storage::StorageNMap<#keygen, #value>
596								>::get(key)
597							}
598						}
599					)
600				},
601				Metadata::CountedNMap { keygen, value, .. } => {
602					let query = match storage.query_kind.as_ref().expect("Checked by def") {
603						QueryKind::OptionQuery => quote::quote_spanned!(storage.attr_span =>
604							Option<#value>
605						),
606						QueryKind::ResultQuery(error_path, _) => {
607							quote::quote_spanned!(storage.attr_span =>
608								Result<#value, #error_path>
609							)
610						},
611						QueryKind::ValueQuery => quote::quote!(#value),
612					};
613					quote::quote_spanned!(storage.attr_span =>
614						#(#cfg_attrs)*
615						impl<#type_impl_gen> #pallet_ident<#type_use_gen> #completed_where_clause {
616							#[doc = #getter_doc_line]
617							pub fn #getter<KArg>(key: KArg) -> #query
618							where
619								KArg: #frame_support::storage::types::EncodeLikeTuple<
620									<#keygen as #frame_support::storage::types::KeyGenerator>::KArg
621								>
622									+ #frame_support::storage::types::TupleToEncodedIter,
623							{
624								// NOTE: we can't use any trait here because CountedStorageNMap
625								// doesn't implement any.
626								<#full_ident>::get(key)
627							}
628						}
629					)
630				},
631			}
632		} else {
633			Default::default()
634		}
635	});
636
637	let prefix_structs = def.storages.iter().map(|storage_def| {
638		let type_impl_gen = &def.type_impl_generics(storage_def.attr_span);
639		let type_use_gen = &def.type_use_generics(storage_def.attr_span);
640		let prefix_struct_ident = prefix_ident(storage_def);
641		let prefix_struct_vis = &storage_def.vis;
642		let prefix_struct_const = storage_def.prefix();
643		let config_where_clause = &def.config.where_clause;
644
645		let cfg_attrs = &storage_def.cfg_attrs;
646
647		let maybe_counter = match storage_def.metadata {
648			Metadata::CountedMap { .. } => {
649				let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
650				let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
651				let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
652				quote::quote_spanned!(storage_def.attr_span =>
653					#(#cfg_attrs)*
654					#[doc(hidden)]
655					#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
656						core::marker::PhantomData<(#type_use_gen,)>
657					);
658					#(#cfg_attrs)*
659					impl<#type_impl_gen> #frame_support::traits::StorageInstance
660						for #counter_prefix_struct_ident<#type_use_gen>
661						#config_where_clause
662					{
663						fn pallet_prefix() -> &'static str {
664							<
665								<T as #frame_system::Config>::PalletInfo
666								as #frame_support::traits::PalletInfo
667							>::name::<Pallet<#type_use_gen>>()
668								.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
669						}
670
671						fn pallet_prefix_hash() -> [u8; 16] {
672							<
673								<T as #frame_system::Config>::PalletInfo
674								as #frame_support::traits::PalletInfo
675							>::name_hash::<Pallet<#type_use_gen>>()
676								.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
677						}
678
679						const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
680						fn storage_prefix_hash() -> [u8; 16] {
681							#storage_prefix_hash
682						}
683					}
684					#(#cfg_attrs)*
685					impl<#type_impl_gen> #frame_support::storage::types::CountedStorageMapInstance
686						for #prefix_struct_ident<#type_use_gen>
687						#config_where_clause
688					{
689						type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
690					}
691				)
692			},
693			Metadata::CountedNMap { .. } => {
694				let counter_prefix_struct_ident = counter_prefix_ident(&storage_def.ident);
695				let counter_prefix_struct_const = counter_prefix(&prefix_struct_const);
696				let storage_prefix_hash = two128_str(&counter_prefix_struct_const);
697				quote::quote_spanned!(storage_def.attr_span =>
698					#(#cfg_attrs)*
699					#[doc(hidden)]
700					#prefix_struct_vis struct #counter_prefix_struct_ident<#type_use_gen>(
701						core::marker::PhantomData<(#type_use_gen,)>
702					);
703					#(#cfg_attrs)*
704					impl<#type_impl_gen> #frame_support::traits::StorageInstance
705						for #counter_prefix_struct_ident<#type_use_gen>
706						#config_where_clause
707					{
708						fn pallet_prefix() -> &'static str {
709							<
710								<T as #frame_system::Config>::PalletInfo
711								as #frame_support::traits::PalletInfo
712							>::name::<Pallet<#type_use_gen>>()
713								.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
714						}
715						fn pallet_prefix_hash() -> [u8; 16] {
716							<
717								<T as #frame_system::Config>::PalletInfo
718								as #frame_support::traits::PalletInfo
719							>::name_hash::<Pallet<#type_use_gen>>()
720								.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
721						}
722						const STORAGE_PREFIX: &'static str = #counter_prefix_struct_const;
723						fn storage_prefix_hash() -> [u8; 16] {
724							#storage_prefix_hash
725						}
726					}
727					#(#cfg_attrs)*
728					impl<#type_impl_gen> #frame_support::storage::types::CountedStorageNMapInstance
729						for #prefix_struct_ident<#type_use_gen>
730						#config_where_clause
731					{
732						type CounterPrefix = #counter_prefix_struct_ident<#type_use_gen>;
733					}
734				)
735			},
736			_ => proc_macro2::TokenStream::default(),
737		};
738
739		let storage_prefix_hash = two128_str(&prefix_struct_const);
740		quote::quote_spanned!(storage_def.attr_span =>
741			#maybe_counter
742
743			#(#cfg_attrs)*
744			#[doc(hidden)]
745			#prefix_struct_vis struct #prefix_struct_ident<#type_use_gen>(
746				core::marker::PhantomData<(#type_use_gen,)>
747			);
748			#(#cfg_attrs)*
749			impl<#type_impl_gen> #frame_support::traits::StorageInstance
750				for #prefix_struct_ident<#type_use_gen>
751				#config_where_clause
752			{
753				fn pallet_prefix() -> &'static str {
754					<
755						<T as #frame_system::Config>::PalletInfo
756						as #frame_support::traits::PalletInfo
757					>::name::<Pallet<#type_use_gen>>()
758						.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
759				}
760
761				fn pallet_prefix_hash() -> [u8; 16] {
762					<
763						<T as #frame_system::Config>::PalletInfo
764						as #frame_support::traits::PalletInfo
765					>::name_hash::<Pallet<#type_use_gen>>()
766						.expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
767				}
768
769				const STORAGE_PREFIX: &'static str = #prefix_struct_const;
770				fn storage_prefix_hash() -> [u8; 16] {
771					#storage_prefix_hash
772				}
773			}
774		)
775	});
776
777	let on_empty_structs = on_empty_struct_metadata.into_iter().map(|metadata| {
778		use crate::pallet::parse::GenericKind;
779		use syn::{GenericArgument, Path, PathArguments, PathSegment, Type, TypePath};
780
781		let ResultOnEmptyStructMetadata {
782			name,
783			visibility,
784			value_ty,
785			error_path,
786			variant_name,
787			span,
788		} = metadata;
789
790		let generic_kind = match error_path.segments.last() {
791			Some(PathSegment { arguments: PathArguments::AngleBracketed(args), .. }) => {
792				let (has_config, has_instance) =
793					args.args.iter().fold((false, false), |(has_config, has_instance), arg| {
794						match arg {
795							GenericArgument::Type(Type::Path(TypePath {
796								path: Path { segments, .. },
797								..
798							})) => {
799								let maybe_config =
800									segments.first().map_or(false, |seg| seg.ident == "T");
801								let maybe_instance =
802									segments.first().map_or(false, |seg| seg.ident == "I");
803
804								(has_config || maybe_config, has_instance || maybe_instance)
805							},
806							_ => (has_config, has_instance),
807						}
808					});
809				GenericKind::from_gens(has_config, has_instance).unwrap_or(GenericKind::None)
810			},
811			_ => GenericKind::None,
812		};
813		let type_impl_gen = generic_kind.type_impl_gen(proc_macro2::Span::call_site());
814		let config_where_clause = &def.config.where_clause;
815
816		quote::quote_spanned!(span =>
817			#[doc(hidden)]
818			#[allow(non_camel_case_types)]
819			#visibility struct #name;
820
821			impl<#type_impl_gen> #frame_support::traits::Get<Result<#value_ty, #error_path>>
822				for #name
823				#config_where_clause
824			{
825				fn get() -> Result<#value_ty, #error_path> {
826					Err(<#error_path>::#variant_name)
827				}
828			}
829		)
830	});
831
832	// aggregated where clause of all storage types and the whole pallet.
833	let mut where_clauses = vec![&def.config.where_clause];
834	where_clauses.extend(def.storages.iter().map(|storage| &storage.where_clause));
835	let completed_where_clause = super::merge_where_clauses(&where_clauses);
836	let type_impl_gen = &def.type_impl_generics(proc_macro2::Span::call_site());
837	let type_use_gen = &def.type_use_generics(proc_macro2::Span::call_site());
838
839	let try_decode_entire_state = {
840		let mut storage_names = def
841			.storages
842			.iter()
843			.filter_map(|storage| {
844				// A little hacky; don't generate for cfg gated storages to not get compile errors
845				// when building "frame-feature-testing" gated storages in the "frame-support-test"
846				// crate.
847				if storage.try_decode && storage.cfg_attrs.is_empty() {
848					let ident = &storage.ident;
849					let gen = &def.type_use_generics(storage.attr_span);
850					Some(quote::quote_spanned!(storage.attr_span => #ident<#gen> ))
851				} else {
852					None
853				}
854			})
855			.collect::<Vec<_>>();
856		storage_names.sort_by_cached_key(|ident| ident.to_string());
857
858		quote::quote!(
859			#frame_support::try_runtime_enabled! {
860				impl<#type_impl_gen> #frame_support::traits::TryDecodeEntireStorage
861				for #pallet_ident<#type_use_gen> #completed_where_clause
862				{
863					fn try_decode_entire_state() -> Result<usize, #frame_support::__private::Vec<#frame_support::traits::TryDecodeEntireStorageError>> {
864						let pallet_name = <<T as #frame_system::Config>::PalletInfo	as #frame_support::traits::PalletInfo>
865							::name::<#pallet_ident<#type_use_gen>>()
866							.expect("Every active pallet has a name in the runtime; qed");
867
868						#frame_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode pallet: {pallet_name}");
869
870						// NOTE: for now, we have to exclude storage items that are feature gated.
871						let mut errors = #frame_support::__private::Vec::new();
872						let mut decoded = 0usize;
873
874						#(
875							#frame_support::__private::log::debug!(target: "runtime::try-decode-state", "trying to decode storage: \
876							{pallet_name}::{}", stringify!(#storage_names));
877
878							match <#storage_names as #frame_support::traits::TryDecodeEntireStorage>::try_decode_entire_state() {
879								Ok(count) => {
880									decoded += count;
881								},
882								Err(err) => {
883									errors.extend(err);
884								},
885							}
886						)*
887
888						if errors.is_empty() {
889							Ok(decoded)
890						} else {
891							Err(errors)
892						}
893					}
894				}
895			}
896		)
897	};
898
899	quote::quote!(
900		impl<#type_impl_gen> #pallet_ident<#type_use_gen>
901			#completed_where_clause
902		{
903			#[doc(hidden)]
904			pub fn storage_metadata() -> #frame_support::__private::metadata_ir::PalletStorageMetadataIR {
905				#frame_support::__private::metadata_ir::PalletStorageMetadataIR {
906					prefix: <
907						<T as #frame_system::Config>::PalletInfo as
908						#frame_support::traits::PalletInfo
909					>::name::<#pallet_ident<#type_use_gen>>()
910						.expect("No name found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`."),
911					entries: {
912						#[allow(unused_mut)]
913						let mut entries = #frame_support::__private::vec![];
914						#( #entries_builder )*
915						entries
916					},
917				}
918			}
919		}
920
921		#( #getters )*
922		#( #prefix_structs )*
923		#( #on_empty_structs )*
924
925		#try_decode_entire_state
926	)
927}