frame_support_procedural/pallet/expand/
tasks.rs1use crate::pallet::{parse::tasks::*, Def};
23use derive_syn_parse::Parse;
24use inflector::Inflector;
25use proc_macro2::TokenStream as TokenStream2;
26use quote::{format_ident, quote, ToTokens};
27use syn::{parse_quote, spanned::Spanned, ItemEnum, ItemImpl};
28
29impl TaskEnumDef {
30 pub fn generate(
34 tasks: &TasksDef,
35 type_decl_bounded_generics: TokenStream2,
36 type_use_generics: TokenStream2,
37 ) -> Self {
38 let variants = if tasks.tasks_attr.is_some() {
39 tasks
40 .tasks
41 .iter()
42 .map(|task| {
43 let ident = &task.item.sig.ident;
44 let ident =
45 format_ident!("{}", ident.to_string().to_class_case(), span = ident.span());
46
47 let args = task.item.sig.inputs.iter().collect::<Vec<_>>();
48
49 if args.is_empty() {
50 quote!(#ident)
51 } else {
52 quote!(#ident {
53 #(#args),*
54 })
55 }
56 })
57 .collect::<Vec<_>>()
58 } else {
59 Vec::new()
60 };
61 let mut task_enum_def: TaskEnumDef = parse_quote! {
62 #[pallet::task_enum]
67 pub enum Task<#type_decl_bounded_generics> {
68 #(
69 #variants,
70 )*
71 }
72 };
73 task_enum_def.type_use_generics = type_use_generics;
74 task_enum_def
75 }
76}
77
78impl ToTokens for TaskEnumDef {
79 fn to_tokens(&self, tokens: &mut TokenStream2) {
80 let item_enum = &self.item_enum;
81 let ident = &item_enum.ident;
82 let vis = &item_enum.vis;
83 let attrs = &item_enum.attrs;
84 let generics = &item_enum.generics;
85 let variants = &item_enum.variants;
86 let scrate = &self.scrate;
87 let type_use_generics = &self.type_use_generics;
88 if self.attr.is_some() {
89 tokens.extend(quote! {
91 #(#attrs)*
92 #[derive(
93 #scrate::CloneNoBound,
94 #scrate::EqNoBound,
95 #scrate::PartialEqNoBound,
96 #scrate::pallet_prelude::Encode,
97 #scrate::pallet_prelude::Decode,
98 #scrate::pallet_prelude::TypeInfo,
99 )]
100 #[codec(encode_bound())]
101 #[codec(decode_bound())]
102 #[scale_info(skip_type_params(#type_use_generics))]
103 #vis enum #ident #generics {
104 #variants
105 #[doc(hidden)]
106 #[codec(skip)]
107 __Ignore(core::marker::PhantomData<T>, #scrate::Never),
108 }
109
110 impl<T: Config> core::fmt::Debug for #ident<#type_use_generics> {
111 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112 f.debug_struct(stringify!(#ident)).field("value", self).finish()
113 }
114 }
115 });
116 } else {
117 tokens.extend(item_enum.to_token_stream());
119 }
120 }
121}
122
123#[derive(Parse)]
125pub struct ExpandedTasksDef {
126 pub task_item_impl: ItemImpl,
127 pub task_trait_impl: ItemImpl,
128}
129
130impl ToTokens for TasksDef {
131 fn to_tokens(&self, tokens: &mut TokenStream2) {
132 let scrate = &self.scrate;
133 let enum_ident = syn::Ident::new("Task", self.enum_ident.span());
134 let enum_arguments = &self.enum_arguments;
135 let enum_use = quote!(#enum_ident #enum_arguments);
136
137 let task_fn_idents = self
138 .tasks
139 .iter()
140 .map(|task| {
141 format_ident!(
142 "{}",
143 &task.item.sig.ident.to_string().to_class_case(),
144 span = task.item.sig.ident.span()
145 )
146 })
147 .collect::<Vec<_>>();
148 let task_indices = self.tasks.iter().map(|task| &task.index_attr.meta.index);
149 let task_conditions = self.tasks.iter().map(|task| &task.condition_attr.meta.expr);
150 let task_weights = self.tasks.iter().map(|task| &task.weight_attr.meta.expr);
151 let task_iters = self.tasks.iter().map(|task| &task.list_attr.meta.expr);
152
153 let task_fn_impls = self.tasks.iter().map(|task| {
154 let mut task_fn_impl = task.item.clone();
155 task_fn_impl.attrs = vec![];
156 task_fn_impl
157 });
158
159 let task_fn_names = self.tasks.iter().map(|task| &task.item.sig.ident);
160 let task_arg_names = self.tasks.iter().map(|task| &task.arg_names).collect::<Vec<_>>();
161
162 let impl_generics = &self.item_impl.generics;
163 tokens.extend(quote! {
164 impl #impl_generics #enum_use
165 {
166 #(#task_fn_impls)*
167 }
168
169 impl #impl_generics #scrate::traits::Task for #enum_use
170 {
171 type Enumeration = #scrate::__private::IntoIter<#enum_use>;
172
173 fn iter() -> Self::Enumeration {
174 let mut all_tasks = #scrate::__private::vec![];
175 #(all_tasks
176 .extend(#task_iters.map(|(#(#task_arg_names),*)| #enum_ident::#task_fn_idents { #(#task_arg_names: #task_arg_names.clone()),* })
177 .collect::<#scrate::__private::Vec<_>>());
178 )*
179 all_tasks.into_iter()
180 }
181
182 fn task_index(&self) -> u32 {
183 match self.clone() {
184 #(#enum_ident::#task_fn_idents { .. } => #task_indices,)*
185 Task::__Ignore(_, _) => unreachable!(),
186 }
187 }
188
189 fn is_valid(&self) -> bool {
190 match self.clone() {
191 #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => (#task_conditions)(#(#task_arg_names),* ),)*
192 Task::__Ignore(_, _) => unreachable!(),
193 }
194 }
195
196 fn run(&self) -> Result<(), #scrate::pallet_prelude::DispatchError> {
197 match self.clone() {
198 #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => {
199 <#enum_use>::#task_fn_names(#( #task_arg_names, )* )
200 },)*
201 Task::__Ignore(_, _) => unreachable!(),
202 }
203 }
204
205 #[allow(unused_variables)]
206 fn weight(&self) -> #scrate::pallet_prelude::Weight {
207 match self.clone() {
208 #(#enum_ident::#task_fn_idents { #(#task_arg_names),* } => #task_weights,)*
209 Task::__Ignore(_, _) => unreachable!(),
210 }
211 }
212 }
213 });
214 }
215}
216
217pub fn expand_tasks_impl(def: &mut Def) -> TokenStream2 {
221 let Some(tasks) = &mut def.tasks else { return quote!() };
222 let ExpandedTasksDef { task_item_impl, task_trait_impl } = parse_quote!(#tasks);
223 quote! {
224 #task_item_impl
225 #task_trait_impl
226 }
227}
228
229#[derive(Parse)]
231pub struct ExpandedTaskEnum {
232 pub item_enum: ItemEnum,
233 pub debug_impl: ItemImpl,
234}
235
236pub fn expand_task_enum(def: &mut Def) -> TokenStream2 {
240 let Some(task_enum) = &mut def.task_enum else { return quote!() };
241 let ExpandedTaskEnum { item_enum, debug_impl } = parse_quote!(#task_enum);
242 quote! {
243 #item_enum
244 #debug_impl
245 }
246}
247
248pub fn expand_tasks(def: &mut Def) -> TokenStream2 {
251 if let Some(tasks_def) = &def.tasks {
252 if def.task_enum.is_none() {
253 def.task_enum = Some(TaskEnumDef::generate(
254 &tasks_def,
255 def.type_decl_bounded_generics(tasks_def.item_impl.span()),
256 def.type_use_generics(tasks_def.item_impl.span()),
257 ));
258 }
259 }
260 let tasks_extra_output = expand_tasks_impl(def);
261 let task_enum_extra_output = expand_task_enum(def);
262 quote! {
263 #tasks_extra_output
264 #task_enum_extra_output
265 }
266}