referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/pallet/parse/
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 super::helper;
19use frame_support_procedural_tools::get_doc_literals;
20use quote::ToTokens;
21use std::collections::HashMap;
22use syn::spanned::Spanned;
23
24/// List of additional token to be used for parsing.
25mod keyword {
26	syn::custom_keyword!(Error);
27	syn::custom_keyword!(pallet);
28	syn::custom_keyword!(getter);
29	syn::custom_keyword!(storage_prefix);
30	syn::custom_keyword!(unbounded);
31	syn::custom_keyword!(whitelist_storage);
32	syn::custom_keyword!(disable_try_decode_storage);
33	syn::custom_keyword!(OptionQuery);
34	syn::custom_keyword!(ResultQuery);
35	syn::custom_keyword!(ValueQuery);
36}
37
38/// Parse for one of the following:
39/// * `#[pallet::getter(fn dummy)]`
40/// * `#[pallet::storage_prefix = "CustomName"]`
41/// * `#[pallet::unbounded]`
42/// * `#[pallet::whitelist_storage]
43/// * `#[pallet::disable_try_decode_storage]`
44pub enum PalletStorageAttr {
45	Getter(syn::Ident, proc_macro2::Span),
46	StorageName(syn::LitStr, proc_macro2::Span),
47	Unbounded(proc_macro2::Span),
48	WhitelistStorage(proc_macro2::Span),
49	DisableTryDecodeStorage(proc_macro2::Span),
50}
51
52impl PalletStorageAttr {
53	fn attr_span(&self) -> proc_macro2::Span {
54		match self {
55			Self::Getter(_, span) |
56			Self::StorageName(_, span) |
57			Self::Unbounded(span) |
58			Self::WhitelistStorage(span) => *span,
59			Self::DisableTryDecodeStorage(span) => *span,
60		}
61	}
62}
63
64impl syn::parse::Parse for PalletStorageAttr {
65	fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
66		input.parse::<syn::Token![#]>()?;
67		let attr_span = input.span();
68		let content;
69		syn::bracketed!(content in input);
70		content.parse::<keyword::pallet>()?;
71		content.parse::<syn::Token![::]>()?;
72
73		let lookahead = content.lookahead1();
74		if lookahead.peek(keyword::getter) {
75			content.parse::<keyword::getter>()?;
76
77			let generate_content;
78			syn::parenthesized!(generate_content in content);
79			generate_content.parse::<syn::Token![fn]>()?;
80			Ok(Self::Getter(generate_content.parse::<syn::Ident>()?, attr_span))
81		} else if lookahead.peek(keyword::storage_prefix) {
82			content.parse::<keyword::storage_prefix>()?;
83			content.parse::<syn::Token![=]>()?;
84
85			let renamed_prefix = content.parse::<syn::LitStr>()?;
86			// Ensure the renamed prefix is a proper Rust identifier
87			syn::parse_str::<syn::Ident>(&renamed_prefix.value()).map_err(|_| {
88				let msg = format!("`{}` is not a valid identifier", renamed_prefix.value());
89				syn::Error::new(renamed_prefix.span(), msg)
90			})?;
91
92			Ok(Self::StorageName(renamed_prefix, attr_span))
93		} else if lookahead.peek(keyword::unbounded) {
94			content.parse::<keyword::unbounded>()?;
95
96			Ok(Self::Unbounded(attr_span))
97		} else if lookahead.peek(keyword::whitelist_storage) {
98			content.parse::<keyword::whitelist_storage>()?;
99			Ok(Self::WhitelistStorage(attr_span))
100		} else if lookahead.peek(keyword::disable_try_decode_storage) {
101			content.parse::<keyword::disable_try_decode_storage>()?;
102			Ok(Self::DisableTryDecodeStorage(attr_span))
103		} else {
104			Err(lookahead.error())
105		}
106	}
107}
108
109struct PalletStorageAttrInfo {
110	getter: Option<syn::Ident>,
111	rename_as: Option<syn::LitStr>,
112	unbounded: bool,
113	whitelisted: bool,
114	try_decode: bool,
115}
116
117impl PalletStorageAttrInfo {
118	fn from_attrs(attrs: Vec<PalletStorageAttr>) -> syn::Result<Self> {
119		let mut getter = None;
120		let mut rename_as = None;
121		let mut unbounded = false;
122		let mut whitelisted = false;
123		let mut disable_try_decode_storage = false;
124		for attr in attrs {
125			match attr {
126				PalletStorageAttr::Getter(ident, ..) if getter.is_none() => getter = Some(ident),
127				PalletStorageAttr::StorageName(name, ..) if rename_as.is_none() =>
128					rename_as = Some(name),
129				PalletStorageAttr::Unbounded(..) if !unbounded => unbounded = true,
130				PalletStorageAttr::WhitelistStorage(..) if !whitelisted => whitelisted = true,
131				PalletStorageAttr::DisableTryDecodeStorage(..) if !disable_try_decode_storage =>
132					disable_try_decode_storage = true,
133				attr =>
134					return Err(syn::Error::new(
135						attr.attr_span(),
136						"Invalid attribute: Duplicate attribute",
137					)),
138			}
139		}
140
141		Ok(PalletStorageAttrInfo {
142			getter,
143			rename_as,
144			unbounded,
145			whitelisted,
146			try_decode: !disable_try_decode_storage,
147		})
148	}
149}
150
151/// The value and key types used by storages. Needed to expand metadata.
152pub enum Metadata {
153	Value { value: syn::Type },
154	Map { value: syn::Type, key: syn::Type },
155	CountedMap { value: syn::Type, key: syn::Type },
156	DoubleMap { value: syn::Type, key1: syn::Type, key2: syn::Type },
157	NMap { keys: Vec<syn::Type>, keygen: syn::Type, value: syn::Type },
158	CountedNMap { keys: Vec<syn::Type>, keygen: syn::Type, value: syn::Type },
159}
160
161pub enum QueryKind {
162	OptionQuery,
163	ResultQuery(syn::Path, syn::Ident),
164	ValueQuery,
165}
166
167/// Definition of a storage, storage is a storage type like
168/// `type MyStorage = StorageValue<MyStorageP, u32>`
169/// The keys and values types are parsed in order to get metadata
170pub struct StorageDef {
171	/// The index of storage item in pallet module.
172	pub index: usize,
173	/// Visibility of the storage type.
174	pub vis: syn::Visibility,
175	/// The type ident, to generate the StoragePrefix for.
176	pub ident: syn::Ident,
177	/// The keys and value metadata of the storage.
178	pub metadata: Metadata,
179	/// The doc associated to the storage.
180	pub docs: Vec<syn::Expr>,
181	/// A set of usage of instance, must be check for consistency with config.
182	pub instances: Vec<helper::InstanceUsage>,
183	/// Optional getter to generate. If some then query_kind is ensured to be some as well.
184	pub getter: Option<syn::Ident>,
185	/// Optional expression that evaluates to a type that can be used as StoragePrefix instead of
186	/// ident.
187	pub rename_as: Option<syn::LitStr>,
188	/// Whereas the querytype of the storage is OptionQuery, ResultQuery or ValueQuery.
189	/// Note that this is best effort as it can't be determined when QueryKind is generic, and
190	/// result can be false if user do some unexpected type alias.
191	pub query_kind: Option<QueryKind>,
192	/// Where clause of type definition.
193	pub where_clause: Option<syn::WhereClause>,
194	/// The span of the pallet::storage attribute.
195	pub attr_span: proc_macro2::Span,
196	/// The `cfg` attributes.
197	pub cfg_attrs: Vec<syn::Attribute>,
198	/// If generics are named (e.g. `StorageValue<Value = u32, ..>`) then this contains all the
199	/// generics of the storage.
200	/// If generics are not named, this is none.
201	pub named_generics: Option<StorageGenerics>,
202	/// If the value stored in this storage is unbounded.
203	pub unbounded: bool,
204	/// Whether or not reads to this storage key will be ignored by benchmarking
205	pub whitelisted: bool,
206	/// Whether or not to try to decode the storage key when running try-runtime checks.
207	pub try_decode: bool,
208	/// Whether or not a default hasher is allowed to replace `_`
209	pub use_default_hasher: bool,
210	/// Attributes
211	pub attrs: Vec<syn::Attribute>,
212}
213
214/// The parsed generic from the
215#[derive(Clone)]
216pub enum StorageGenerics {
217	DoubleMap {
218		hasher1: syn::Type,
219		key1: syn::Type,
220		hasher2: syn::Type,
221		key2: syn::Type,
222		value: syn::Type,
223		query_kind: Option<syn::Type>,
224		on_empty: Option<syn::Type>,
225		max_values: Option<syn::Type>,
226	},
227	Map {
228		hasher: syn::Type,
229		key: syn::Type,
230		value: syn::Type,
231		query_kind: Option<syn::Type>,
232		on_empty: Option<syn::Type>,
233		max_values: Option<syn::Type>,
234	},
235	CountedMap {
236		hasher: syn::Type,
237		key: syn::Type,
238		value: syn::Type,
239		query_kind: Option<syn::Type>,
240		on_empty: Option<syn::Type>,
241		max_values: Option<syn::Type>,
242	},
243	Value {
244		value: syn::Type,
245		query_kind: Option<syn::Type>,
246		on_empty: Option<syn::Type>,
247	},
248	NMap {
249		keygen: syn::Type,
250		value: syn::Type,
251		query_kind: Option<syn::Type>,
252		on_empty: Option<syn::Type>,
253		max_values: Option<syn::Type>,
254	},
255	CountedNMap {
256		keygen: syn::Type,
257		value: syn::Type,
258		query_kind: Option<syn::Type>,
259		on_empty: Option<syn::Type>,
260		max_values: Option<syn::Type>,
261	},
262}
263
264impl StorageGenerics {
265	/// Return the metadata from the defined generics
266	fn metadata(&self) -> syn::Result<Metadata> {
267		let res = match self.clone() {
268			Self::DoubleMap { value, key1, key2, .. } => Metadata::DoubleMap { value, key1, key2 },
269			Self::Map { value, key, .. } => Metadata::Map { value, key },
270			Self::CountedMap { value, key, .. } => Metadata::CountedMap { value, key },
271			Self::Value { value, .. } => Metadata::Value { value },
272			Self::NMap { keygen, value, .. } =>
273				Metadata::NMap { keys: collect_keys(&keygen)?, keygen, value },
274			Self::CountedNMap { keygen, value, .. } =>
275				Metadata::CountedNMap { keys: collect_keys(&keygen)?, keygen, value },
276		};
277
278		Ok(res)
279	}
280
281	/// Return the query kind from the defined generics
282	fn query_kind(&self) -> Option<syn::Type> {
283		match &self {
284			Self::DoubleMap { query_kind, .. } |
285			Self::Map { query_kind, .. } |
286			Self::CountedMap { query_kind, .. } |
287			Self::Value { query_kind, .. } |
288			Self::NMap { query_kind, .. } |
289			Self::CountedNMap { query_kind, .. } => query_kind.clone(),
290		}
291	}
292}
293
294enum StorageKind {
295	Value,
296	Map,
297	CountedMap,
298	DoubleMap,
299	NMap,
300	CountedNMap,
301}
302
303/// Check the generics in the `map` contains the generics in `gen` may contains generics in
304/// `optional_gen`, and doesn't contains any other.
305fn check_generics(
306	map: &HashMap<String, syn::AssocType>,
307	mandatory_generics: &[&str],
308	optional_generics: &[&str],
309	storage_type_name: &str,
310	args_span: proc_macro2::Span,
311) -> syn::Result<()> {
312	let mut errors = vec![];
313
314	let expectation = {
315		let mut e = format!(
316			"`{}` expect generics {}and optional generics {}",
317			storage_type_name,
318			mandatory_generics
319				.iter()
320				.map(|name| format!("`{}`, ", name))
321				.collect::<String>(),
322			&optional_generics.iter().map(|name| format!("`{}`, ", name)).collect::<String>(),
323		);
324		e.pop();
325		e.pop();
326		e.push('.');
327		e
328	};
329
330	for (gen_name, gen_binding) in map {
331		if !mandatory_generics.contains(&gen_name.as_str()) &&
332			!optional_generics.contains(&gen_name.as_str())
333		{
334			let msg = format!(
335				"Invalid pallet::storage, Unexpected generic `{}` for `{}`. {}",
336				gen_name, storage_type_name, expectation,
337			);
338			errors.push(syn::Error::new(gen_binding.span(), msg));
339		}
340	}
341
342	for mandatory_generic in mandatory_generics {
343		if !map.contains_key(&mandatory_generic.to_string()) {
344			let msg = format!(
345				"Invalid pallet::storage, cannot find `{}` generic, required for `{}`.",
346				mandatory_generic, storage_type_name
347			);
348			errors.push(syn::Error::new(args_span, msg));
349		}
350	}
351
352	let mut errors = errors.drain(..);
353	if let Some(mut error) = errors.next() {
354		for other_error in errors {
355			error.combine(other_error);
356		}
357		Err(error)
358	} else {
359		Ok(())
360	}
361}
362
363/// Returns `(named generics, metadata, query kind, use_default_hasher)`
364fn process_named_generics(
365	storage: &StorageKind,
366	args_span: proc_macro2::Span,
367	args: &[syn::AssocType],
368	dev_mode: bool,
369) -> syn::Result<(Option<StorageGenerics>, Metadata, Option<syn::Type>, bool)> {
370	let mut parsed = HashMap::<String, syn::AssocType>::new();
371
372	// Ensure no duplicate.
373	for arg in args {
374		if let Some(other) = parsed.get(&arg.ident.to_string()) {
375			let msg = "Invalid pallet::storage, Duplicated named generic";
376			let mut err = syn::Error::new(arg.ident.span(), msg);
377			err.combine(syn::Error::new(other.ident.span(), msg));
378			return Err(err);
379		}
380		parsed.insert(arg.ident.to_string(), arg.clone());
381	}
382
383	let mut map_mandatory_generics = vec!["Key", "Value"];
384	let mut map_optional_generics = vec!["QueryKind", "OnEmpty", "MaxValues"];
385	if dev_mode {
386		map_optional_generics.push("Hasher");
387	} else {
388		map_mandatory_generics.push("Hasher");
389	}
390
391	let generics = match storage {
392		StorageKind::Value => {
393			check_generics(
394				&parsed,
395				&["Value"],
396				&["QueryKind", "OnEmpty"],
397				"StorageValue",
398				args_span,
399			)?;
400
401			StorageGenerics::Value {
402				value: parsed
403					.remove("Value")
404					.map(|binding| binding.ty)
405					.expect("checked above as mandatory generic"),
406				query_kind: parsed.remove("QueryKind").map(|binding| binding.ty),
407				on_empty: parsed.remove("OnEmpty").map(|binding| binding.ty),
408			}
409		},
410		StorageKind::Map => {
411			check_generics(
412				&parsed,
413				&map_mandatory_generics,
414				&map_optional_generics,
415				"StorageMap",
416				args_span,
417			)?;
418
419			StorageGenerics::Map {
420				hasher: parsed
421					.remove("Hasher")
422					.map(|binding| binding.ty)
423					.unwrap_or(syn::parse_quote!(Blake2_128Concat)),
424				key: parsed
425					.remove("Key")
426					.map(|binding| binding.ty)
427					.expect("checked above as mandatory generic"),
428				value: parsed
429					.remove("Value")
430					.map(|binding| binding.ty)
431					.expect("checked above as mandatory generic"),
432				query_kind: parsed.remove("QueryKind").map(|binding| binding.ty),
433				on_empty: parsed.remove("OnEmpty").map(|binding| binding.ty),
434				max_values: parsed.remove("MaxValues").map(|binding| binding.ty),
435			}
436		},
437		StorageKind::CountedMap => {
438			check_generics(
439				&parsed,
440				&map_mandatory_generics,
441				&map_optional_generics,
442				"CountedStorageMap",
443				args_span,
444			)?;
445
446			StorageGenerics::CountedMap {
447				hasher: parsed
448					.remove("Hasher")
449					.map(|binding| binding.ty)
450					.unwrap_or(syn::Type::Verbatim(quote::quote! { Blake2_128Concat })),
451				key: parsed
452					.remove("Key")
453					.map(|binding| binding.ty)
454					.expect("checked above as mandatory generic"),
455				value: parsed
456					.remove("Value")
457					.map(|binding| binding.ty)
458					.expect("checked above as mandatory generic"),
459				query_kind: parsed.remove("QueryKind").map(|binding| binding.ty),
460				on_empty: parsed.remove("OnEmpty").map(|binding| binding.ty),
461				max_values: parsed.remove("MaxValues").map(|binding| binding.ty),
462			}
463		},
464		StorageKind::DoubleMap => {
465			let mut double_map_mandatory_generics = vec!["Key1", "Key2", "Value"];
466			if dev_mode {
467				map_optional_generics.extend(["Hasher1", "Hasher2"]);
468			} else {
469				double_map_mandatory_generics.extend(["Hasher1", "Hasher2"]);
470			}
471
472			check_generics(
473				&parsed,
474				&double_map_mandatory_generics,
475				&map_optional_generics,
476				"StorageDoubleMap",
477				args_span,
478			)?;
479
480			StorageGenerics::DoubleMap {
481				hasher1: parsed
482					.remove("Hasher1")
483					.map(|binding| binding.ty)
484					.unwrap_or(syn::parse_quote!(Blake2_128Concat)),
485				key1: parsed
486					.remove("Key1")
487					.map(|binding| binding.ty)
488					.expect("checked above as mandatory generic"),
489				hasher2: parsed
490					.remove("Hasher2")
491					.map(|binding| binding.ty)
492					.unwrap_or(syn::parse_quote!(Blake2_128Concat)),
493				key2: parsed
494					.remove("Key2")
495					.map(|binding| binding.ty)
496					.expect("checked above as mandatory generic"),
497				value: parsed
498					.remove("Value")
499					.map(|binding| binding.ty)
500					.expect("checked above as mandatory generic"),
501				query_kind: parsed.remove("QueryKind").map(|binding| binding.ty),
502				on_empty: parsed.remove("OnEmpty").map(|binding| binding.ty),
503				max_values: parsed.remove("MaxValues").map(|binding| binding.ty),
504			}
505		},
506		StorageKind::NMap => {
507			check_generics(
508				&parsed,
509				&["Key", "Value"],
510				&["QueryKind", "OnEmpty", "MaxValues"],
511				"StorageNMap",
512				args_span,
513			)?;
514
515			StorageGenerics::NMap {
516				keygen: parsed
517					.remove("Key")
518					.map(|binding| binding.ty)
519					.expect("checked above as mandatory generic"),
520				value: parsed
521					.remove("Value")
522					.map(|binding| binding.ty)
523					.expect("checked above as mandatory generic"),
524				query_kind: parsed.remove("QueryKind").map(|binding| binding.ty),
525				on_empty: parsed.remove("OnEmpty").map(|binding| binding.ty),
526				max_values: parsed.remove("MaxValues").map(|binding| binding.ty),
527			}
528		},
529		StorageKind::CountedNMap => {
530			check_generics(
531				&parsed,
532				&["Key", "Value"],
533				&["QueryKind", "OnEmpty", "MaxValues"],
534				"CountedStorageNMap",
535				args_span,
536			)?;
537
538			StorageGenerics::CountedNMap {
539				keygen: parsed
540					.remove("Key")
541					.map(|binding| binding.ty)
542					.expect("checked above as mandatory generic"),
543				value: parsed
544					.remove("Value")
545					.map(|binding| binding.ty)
546					.expect("checked above as mandatory generic"),
547				query_kind: parsed.remove("QueryKind").map(|binding| binding.ty),
548				on_empty: parsed.remove("OnEmpty").map(|binding| binding.ty),
549				max_values: parsed.remove("MaxValues").map(|binding| binding.ty),
550			}
551		},
552	};
553
554	let metadata = generics.metadata()?;
555	let query_kind = generics.query_kind();
556
557	Ok((Some(generics), metadata, query_kind, false))
558}
559
560/// Returns `(named generics, metadata, query kind, use_default_hasher)`
561fn process_unnamed_generics(
562	storage: &StorageKind,
563	args_span: proc_macro2::Span,
564	args: &[syn::Type],
565	dev_mode: bool,
566) -> syn::Result<(Option<StorageGenerics>, Metadata, Option<syn::Type>, bool)> {
567	let retrieve_arg = |arg_pos| {
568		args.get(arg_pos).cloned().ok_or_else(|| {
569			let msg = format!(
570				"Invalid pallet::storage, unexpected number of generic argument, \
571						expect at least {} args, found {}.",
572				arg_pos + 1,
573				args.len(),
574			);
575			syn::Error::new(args_span, msg)
576		})
577	};
578
579	let prefix_arg = retrieve_arg(0)?;
580	syn::parse2::<syn::Token![_]>(prefix_arg.to_token_stream()).map_err(|e| {
581		let msg = "Invalid pallet::storage, for unnamed generic arguments the type \
582				first generic argument must be `_`, the argument is then replaced by macro.";
583		let mut err = syn::Error::new(prefix_arg.span(), msg);
584		err.combine(e);
585		err
586	})?;
587
588	let use_default_hasher = |arg_pos| {
589		let arg = retrieve_arg(arg_pos)?;
590		if syn::parse2::<syn::Token![_]>(arg.to_token_stream()).is_ok() {
591			if dev_mode {
592				Ok(true)
593			} else {
594				let msg = "`_` can only be used in dev_mode. Please specify an appropriate hasher.";
595				Err(syn::Error::new(arg.span(), msg))
596			}
597		} else {
598			Ok(false)
599		}
600	};
601
602	let res = match storage {
603		StorageKind::Value =>
604			(None, Metadata::Value { value: retrieve_arg(1)? }, retrieve_arg(2).ok(), false),
605		StorageKind::Map => (
606			None,
607			Metadata::Map { key: retrieve_arg(2)?, value: retrieve_arg(3)? },
608			retrieve_arg(4).ok(),
609			use_default_hasher(1)?,
610		),
611		StorageKind::CountedMap => (
612			None,
613			Metadata::CountedMap { key: retrieve_arg(2)?, value: retrieve_arg(3)? },
614			retrieve_arg(4).ok(),
615			use_default_hasher(1)?,
616		),
617		StorageKind::DoubleMap => (
618			None,
619			Metadata::DoubleMap {
620				key1: retrieve_arg(2)?,
621				key2: retrieve_arg(4)?,
622				value: retrieve_arg(5)?,
623			},
624			retrieve_arg(6).ok(),
625			use_default_hasher(1)? && use_default_hasher(3)?,
626		),
627		StorageKind::NMap => {
628			let keygen = retrieve_arg(1)?;
629			let keys = collect_keys(&keygen)?;
630			(
631				None,
632				Metadata::NMap { keys, keygen, value: retrieve_arg(2)? },
633				retrieve_arg(3).ok(),
634				false,
635			)
636		},
637		StorageKind::CountedNMap => {
638			let keygen = retrieve_arg(1)?;
639			let keys = collect_keys(&keygen)?;
640			(
641				None,
642				Metadata::CountedNMap { keys, keygen, value: retrieve_arg(2)? },
643				retrieve_arg(3).ok(),
644				false,
645			)
646		},
647	};
648
649	Ok(res)
650}
651
652/// Returns `(named generics, metadata, query kind, use_default_hasher)`
653fn process_generics(
654	segment: &syn::PathSegment,
655	dev_mode: bool,
656) -> syn::Result<(Option<StorageGenerics>, Metadata, Option<syn::Type>, bool)> {
657	let storage_kind = match &*segment.ident.to_string() {
658		"StorageValue" => StorageKind::Value,
659		"StorageMap" => StorageKind::Map,
660		"CountedStorageMap" => StorageKind::CountedMap,
661		"StorageDoubleMap" => StorageKind::DoubleMap,
662		"StorageNMap" => StorageKind::NMap,
663		"CountedStorageNMap" => StorageKind::CountedNMap,
664		found => {
665			let msg = format!(
666				"Invalid pallet::storage, expected ident: `StorageValue` or \
667				`StorageMap` or `CountedStorageMap` or `StorageDoubleMap` or `StorageNMap` or `CountedStorageNMap` \
668				in order to expand metadata, found `{}`.",
669				found,
670			);
671			return Err(syn::Error::new(segment.ident.span(), msg));
672		},
673	};
674
675	let args_span = segment.arguments.span();
676
677	let args = match &segment.arguments {
678		syn::PathArguments::AngleBracketed(args) if !args.args.is_empty() => args,
679		_ => {
680			let msg = "Invalid pallet::storage, invalid number of generic generic arguments, \
681				expect more that 0 generic arguments.";
682			return Err(syn::Error::new(segment.span(), msg));
683		},
684	};
685
686	if args.args.iter().all(|gen| matches!(gen, syn::GenericArgument::Type(_))) {
687		let args = args
688			.args
689			.iter()
690			.map(|gen| match gen {
691				syn::GenericArgument::Type(gen) => gen.clone(),
692				_ => unreachable!("It is asserted above that all generics are types"),
693			})
694			.collect::<Vec<_>>();
695		process_unnamed_generics(&storage_kind, args_span, &args, dev_mode)
696	} else if args.args.iter().all(|gen| matches!(gen, syn::GenericArgument::AssocType(_))) {
697		let args = args
698			.args
699			.iter()
700			.map(|gen| match gen {
701				syn::GenericArgument::AssocType(gen) => gen.clone(),
702				_ => unreachable!("It is asserted above that all generics are bindings"),
703			})
704			.collect::<Vec<_>>();
705		process_named_generics(&storage_kind, args_span, &args, dev_mode)
706	} else {
707		let msg = "Invalid pallet::storage, invalid generic declaration for storage. Expect only \
708			type generics or binding generics, e.g. `<Name1 = Gen1, Name2 = Gen2, ..>` or \
709			`<Gen1, Gen2, ..>`.";
710		Err(syn::Error::new(segment.span(), msg))
711	}
712}
713
714/// Parse the 2nd type argument to `StorageNMap` and return its keys.
715fn collect_keys(keygen: &syn::Type) -> syn::Result<Vec<syn::Type>> {
716	if let syn::Type::Tuple(tup) = keygen {
717		tup.elems.iter().map(extract_key).collect::<syn::Result<Vec<_>>>()
718	} else {
719		Ok(vec![extract_key(keygen)?])
720	}
721}
722
723/// In `Key<H, K>`, extract K and return it.
724fn extract_key(ty: &syn::Type) -> syn::Result<syn::Type> {
725	let typ = if let syn::Type::Path(typ) = ty {
726		typ
727	} else {
728		let msg = "Invalid pallet::storage, expected type path";
729		return Err(syn::Error::new(ty.span(), msg));
730	};
731
732	let key_struct = typ.path.segments.last().ok_or_else(|| {
733		let msg = "Invalid pallet::storage, expected type path with at least one segment";
734		syn::Error::new(typ.path.span(), msg)
735	})?;
736	if key_struct.ident != "Key" && key_struct.ident != "NMapKey" {
737		let msg = "Invalid pallet::storage, expected Key or NMapKey struct";
738		return Err(syn::Error::new(key_struct.ident.span(), msg));
739	}
740
741	let ty_params = if let syn::PathArguments::AngleBracketed(args) = &key_struct.arguments {
742		args
743	} else {
744		let msg = "Invalid pallet::storage, expected angle bracketed arguments";
745		return Err(syn::Error::new(key_struct.arguments.span(), msg));
746	};
747
748	if ty_params.args.len() != 2 {
749		let msg = format!(
750			"Invalid pallet::storage, unexpected number of generic arguments \
751			for Key struct, expected 2 args, found {}",
752			ty_params.args.len()
753		);
754		return Err(syn::Error::new(ty_params.span(), msg));
755	}
756
757	let key = match &ty_params.args[1] {
758		syn::GenericArgument::Type(key_ty) => key_ty.clone(),
759		_ => {
760			let msg = "Invalid pallet::storage, expected type";
761			return Err(syn::Error::new(ty_params.args[1].span(), msg));
762		},
763	};
764
765	Ok(key)
766}
767
768impl StorageDef {
769	/// Return the storage prefix for this storage item
770	pub fn prefix(&self) -> String {
771		self.rename_as
772			.as_ref()
773			.map(syn::LitStr::value)
774			.unwrap_or_else(|| self.ident.to_string())
775	}
776
777	/// Return either the span of the ident or the span of the literal in the
778	/// #[storage_prefix] attribute
779	pub fn prefix_span(&self) -> proc_macro2::Span {
780		self.rename_as
781			.as_ref()
782			.map(syn::LitStr::span)
783			.unwrap_or_else(|| self.ident.span())
784	}
785
786	pub fn try_from(
787		attr_span: proc_macro2::Span,
788		index: usize,
789		item: &mut syn::Item,
790		dev_mode: bool,
791	) -> syn::Result<Self> {
792		let item = if let syn::Item::Type(item) = item {
793			item
794		} else {
795			return Err(syn::Error::new(item.span(), "Invalid pallet::storage, expect item type."));
796		};
797
798		let attrs: Vec<PalletStorageAttr> = helper::take_item_pallet_attrs(&mut item.attrs)?;
799		let PalletStorageAttrInfo { getter, rename_as, mut unbounded, whitelisted, try_decode } =
800			PalletStorageAttrInfo::from_attrs(attrs)?;
801
802		// set all storages to be unbounded if dev_mode is enabled
803		unbounded |= dev_mode;
804		let cfg_attrs = helper::get_item_cfg_attrs(&item.attrs);
805
806		let instances = vec![helper::check_type_def_gen(&item.generics, item.ident.span())?];
807
808		let where_clause = item.generics.where_clause.clone();
809		let docs = get_doc_literals(&item.attrs);
810
811		let typ = if let syn::Type::Path(typ) = &*item.ty {
812			typ
813		} else {
814			let msg = "Invalid pallet::storage, expected type path";
815			return Err(syn::Error::new(item.ty.span(), msg));
816		};
817
818		if typ.path.segments.len() != 1 {
819			let msg = "Invalid pallet::storage, expected type path with one segment";
820			return Err(syn::Error::new(item.ty.span(), msg));
821		}
822
823		let (named_generics, metadata, query_kind, use_default_hasher) =
824			process_generics(&typ.path.segments[0], dev_mode)?;
825
826		let query_kind = query_kind
827			.map(|query_kind| {
828				use syn::{
829					AngleBracketedGenericArguments, GenericArgument, Path, PathArguments, Type,
830					TypePath,
831				};
832
833				let result_query = match query_kind {
834					Type::Path(path)
835						if path
836							.path
837							.segments
838							.last()
839							.map_or(false, |s| s.ident == "OptionQuery") =>
840						return Ok(Some(QueryKind::OptionQuery)),
841					Type::Path(TypePath { path: Path { segments, .. }, .. })
842						if segments.last().map_or(false, |s| s.ident == "ResultQuery") =>
843						segments
844							.last()
845							.expect("segments is checked to have the last value; qed")
846							.clone(),
847					Type::Path(path)
848						if path.path.segments.last().map_or(false, |s| s.ident == "ValueQuery") =>
849						return Ok(Some(QueryKind::ValueQuery)),
850					_ => return Ok(None),
851				};
852
853				let error_type = match result_query.arguments {
854					PathArguments::AngleBracketed(AngleBracketedGenericArguments {
855						args, ..
856					}) => {
857						if args.len() != 1 {
858							let msg = format!(
859								"Invalid pallet::storage, unexpected number of generic arguments \
860								for ResultQuery, expected 1 type argument, found {}",
861								args.len(),
862							);
863							return Err(syn::Error::new(args.span(), msg));
864						}
865
866						args[0].clone()
867					},
868					args => {
869						let msg = format!(
870							"Invalid pallet::storage, unexpected generic args for ResultQuery, \
871							expected angle-bracketed arguments, found `{}`",
872							args.to_token_stream().to_string()
873						);
874						return Err(syn::Error::new(args.span(), msg));
875					},
876				};
877
878				match error_type {
879					GenericArgument::Type(Type::Path(TypePath {
880						path: Path { segments: err_variant, leading_colon },
881						..
882					})) => {
883						if err_variant.len() < 2 {
884							let msg = format!(
885								"Invalid pallet::storage, unexpected number of path segments for \
886								the generics in ResultQuery, expected a path with at least 2 \
887								segments, found {}",
888								err_variant.len(),
889							);
890							return Err(syn::Error::new(err_variant.span(), msg));
891						}
892						let mut error = err_variant.clone();
893						let err_variant = error
894							.pop()
895							.expect("Checked to have at least 2; qed")
896							.into_value()
897							.ident;
898
899						// Necessary here to eliminate the last double colon
900						let last =
901							error.pop().expect("Checked to have at least 2; qed").into_value();
902						error.push_value(last);
903
904						Ok(Some(QueryKind::ResultQuery(
905							syn::Path { leading_colon, segments: error },
906							err_variant,
907						)))
908					},
909					gen_arg => {
910						let msg = format!(
911							"Invalid pallet::storage, unexpected generic argument kind, expected a \
912							type path to a `PalletError` enum variant, found `{}`",
913							gen_arg.to_token_stream().to_string(),
914						);
915						Err(syn::Error::new(gen_arg.span(), msg))
916					},
917				}
918			})
919			.transpose()?
920			.unwrap_or(Some(QueryKind::OptionQuery));
921
922		if let (None, Some(getter)) = (query_kind.as_ref(), getter.as_ref()) {
923			let msg = "Invalid pallet::storage, cannot generate getter because QueryKind is not \
924				identifiable. QueryKind must be `OptionQuery`, `ResultQuery`, `ValueQuery`, or default \
925				one to be identifiable.";
926			return Err(syn::Error::new(getter.span(), msg));
927		}
928
929		Ok(StorageDef {
930			attr_span,
931			index,
932			vis: item.vis.clone(),
933			ident: item.ident.clone(),
934			instances,
935			metadata,
936			docs,
937			getter,
938			rename_as,
939			query_kind,
940			where_clause,
941			cfg_attrs,
942			named_generics,
943			unbounded,
944			whitelisted,
945			try_decode,
946			use_default_hasher,
947			attrs: item.attrs.clone(),
948		})
949	}
950}