frame_support_procedural/pallet/parse/
view_functions.rs
1use frame_support_procedural_tools::get_doc_literals;
19use inflector::Inflector;
20use syn::spanned::Spanned;
21
22pub struct ViewFunctionsImplDef {
24 pub where_clause: Option<syn::WhereClause>,
26 pub attr_span: proc_macro2::Span,
28 pub view_functions: Vec<ViewFunctionDef>,
30}
31
32impl ViewFunctionsImplDef {
33 pub fn try_from(attr_span: proc_macro2::Span, item: &mut syn::Item) -> syn::Result<Self> {
34 let syn::Item::Impl(item_impl) = item else {
35 return Err(syn::Error::new(
36 item.span(),
37 "Invalid pallet::view_functions, expected item impl",
38 ))
39 };
40 let mut view_functions = Vec::new();
41 for item in &mut item_impl.items {
42 if let syn::ImplItem::Fn(method) = item {
43 if !matches!(method.vis, syn::Visibility::Public(_)) {
44 let msg = "Invalid pallet::view_functions, view function must be public: \
45 `pub fn`";
46
47 let span = match method.vis {
48 syn::Visibility::Inherited => method.sig.span(),
49 _ => method.vis.span(),
50 };
51
52 return Err(syn::Error::new(span, msg))
53 }
54
55 let view_fn_def = ViewFunctionDef::try_from(method.clone())?;
56 view_functions.push(view_fn_def)
57 } else {
58 return Err(syn::Error::new(
59 item.span(),
60 "Invalid pallet::view_functions, expected a function",
61 ))
62 }
63 }
64 Ok(Self {
65 view_functions,
66 attr_span,
67 where_clause: item_impl.generics.where_clause.clone(),
68 })
69 }
70}
71
72#[derive(Clone)]
74pub struct ViewFunctionDef {
75 pub name: syn::Ident,
76 pub docs: Vec<syn::Expr>,
77 pub args: Vec<syn::FnArg>,
78 pub return_type: syn::Type,
79}
80
81impl TryFrom<syn::ImplItemFn> for ViewFunctionDef {
82 type Error = syn::Error;
83 fn try_from(method: syn::ImplItemFn) -> Result<Self, Self::Error> {
84 let syn::ReturnType::Type(_, type_) = method.sig.output else {
85 return Err(syn::Error::new(method.sig.span(), "view functions must return a value"))
86 };
87
88 Ok(Self {
89 name: method.sig.ident.clone(),
90 docs: get_doc_literals(&method.attrs),
91 args: method.sig.inputs.iter().cloned().collect::<Vec<_>>(),
92 return_type: *type_.clone(),
93 })
94 }
95}
96
97impl ViewFunctionDef {
98 pub fn view_function_struct_ident(&self) -> syn::Ident {
99 syn::Ident::new(
100 &format!("{}ViewFunction", self.name.to_string().to_pascal_case()),
101 self.name.span(),
102 )
103 }
104
105 pub fn view_function_id_suffix_bytes(&self) -> Result<[u8; 16], syn::Error> {
106 let mut output = [0u8; 16];
107
108 let arg_types = self
110 .args_names_types()?
111 .1
112 .iter()
113 .map(|ty| quote::quote!(#ty).to_string().replace(" ", ""))
114 .collect::<Vec<_>>()
115 .join(",");
116 let return_type = &self.return_type;
117 let return_type = quote::quote!(#return_type).to_string().replace(" ", "");
118 let view_fn_signature = format!(
119 "{view_function_name}({arg_types}) -> {return_type}",
120 view_function_name = &self.name,
121 );
122
123 let hash = sp_crypto_hashing::twox_128(view_fn_signature.as_bytes());
125 output.copy_from_slice(&hash[..]);
126 Ok(output)
127 }
128
129 pub fn args_names_types(&self) -> Result<(Vec<syn::Ident>, Vec<syn::Type>), syn::Error> {
130 Ok(self
131 .args
132 .iter()
133 .map(|arg| {
134 let syn::FnArg::Typed(pat_type) = arg else {
135 return Err(syn::Error::new(
136 arg.span(),
137 "Unsupported argument in view function",
138 ));
139 };
140 let syn::Pat::Ident(ident) = &*pat_type.pat else {
141 return Err(syn::Error::new(
142 pat_type.pat.span(),
143 "Unsupported pattern in view function argument",
144 ));
145 };
146 Ok((ident.ident.clone(), *pat_type.ty.clone()))
147 })
148 .collect::<Result<Vec<(syn::Ident, syn::Type)>, syn::Error>>()?
149 .into_iter()
150 .unzip())
151 }
152}