frame_support_procedural/construct_runtime/expand/
outer_enums.rs
1use crate::construct_runtime::Pallet;
19use proc_macro2::{Span, TokenStream};
20use quote::{quote, ToTokens};
21use syn::{Generics, Ident};
22
23#[derive(Clone, Copy, PartialEq)]
25pub enum OuterEnumType {
26 Event,
28 Error,
30}
31
32impl OuterEnumType {
33 fn struct_name(&self) -> &str {
35 match self {
36 OuterEnumType::Event => "RuntimeEvent",
37 OuterEnumType::Error => "RuntimeError",
38 }
39 }
40
41 fn variant_name(&self) -> &str {
43 match self {
44 OuterEnumType::Event => "Event",
45 OuterEnumType::Error => "Error",
46 }
47 }
48}
49
50impl ToTokens for OuterEnumType {
51 fn to_tokens(&self, tokens: &mut TokenStream) {
52 match self {
53 OuterEnumType::Event => quote!(Event).to_tokens(tokens),
54 OuterEnumType::Error => quote!(Error).to_tokens(tokens),
55 }
56 }
57}
58
59pub fn expand_outer_enum(
86 runtime: &Ident,
87 pallet_decls: &[Pallet],
88 scrate: &TokenStream,
89 enum_ty: OuterEnumType,
90) -> syn::Result<TokenStream> {
91 let mut enum_variants = TokenStream::new();
93 let mut enum_conversions = TokenStream::new();
95 let mut query_enum_part_macros = Vec::new();
97
98 let enum_name_str = enum_ty.variant_name();
99 let enum_name_ident = Ident::new(enum_ty.struct_name(), Span::call_site());
100
101 for pallet_decl in pallet_decls {
102 let Some(pallet_entry) = pallet_decl.find_part(enum_name_str) else { continue };
103
104 let path = &pallet_decl.path;
105 let pallet_name = &pallet_decl.name;
106 let index = pallet_decl.index;
107 let instance = pallet_decl.instance.as_ref();
108 let generics = &pallet_entry.generics;
109
110 if instance.is_some() && generics.params.is_empty() {
111 let msg = format!(
112 "Instantiable pallet with no generic `{}` cannot \
113 be constructed: pallet `{}` must have generic `{}`",
114 enum_name_str, pallet_name, enum_name_str,
115 );
116 return Err(syn::Error::new(pallet_name.span(), msg))
117 }
118
119 let part_is_generic = !generics.params.is_empty();
120 let pallet_enum = match (instance, part_is_generic) {
121 (Some(inst), true) => quote!(#path::#enum_ty::<#runtime, #path::#inst>),
122 (Some(inst), false) => quote!(#path::#enum_ty::<#path::#inst>),
123 (None, true) => quote!(#path::#enum_ty::<#runtime>),
124 (None, false) => quote!(#path::#enum_ty),
125 };
126
127 enum_variants.extend(expand_enum_variant(
128 runtime,
129 pallet_decl,
130 index,
131 instance,
132 generics,
133 enum_ty,
134 ));
135 enum_conversions.extend(expand_enum_conversion(
136 pallet_decl,
137 &pallet_enum,
138 &enum_name_ident,
139 ));
140
141 if enum_ty == OuterEnumType::Event {
142 query_enum_part_macros.push(quote! {
143 #path::__substrate_event_check::is_event_part_defined!(#pallet_name);
144 });
145 }
146 }
147
148 let event_custom_derives =
150 if enum_ty == OuterEnumType::Event { quote!(Clone, PartialEq, Eq,) } else { quote!() };
151
152 let error_custom_impl = generate_error_impl(scrate, enum_ty);
154
155 Ok(quote! {
156 #( #query_enum_part_macros )*
157
158 #[derive(
159 #event_custom_derives
160 #scrate::__private::codec::Encode,
161 #scrate::__private::codec::Decode,
162 #scrate::__private::codec::DecodeWithMemTracking,
163 #scrate::__private::scale_info::TypeInfo,
164 #scrate::__private::Debug,
165 )]
166 #[allow(non_camel_case_types)]
167 pub enum #enum_name_ident {
168 #enum_variants
169 }
170
171 #enum_conversions
172
173 #error_custom_impl
174 })
175}
176
177fn expand_enum_variant(
178 runtime: &Ident,
179 pallet: &Pallet,
180 index: u8,
181 instance: Option<&Ident>,
182 generics: &Generics,
183 enum_ty: OuterEnumType,
184) -> TokenStream {
185 let path = &pallet.path;
186 let variant_name = &pallet.name;
187 let part_is_generic = !generics.params.is_empty();
188 let attr = pallet.get_attributes();
189
190 match instance {
191 Some(inst) if part_is_generic => quote! {
192 #attr
193 #[codec(index = #index)]
194 #variant_name(#path::#enum_ty<#runtime, #path::#inst>),
195 },
196 Some(inst) => quote! {
197 #attr
198 #[codec(index = #index)]
199 #variant_name(#path::#enum_ty<#path::#inst>),
200 },
201 None if part_is_generic => quote! {
202 #attr
203 #[codec(index = #index)]
204 #variant_name(#path::#enum_ty<#runtime>),
205 },
206 None => quote! {
207 #attr
208 #[codec(index = #index)]
209 #variant_name(#path::#enum_ty),
210 },
211 }
212}
213
214fn expand_enum_conversion(
215 pallet: &Pallet,
216 pallet_enum: &TokenStream,
217 enum_name_ident: &Ident,
218) -> TokenStream {
219 let variant_name = &pallet.name;
220 let attr = pallet.get_attributes();
221
222 quote! {
223 #attr
224 #[allow(deprecated)]
225 impl From<#pallet_enum> for #enum_name_ident {
226 fn from(x: #pallet_enum) -> Self {
227 #enum_name_ident
228 ::#variant_name(x)
229 }
230 }
231 #attr
232 #[allow(deprecated)]
233 impl TryInto<#pallet_enum> for #enum_name_ident {
234 type Error = ();
235
236 fn try_into(self) -> ::core::result::Result<#pallet_enum, Self::Error> {
237 match self {
238 Self::#variant_name(evt) => Ok(evt),
239 _ => Err(()),
240 }
241 }
242 }
243 }
244}
245
246fn generate_error_impl(scrate: &TokenStream, enum_ty: OuterEnumType) -> TokenStream {
247 if enum_ty == OuterEnumType::Event {
249 return quote! {}
250 }
251
252 let enum_name_ident = Ident::new(enum_ty.struct_name(), Span::call_site());
253
254 quote! {
255 impl #enum_name_ident {
256 pub fn from_dispatch_error(err: #scrate::sp_runtime::DispatchError) -> Option<Self> {
260 let #scrate::sp_runtime::DispatchError::Module(module_error) = err else { return None };
261
262 let bytes = #scrate::__private::codec::Encode::encode(&module_error);
263 #scrate::__private::codec::Decode::decode(&mut &bytes[..]).ok()
264 }
265 }
266 }
267}