frame_support_procedural/pallet/parse/
error.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, Fields};
21
22/// List of additional token to be used for parsing.
23mod keyword {
24	syn::custom_keyword!(Error);
25}
26
27/// Records information about the error enum variant field.
28pub struct VariantField {
29	/// Whether or not the field is named, i.e. whether it is a tuple variant or struct variant.
30	pub is_named: bool,
31}
32
33/// Records information about the error enum variants.
34pub struct VariantDef {
35	/// The variant ident.
36	pub ident: syn::Ident,
37	/// The variant field, if any.
38	pub field: Option<VariantField>,
39	/// The `cfg` attributes.
40	pub cfg_attrs: Vec<syn::Attribute>,
41}
42
43/// This checks error declaration as a enum declaration with only variants without fields nor
44/// discriminant.
45pub struct ErrorDef {
46	/// The index of error item in pallet module.
47	pub index: usize,
48	/// Variant definitions.
49	pub variants: Vec<VariantDef>,
50	/// A set of usage of instance, must be check for consistency with trait.
51	pub instances: Vec<helper::InstanceUsage>,
52	/// The keyword error used (contains span).
53	pub error: keyword::Error,
54	/// The span of the pallet::error attribute.
55	pub attr_span: proc_macro2::Span,
56	/// Attributes
57	pub attrs: Vec<syn::Attribute>,
58}
59
60impl ErrorDef {
61	pub fn try_from(
62		attr_span: proc_macro2::Span,
63		index: usize,
64		item: &mut syn::Item,
65	) -> syn::Result<Self> {
66		let item = if let syn::Item::Enum(item) = item {
67			item
68		} else {
69			return Err(syn::Error::new(item.span(), "Invalid pallet::error, expected item enum"))
70		};
71		if !matches!(item.vis, syn::Visibility::Public(_)) {
72			let msg = "Invalid pallet::error, `Error` must be public";
73			return Err(syn::Error::new(item.span(), msg))
74		}
75
76		let instances =
77			vec![helper::check_type_def_gen_no_bounds(&item.generics, item.ident.span())?];
78
79		if item.generics.where_clause.is_some() {
80			let msg = "Invalid pallet::error, where clause is not allowed on pallet error item";
81			return Err(syn::Error::new(item.generics.where_clause.as_ref().unwrap().span(), msg))
82		}
83
84		let error = syn::parse2::<keyword::Error>(item.ident.to_token_stream())?;
85
86		let variants = item
87			.variants
88			.iter()
89			.map(|variant| {
90				let field_ty = match &variant.fields {
91					Fields::Unit => None,
92					Fields::Named(_) => Some(VariantField { is_named: true }),
93					Fields::Unnamed(_) => Some(VariantField { is_named: false }),
94				};
95				if variant.discriminant.is_some() {
96					let msg = "Invalid pallet::error, unexpected discriminant, discriminants \
97						are not supported";
98					let span = variant.discriminant.as_ref().unwrap().0.span();
99					return Err(syn::Error::new(span, msg))
100				}
101				let cfg_attrs: Vec<syn::Attribute> = helper::get_item_cfg_attrs(&variant.attrs);
102
103				Ok(VariantDef { ident: variant.ident.clone(), field: field_ty, cfg_attrs })
104			})
105			.collect::<Result<_, _>>()?;
106
107		Ok(ErrorDef { attr_span, index, variants, instances, error, attrs: item.attrs.clone() })
108	}
109}