frame_support_procedural/pallet/expand/
view_functions.rs
1use crate::pallet::{parse::view_functions::ViewFunctionDef, Def};
19use proc_macro2::{Span, TokenStream};
20use syn::spanned::Spanned;
21
22pub fn expand_view_functions(def: &Def) -> TokenStream {
23 let (span, where_clause, view_fns) = match def.view_functions.as_ref() {
24 Some(view_fns) =>
25 (view_fns.attr_span, view_fns.where_clause.clone(), view_fns.view_functions.clone()),
26 None => (def.item.span(), def.config.where_clause.clone(), Vec::new()),
27 };
28
29 let view_function_prefix_impl =
30 expand_view_function_prefix_impl(def, span, where_clause.as_ref());
31
32 let view_fn_impls = view_fns
33 .iter()
34 .map(|view_fn| expand_view_function(def, span, where_clause.as_ref(), view_fn));
35 let impl_dispatch_view_function =
36 impl_dispatch_view_function(def, span, where_clause.as_ref(), &view_fns);
37 let impl_view_function_metadata =
38 impl_view_function_metadata(def, span, where_clause.as_ref(), &view_fns);
39
40 quote::quote! {
41 #view_function_prefix_impl
42 #( #view_fn_impls )*
43 #impl_dispatch_view_function
44 #impl_view_function_metadata
45 }
46}
47
48fn expand_view_function_prefix_impl(
49 def: &Def,
50 span: Span,
51 where_clause: Option<&syn::WhereClause>,
52) -> TokenStream {
53 let pallet_ident = &def.pallet_struct.pallet;
54 let frame_support = &def.frame_support;
55 let frame_system = &def.frame_system;
56 let type_impl_gen = &def.type_impl_generics(span);
57 let type_use_gen = &def.type_use_generics(span);
58
59 quote::quote! {
60 impl<#type_impl_gen> #frame_support::view_functions::ViewFunctionIdPrefix for #pallet_ident<#type_use_gen> #where_clause {
61 fn prefix() -> [::core::primitive::u8; 16usize] {
62 <
63 <T as #frame_system::Config>::PalletInfo
64 as #frame_support::traits::PalletInfo
65 >::name_hash::<Pallet<#type_use_gen>>()
66 .expect("No name_hash found for the pallet in the runtime! This usually means that the pallet wasn't added to `construct_runtime!`.")
67 }
68 }
69 }
70}
71
72fn expand_view_function(
73 def: &Def,
74 span: Span,
75 where_clause: Option<&syn::WhereClause>,
76 view_fn: &ViewFunctionDef,
77) -> TokenStream {
78 let frame_support = &def.frame_support;
79 let pallet_ident = &def.pallet_struct.pallet;
80 let type_impl_gen = &def.type_impl_generics(span);
81 let type_decl_bounded_gen = &def.type_decl_bounded_generics(span);
82 let type_use_gen = &def.type_use_generics(span);
83 let capture_docs = if cfg!(feature = "no-metadata-docs") { "never" } else { "always" };
84
85 let view_function_struct_ident = view_fn.view_function_struct_ident();
86 let view_fn_name = &view_fn.name;
87 let (arg_names, arg_types) = match view_fn.args_names_types() {
88 Ok((arg_names, arg_types)) => (arg_names, arg_types),
89 Err(e) => return e.into_compile_error(),
90 };
91 let return_type = &view_fn.return_type;
92 let docs = &view_fn.docs;
93
94 let view_function_id_suffix_bytes_raw = match view_fn.view_function_id_suffix_bytes() {
95 Ok(view_function_id_suffix_bytes_raw) => view_function_id_suffix_bytes_raw,
96 Err(e) => return e.into_compile_error(),
97 };
98 let view_function_id_suffix_bytes = view_function_id_suffix_bytes_raw
99 .map(|byte| syn::LitInt::new(&format!("0x{:X}_u8", byte), Span::call_site()));
100
101 quote::quote! {
102 #( #[doc = #docs] )*
103 #[allow(missing_docs)]
104 #[derive(
105 #frame_support::RuntimeDebugNoBound,
106 #frame_support::CloneNoBound,
107 #frame_support::EqNoBound,
108 #frame_support::PartialEqNoBound,
109 #frame_support::__private::codec::Encode,
110 #frame_support::__private::codec::Decode,
111 #frame_support::__private::codec::DecodeWithMemTracking,
112 #frame_support::__private::scale_info::TypeInfo,
113 )]
114 #[codec(encode_bound())]
115 #[codec(decode_bound())]
116 #[scale_info(skip_type_params(#type_use_gen), capture_docs = #capture_docs)]
117 pub struct #view_function_struct_ident<#type_decl_bounded_gen> #where_clause {
118 #(
119 pub #arg_names: #arg_types,
120 )*
121 _marker: ::core::marker::PhantomData<(#type_use_gen,)>,
122 }
123
124 impl<#type_impl_gen> #view_function_struct_ident<#type_use_gen> #where_clause {
125 pub fn new(#( #arg_names: #arg_types, )*) -> Self {
127 Self {
128 #( #arg_names, )*
129 _marker: ::core::default::Default::default()
130 }
131 }
132 }
133
134 impl<#type_impl_gen> #frame_support::view_functions::ViewFunctionIdSuffix for #view_function_struct_ident<#type_use_gen> #where_clause {
135 const SUFFIX: [::core::primitive::u8; 16usize] = [ #( #view_function_id_suffix_bytes ),* ];
136 }
137
138 impl<#type_impl_gen> #frame_support::view_functions::ViewFunction for #view_function_struct_ident<#type_use_gen> #where_clause {
139 fn id() -> #frame_support::view_functions::ViewFunctionId {
140 #frame_support::view_functions::ViewFunctionId {
141 prefix: <#pallet_ident<#type_use_gen> as #frame_support::view_functions::ViewFunctionIdPrefix>::prefix(),
142 suffix: <Self as #frame_support::view_functions::ViewFunctionIdSuffix>::SUFFIX,
143 }
144 }
145
146 type ReturnType = #return_type;
147
148 fn invoke(self) -> Self::ReturnType {
149 let Self { #( #arg_names, )* _marker } = self;
150 #pallet_ident::<#type_use_gen> :: #view_fn_name( #( #arg_names, )* )
151 }
152 }
153 }
154}
155
156fn impl_dispatch_view_function(
157 def: &Def,
158 span: Span,
159 where_clause: Option<&syn::WhereClause>,
160 view_fns: &[ViewFunctionDef],
161) -> TokenStream {
162 let frame_support = &def.frame_support;
163 let pallet_ident = &def.pallet_struct.pallet;
164 let type_impl_gen = &def.type_impl_generics(span);
165 let type_use_gen = &def.type_use_generics(span);
166
167 let query_match_arms = view_fns.iter().map(|view_fn| {
168 let view_function_struct_ident = view_fn.view_function_struct_ident();
169 quote::quote! {
170 <#view_function_struct_ident<#type_use_gen> as #frame_support::view_functions::ViewFunctionIdSuffix>::SUFFIX => {
171 <#view_function_struct_ident<#type_use_gen> as #frame_support::view_functions::ViewFunction>::execute(input, output)
172 }
173 }
174 });
175
176 quote::quote! {
177 impl<#type_impl_gen> #frame_support::view_functions::DispatchViewFunction
178 for #pallet_ident<#type_use_gen> #where_clause
179 {
180 #[deny(unreachable_patterns)]
181 fn dispatch_view_function<O: #frame_support::__private::codec::Output>(
182 id: & #frame_support::view_functions::ViewFunctionId,
183 input: &mut &[u8],
184 output: &mut O
185 ) -> Result<(), #frame_support::view_functions::ViewFunctionDispatchError>
186 {
187 match id.suffix {
188 #( #query_match_arms )*
189 _ => Err(#frame_support::view_functions::ViewFunctionDispatchError::NotFound(id.clone())),
190 }
191 }
192 }
193 }
194}
195
196fn impl_view_function_metadata(
197 def: &Def,
198 span: Span,
199 where_clause: Option<&syn::WhereClause>,
200 view_fns: &[ViewFunctionDef],
201) -> TokenStream {
202 let frame_support = &def.frame_support;
203 let pallet_ident = &def.pallet_struct.pallet;
204 let type_impl_gen = &def.type_impl_generics(span);
205 let type_use_gen = &def.type_use_generics(span);
206
207 let view_functions = view_fns.iter().map(|view_fn| {
208 let view_function_struct_ident = view_fn.view_function_struct_ident();
209 let name = &view_fn.name;
210 let inputs = view_fn.args.iter().filter_map(|fn_arg| {
211 match fn_arg {
212 syn::FnArg::Receiver(_) => None,
213 syn::FnArg::Typed(typed) => {
214 let pat = &typed.pat;
215 let ty = &typed.ty;
216 Some(quote::quote! {
217 #frame_support::__private::metadata_ir::PalletViewFunctionParamMetadataIR {
218 name: ::core::stringify!(#pat),
219 ty: #frame_support::__private::scale_info::meta_type::<#ty>(),
220 }
221 })
222 }
223 }
224 });
225
226 let no_docs = vec![];
227 let doc = if cfg!(feature = "no-metadata-docs") { &no_docs } else { &view_fn.docs };
228
229 let deprecation = match crate::deprecation::get_deprecation(
230 "e::quote! { #frame_support },
231 &def.item.attrs,
232 ) {
233 Ok(deprecation) => deprecation,
234 Err(e) => return e.into_compile_error(),
235 };
236
237 quote::quote! {
238 #frame_support::__private::metadata_ir::PalletViewFunctionMetadataIR {
239 name: ::core::stringify!(#name),
240 id: <#view_function_struct_ident<#type_use_gen> as #frame_support::view_functions::ViewFunction>::id().into(),
241 inputs: #frame_support::__private::sp_std::vec![ #( #inputs ),* ],
242 output: #frame_support::__private::scale_info::meta_type::<
243 <#view_function_struct_ident<#type_use_gen> as #frame_support::view_functions::ViewFunction>::ReturnType
244 >(),
245 docs: #frame_support::__private::sp_std::vec![ #( #doc ),* ],
246 deprecation_info: #deprecation,
247 }
248 }
249 });
250
251 quote::quote! {
252 impl<#type_impl_gen> #pallet_ident<#type_use_gen> #where_clause {
253 #[doc(hidden)]
254 pub fn pallet_view_functions_metadata()
255 -> #frame_support::__private::Vec<#frame_support::__private::metadata_ir::PalletViewFunctionMetadataIR> {
256 #frame_support::__private::vec![ #( #view_functions ),* ]
257 }
258 }
259 }
260}