referrerpolicy=no-referrer-when-downgrade

frame_support_procedural/pallet/expand/
view_functions.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 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			/// Create a new [`#view_function_struct_ident`] instance.
126			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			&quote::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}