sp_runtime_interface_proc_macro/runtime_interface/
trait_decl_impl.rs1use crate::utils::{
22 create_function_ident_with_version, generate_crate_access, get_function_argument_types,
23 get_runtime_interface,
24};
25
26use syn::{
27 fold::{self, Fold},
28 spanned::Spanned,
29 Error, Generics, ItemTrait, Receiver, Result, TraitItemFn, Type, Visibility,
30};
31
32use proc_macro2::TokenStream;
33
34use quote::quote;
35
36pub fn process(trait_def: &ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
39 let impl_trait = impl_trait_for_externalities(trait_def, is_wasm_only)?;
40 let essential_trait_def = declare_essential_trait(trait_def)?;
41
42 Ok(quote! {
43 #impl_trait
44
45 #essential_trait_def
46 })
47}
48
49struct ToEssentialTraitDef {
52 errors: Vec<Error>,
54 methods: Vec<TraitItemFn>,
55}
56
57impl ToEssentialTraitDef {
58 fn new() -> Self {
59 ToEssentialTraitDef { errors: vec![], methods: vec![] }
60 }
61
62 fn into_methods(self) -> Result<Vec<TraitItemFn>> {
63 let mut errors = self.errors;
64 let methods = self.methods;
65 if let Some(first_error) = errors.pop() {
66 Err(errors.into_iter().fold(first_error, |mut o, n| {
67 o.combine(n);
68 o
69 }))
70 } else {
71 Ok(methods)
72 }
73 }
74
75 fn process(&mut self, method: &TraitItemFn, version: u32) {
76 let mut folded = self.fold_trait_item_fn(method.clone());
77 folded.sig.ident = create_function_ident_with_version(&folded.sig.ident, version);
78 crate::utils::unpack_inner_types_in_signature(&mut folded.sig);
79 self.methods.push(folded);
80 }
81
82 fn push_error<S: Spanned>(&mut self, span: &S, msg: &str) {
83 self.errors.push(Error::new(span.span(), msg));
84 }
85
86 fn error_on_generic_parameters(&mut self, generics: &Generics) {
87 if let Some(param) = generics.params.first() {
88 self.push_error(param, "Generic parameters not supported.");
89 }
90 }
91}
92
93impl Fold for ToEssentialTraitDef {
94 fn fold_trait_item_fn(&mut self, mut method: TraitItemFn) -> TraitItemFn {
95 if method.default.take().is_none() {
96 self.push_error(&method, "Methods need to have an implementation.");
97 }
98
99 let arg_types = get_function_argument_types(&method.sig);
100 arg_types
101 .filter_map(|ty| match *ty {
102 Type::ImplTrait(impl_trait) => Some(impl_trait),
103 _ => None,
104 })
105 .for_each(|invalid| self.push_error(&invalid, "`impl Trait` syntax not supported."));
106
107 self.error_on_generic_parameters(&method.sig.generics);
108
109 method.attrs.retain(|a| !a.path().is_ident("version"));
110
111 fold::fold_trait_item_fn(self, method)
112 }
113
114 fn fold_item_trait(&mut self, mut trait_def: ItemTrait) -> ItemTrait {
115 self.error_on_generic_parameters(&trait_def.generics);
116
117 trait_def.vis = Visibility::Inherited;
118 fold::fold_item_trait(self, trait_def)
119 }
120
121 fn fold_receiver(&mut self, receiver: Receiver) -> Receiver {
122 if receiver.reference.is_none() {
123 self.push_error(&receiver, "Taking `Self` by value is not allowed.");
124 }
125
126 fold::fold_receiver(self, receiver)
127 }
128}
129
130fn declare_essential_trait(trait_def: &ItemTrait) -> Result<TokenStream> {
131 let trait_ = &trait_def.ident;
132
133 if let Some(param) = trait_def.generics.params.first() {
134 return Err(Error::new(param.span(), "Generic parameters not supported."))
135 }
136
137 let interface = get_runtime_interface(trait_def)?;
138 let mut folder = ToEssentialTraitDef::new();
139 for (version, interface_method) in interface.all_versions() {
140 folder.process(interface_method, version);
141 }
142 let methods = folder.into_methods()?;
143
144 Ok(quote! {
145 trait #trait_ {
146 #( #methods )*
147 }
148 })
149}
150
151fn impl_trait_for_externalities(trait_def: &ItemTrait, is_wasm_only: bool) -> Result<TokenStream> {
153 let trait_ = &trait_def.ident;
154 let crate_ = generate_crate_access();
155 let interface = get_runtime_interface(trait_def)?;
156 let methods = interface.all_versions().map(|(version, method)| {
157 let mut cloned = (*method).clone();
158 cloned.attrs.retain(|a| !a.path().is_ident("version"));
159 cloned.sig.ident = create_function_ident_with_version(&cloned.sig.ident, version);
160 crate::utils::unpack_inner_types_in_signature(&mut cloned.sig);
161 cloned
162 });
163
164 let impl_type = if is_wasm_only {
165 quote!( &mut dyn #crate_::sp_wasm_interface::FunctionContext )
166 } else {
167 quote!( &mut dyn #crate_::Externalities )
168 };
169
170 Ok(quote! {
171 #[cfg(not(substrate_runtime))]
172 impl #trait_ for #impl_type {
173 #( #methods )*
174 }
175 })
176}