frame_support_procedural/runtime/parse/
pallet.rs1use crate::{
19 construct_runtime::parse::{Pallet, PalletPart, PalletPartKeyword, PalletPath},
20 runtime::parse::PalletDeclaration,
21};
22use frame_support_procedural_tools::get_doc_literals;
23use quote::ToTokens;
24use syn::{punctuated::Punctuated, spanned::Spanned, token, Error};
25
26impl Pallet {
27 pub fn try_from(
28 attr_span: proc_macro2::Span,
29 item: &syn::ItemType,
30 pallet_index: u8,
31 disable_call: bool,
32 disable_unsigned: bool,
33 bounds: &Punctuated<syn::TypeParamBound, token::Plus>,
34 ) -> syn::Result<Self> {
35 let name = item.ident.clone();
36
37 let mut pallet_path = None;
38 let mut pallet_parts = vec![];
39
40 for (index, bound) in bounds.into_iter().enumerate() {
41 if let syn::TypeParamBound::Trait(syn::TraitBound { path, .. }) = bound {
42 if index == 0 {
43 pallet_path = Some(PalletPath { inner: path.clone() });
44 } else {
45 let pallet_part = syn::parse2::<PalletPart>(bound.into_token_stream())?;
46 pallet_parts.push(pallet_part);
47 }
48 } else {
49 return Err(Error::new(
50 attr_span,
51 "Invalid pallet declaration, expected a path or a trait object",
52 ));
53 };
54 }
55
56 let mut path = pallet_path.ok_or(Error::new(
57 attr_span,
58 "Invalid pallet declaration, expected a path or a trait object",
59 ))?;
60
61 let PalletDeclaration { path: inner, instance, .. } =
62 PalletDeclaration::try_from(attr_span, item, &path.inner)?;
63
64 path = PalletPath { inner };
65
66 pallet_parts = pallet_parts
67 .into_iter()
68 .filter(|part| {
69 if let (true, &PalletPartKeyword::Call(_)) = (disable_call, &part.keyword) {
70 false
71 } else if let (true, &PalletPartKeyword::ValidateUnsigned(_)) =
72 (disable_unsigned, &part.keyword)
73 {
74 false
75 } else {
76 true
77 }
78 })
79 .collect();
80
81 let cfg_pattern = item
82 .attrs
83 .iter()
84 .filter(|attr| attr.path().segments.first().map_or(false, |s| s.ident == "cfg"))
85 .map(|attr| {
86 attr.parse_args_with(|input: syn::parse::ParseStream| {
87 let input = input.parse::<proc_macro2::TokenStream>()?;
88 cfg_expr::Expression::parse(&input.to_string())
89 .map_err(|e| syn::Error::new(attr.span(), e.to_string()))
90 })
91 })
92 .collect::<syn::Result<Vec<_>>>()?;
93
94 let docs = get_doc_literals(&item.attrs);
95
96 Ok(Pallet {
97 is_expanded: true,
98 name,
99 index: pallet_index,
100 path,
101 instance,
102 cfg_pattern,
103 pallet_parts,
104 docs,
105 })
106 }
107}
108
109#[test]
110fn pallet_parsing_works() {
111 use syn::{parse_quote, ItemType};
112
113 let item: ItemType = parse_quote! {
114 pub type System = frame_system + Call;
115 };
116 let ItemType { ty, .. } = item.clone();
117 let syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) = *ty else {
118 panic!("Expected a trait object");
119 };
120
121 let index = 0;
122 let pallet =
123 Pallet::try_from(proc_macro2::Span::call_site(), &item, index, false, false, &bounds)
124 .unwrap();
125
126 assert_eq!(pallet.name.to_string(), "System");
127 assert_eq!(pallet.index, index);
128 assert_eq!(pallet.path.to_token_stream().to_string(), "frame_system");
129 assert_eq!(pallet.instance, None);
130}
131
132#[test]
133fn pallet_parsing_works_with_instance() {
134 use syn::{parse_quote, ItemType};
135
136 let item: ItemType = parse_quote! {
137 pub type System = frame_system<Instance1> + Call;
138 };
139 let ItemType { ty, .. } = item.clone();
140 let syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) = *ty else {
141 panic!("Expected a trait object");
142 };
143
144 let index = 0;
145 let pallet =
146 Pallet::try_from(proc_macro2::Span::call_site(), &item, index, false, false, &bounds)
147 .unwrap();
148
149 assert_eq!(pallet.name.to_string(), "System");
150 assert_eq!(pallet.index, index);
151 assert_eq!(pallet.path.to_token_stream().to_string(), "frame_system");
152 assert_eq!(pallet.instance, Some(parse_quote! { Instance1 }));
153}
154
155#[test]
156fn pallet_parsing_works_with_pallet() {
157 use syn::{parse_quote, ItemType};
158
159 let item: ItemType = parse_quote! {
160 pub type System = frame_system::Pallet<Runtime> + Call;
161 };
162 let ItemType { ty, .. } = item.clone();
163 let syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) = *ty else {
164 panic!("Expected a trait object");
165 };
166
167 let index = 0;
168 let pallet =
169 Pallet::try_from(proc_macro2::Span::call_site(), &item, index, false, false, &bounds)
170 .unwrap();
171
172 assert_eq!(pallet.name.to_string(), "System");
173 assert_eq!(pallet.index, index);
174 assert_eq!(pallet.path.to_token_stream().to_string(), "frame_system");
175 assert_eq!(pallet.instance, None);
176}
177
178#[test]
179fn pallet_parsing_works_with_instance_and_pallet() {
180 use syn::{parse_quote, ItemType};
181
182 let item: ItemType = parse_quote! {
183 pub type System = frame_system::Pallet<Runtime, Instance1> + Call;
184 };
185 let ItemType { ty, .. } = item.clone();
186 let syn::Type::TraitObject(syn::TypeTraitObject { bounds, .. }) = *ty else {
187 panic!("Expected a trait object");
188 };
189
190 let index = 0;
191 let pallet =
192 Pallet::try_from(proc_macro2::Span::call_site(), &item, index, false, false, &bounds)
193 .unwrap();
194
195 assert_eq!(pallet.name.to_string(), "System");
196 assert_eq!(pallet.index, index);
197 assert_eq!(pallet.path.to_token_stream().to_string(), "frame_system");
198 assert_eq!(pallet.instance, Some(parse_quote! { Instance1 }));
199}