1use crate::utils::{
19 extract_api_version, extract_block_type_from_trait_path, extract_impl_trait,
20 extract_parameter_names_types_and_borrows, generate_crate_access,
21 generate_runtime_mod_name_for_trait, prefix_function_with_trait, versioned_trait_name,
22 AllowSelfRefInParameters, ApiVersion, RequireQualifiedTraitPath,
23};
24
25use proc_macro2::{Span, TokenStream};
26
27use quote::quote;
28
29use syn::{
30 fold::{self, Fold},
31 parse::{Error, Parse, ParseStream, Result},
32 parse_macro_input, parse_quote,
33 spanned::Spanned,
34 visit_mut::{self, VisitMut},
35 Attribute, Ident, ImplItem, ItemImpl, Path, Signature, Type, TypePath,
36};
37
38use std::collections::HashMap;
39
40struct RuntimeApiImpls {
42 impls: Vec<ItemImpl>,
43}
44
45impl Parse for RuntimeApiImpls {
46 fn parse(input: ParseStream) -> Result<Self> {
47 let mut impls = Vec::new();
48
49 while !input.is_empty() {
50 impls.push(ItemImpl::parse(input)?);
51 }
52
53 if impls.is_empty() {
54 Err(Error::new(Span::call_site(), "No api implementation given!"))
55 } else {
56 Ok(Self { impls })
57 }
58 }
59}
60
61fn generate_impl_call(
64 signature: &Signature,
65 runtime: &Type,
66 input: &Ident,
67 impl_trait: &Path,
68 api_version: &ApiVersion,
69) -> Result<TokenStream> {
70 let params =
71 extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
72
73 let c = generate_crate_access();
74 let fn_name = &signature.ident;
75 let fn_name_str = fn_name.to_string();
76 let pnames = params.iter().map(|v| &v.0);
77 let pnames2 = params.iter().map(|v| &v.0);
78 let ptypes = params.iter().map(|v| &v.1);
79 let pborrow = params.iter().map(|v| &v.2);
80
81 let decode_params = if params.is_empty() {
82 quote!(
83 if !#input.is_empty() {
84 panic!(
85 "Bad input data provided to {}: expected no parameters, but input buffer is not empty. Nothing bad happened: someone sent an invalid transaction to the node.",
86 #fn_name_str
87 );
88 }
89 )
90 } else {
91 let let_binding = if params.len() == 1 {
92 quote! {
93 let #( #pnames )* : #( #ptypes )*
94 }
95 } else {
96 quote! {
97 let ( #( #pnames ),* ) : ( #( #ptypes ),* )
98 }
99 };
100
101 quote!(
102 #let_binding =
103 match #c::Decode::decode(
104 &mut #input,
105 ) {
106 Ok(res) => res,
107 Err(e) => panic!("Bad input data provided to {}: {}. Nothing bad happened: someone sent an invalid transaction to the node.", #fn_name_str, e),
108 };
109 )
110 };
111
112 let fn_calls = if let Some(feature_gated) = &api_version.feature_gated {
113 let pnames = pnames2;
114 let pnames2 = pnames.clone();
115 let pborrow2 = pborrow.clone();
116
117 let feature_name = &feature_gated.0;
118 let impl_trait_fg = extend_with_api_version(impl_trait.clone(), Some(feature_gated.1));
119 let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
120
121 quote!(
122 #[cfg(feature = #feature_name)]
123 #[allow(deprecated)]
124 let r = <#runtime as #impl_trait_fg>::#fn_name(#( #pborrow #pnames ),*);
125
126 #[cfg(not(feature = #feature_name))]
127 #[allow(deprecated)]
128 let r = <#runtime as #impl_trait>::#fn_name(#( #pborrow2 #pnames2 ),*);
129
130 r
131 )
132 } else {
133 let pnames = pnames2;
134 let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
135
136 quote!(
137 #[allow(deprecated)]
138 <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames ),*)
139 )
140 };
141
142 Ok(quote!(
143 #decode_params
144
145 #fn_calls
146 ))
147}
148
149fn generate_impl_calls(
151 impls: &[ItemImpl],
152 input: &Ident,
153) -> Result<Vec<(Ident, Ident, TokenStream, Vec<Attribute>)>> {
154 let mut impl_calls = Vec::new();
155
156 for impl_ in impls {
157 let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
158 let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
159 let impl_trait = extend_with_runtime_decl_path(impl_trait_path.clone());
160 let impl_trait_ident = &impl_trait_path
161 .segments
162 .last()
163 .ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))?
164 .ident;
165
166 for item in &impl_.items {
167 if let ImplItem::Fn(method) = item {
168 let impl_call = generate_impl_call(
169 &method.sig,
170 &impl_.self_ty,
171 input,
172 &impl_trait,
173 &trait_api_ver,
174 )?;
175 let mut attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
176
177 attrs.extend(filter_cfg_and_allow_attrs(&method.attrs));
179
180 impl_calls.push((
181 impl_trait_ident.clone(),
182 method.sig.ident.clone(),
183 impl_call,
184 attrs,
185 ));
186 }
187 }
188 }
189
190 Ok(impl_calls)
191}
192
193fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
195 let data = Ident::new("_sp_api_input_data_", Span::call_site());
196 let c = generate_crate_access();
197 let impl_calls =
198 generate_impl_calls(impls, &data)?
199 .into_iter()
200 .map(|(trait_, fn_name, impl_, attrs)| {
201 let name = prefix_function_with_trait(&trait_, &fn_name);
202 quote!(
203 #( #attrs )*
204 #name => Some(#c::Encode::encode(&{ #impl_ })),
205 )
206 });
207
208 Ok(quote!(
209 #c::std_enabled! {
210 pub fn dispatch(method: &str, mut #data: &[u8]) -> Option<Vec<u8>> {
211 match method {
212 #( #impl_calls )*
213 _ => None,
214 }
215 }
216 }
217 ))
218}
219
220fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
222 let input = Ident::new("input", Span::call_site());
223 let c = generate_crate_access();
224
225 let impl_calls =
226 generate_impl_calls(impls, &input)?
227 .into_iter()
228 .map(|(trait_, fn_name, impl_, attrs)| {
229 let fn_name =
230 Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site());
231
232 quote!(
233 #c::std_disabled! {
234 #( #attrs )*
235 #[no_mangle]
236 #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #c::__private::polkavm_export(abi = #c::__private::polkavm_abi))]
237 pub unsafe extern fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
238 let mut #input = if input_len == 0 {
239 &[0u8; 0]
240 } else {
241 unsafe {
242 ::core::slice::from_raw_parts(input_data, input_len)
243 }
244 };
245
246 #c::init_runtime_logger();
247
248 let output = (move || { #impl_ })();
249 #c::to_substrate_wasm_fn_return_value(&output)
250 }
251 }
252 )
253 });
254
255 Ok(quote!( #( #impl_calls )* ))
256}
257
258fn generate_runtime_api_base_structures() -> Result<TokenStream> {
259 let crate_ = generate_crate_access();
260
261 Ok(quote!(
262 pub struct RuntimeApi {}
263 #crate_::std_enabled! {
264 pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
266 call: &'static C,
267 transaction_depth: std::cell::RefCell<u16>,
268 changes: std::cell::RefCell<#crate_::OverlayedChanges<#crate_::HashingFor<Block>>>,
269 recorder: std::option::Option<#crate_::ProofRecorder<Block>>,
270 call_context: #crate_::CallContext,
271 extensions: std::cell::RefCell<#crate_::Extensions>,
272 extensions_generated_for: std::cell::RefCell<std::option::Option<Block::Hash>>,
273 }
274
275 #[automatically_derived]
276 impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> #crate_::ApiExt<Block> for
277 RuntimeApiImpl<Block, C>
278 {
279 fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
280 &self,
281 call: F,
282 ) -> R where Self: Sized {
283 self.start_transaction();
284
285 *std::cell::RefCell::borrow_mut(&self.transaction_depth) += 1;
286 let res = call(self);
287 std::cell::RefCell::borrow_mut(&self.transaction_depth)
288 .checked_sub(1)
289 .expect("Transactions are opened and closed together; qed");
290
291 self.commit_or_rollback_transaction(
292 std::matches!(res, #crate_::TransactionOutcome::Commit(_))
293 );
294
295 res.into_inner()
296 }
297
298 fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
299 &self,
300 at: <Block as #crate_::BlockT>::Hash,
301 ) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
302 #crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
303 .map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION))
304 }
305
306 fn has_api_with<A: #crate_::RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
307 &self,
308 at: <Block as #crate_::BlockT>::Hash,
309 pred: P,
310 ) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
311 #crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
312 .map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, pred))
313 }
314
315 fn api_version<A: #crate_::RuntimeApiInfo + ?Sized>(
316 &self,
317 at: <Block as #crate_::BlockT>::Hash,
318 ) -> std::result::Result<Option<u32>, #crate_::ApiError> where Self: Sized {
319 #crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
320 .map(|v| #crate_::RuntimeVersion::api_version(&v, &A::ID))
321 }
322
323 fn record_proof(&mut self) {
324 self.recorder = std::option::Option::Some(std::default::Default::default());
325 }
326
327 fn proof_recorder(&self) -> std::option::Option<#crate_::ProofRecorder<Block>> {
328 std::clone::Clone::clone(&self.recorder)
329 }
330
331 fn extract_proof(
332 &mut self,
333 ) -> std::option::Option<#crate_::StorageProof> {
334 let recorder = std::option::Option::take(&mut self.recorder);
335 std::option::Option::map(recorder, |recorder| {
336 #crate_::ProofRecorder::<Block>::drain_storage_proof(recorder)
337 })
338 }
339
340 fn into_storage_changes<B: #crate_::StateBackend<#crate_::HashingFor<Block>>>(
341 &self,
342 backend: &B,
343 parent_hash: Block::Hash,
344 ) -> ::core::result::Result<
345 #crate_::StorageChanges<Block>,
346 String
347 > where Self: Sized {
348 let state_version = #crate_::CallApiAt::<Block>::runtime_version_at(self.call, std::clone::Clone::clone(&parent_hash))
349 .map(|v| #crate_::RuntimeVersion::state_version(&v))
350 .map_err(|e| format!("Failed to get state version: {}", e))?;
351
352 #crate_::OverlayedChanges::drain_storage_changes(
353 &mut std::cell::RefCell::borrow_mut(&self.changes),
354 backend,
355 state_version,
356 )
357 }
358
359 fn set_call_context(&mut self, call_context: #crate_::CallContext) {
360 self.call_context = call_context;
361 }
362
363 fn register_extension<E: #crate_::Extension>(&mut self, extension: E) {
364 std::cell::RefCell::borrow_mut(&self.extensions).register(extension);
365 }
366 }
367
368 #[automatically_derived]
369 impl<Block: #crate_::BlockT, C> #crate_::ConstructRuntimeApi<Block, C>
370 for RuntimeApi
371 where
372 C: #crate_::CallApiAt<Block> + 'static,
373 {
374 type RuntimeApi = RuntimeApiImpl<Block, C>;
375
376 fn construct_runtime_api<'a>(
377 call: &'a C,
378 ) -> #crate_::ApiRef<'a, Self::RuntimeApi> {
379 RuntimeApiImpl {
380 call: unsafe { std::mem::transmute(call) },
381 transaction_depth: 0.into(),
382 changes: std::default::Default::default(),
383 recorder: std::default::Default::default(),
384 call_context: #crate_::CallContext::Offchain,
385 extensions: std::default::Default::default(),
386 extensions_generated_for: std::default::Default::default(),
387 }.into()
388 }
389 }
390
391 #[automatically_derived]
392 impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> RuntimeApiImpl<Block, C> {
393 fn commit_or_rollback_transaction(&self, commit: bool) {
394 let proof = "\
395 We only close a transaction when we opened one ourself.
396 Other parts of the runtime that make use of transactions (state-machine)
397 also balance their transactions. The runtime cannot close client initiated
398 transactions; qed";
399
400 let res = if commit {
401 let res = if let Some(recorder) = &self.recorder {
402 #crate_::ProofRecorder::<Block>::commit_transaction(&recorder)
403 } else {
404 Ok(())
405 };
406
407 let res2 = #crate_::OverlayedChanges::commit_transaction(
408 &mut std::cell::RefCell::borrow_mut(&self.changes)
409 );
410
411 std::result::Result::and(res, std::result::Result::map_err(res2, drop))
414 } else {
415 let res = if let Some(recorder) = &self.recorder {
416 #crate_::ProofRecorder::<Block>::rollback_transaction(&recorder)
417 } else {
418 Ok(())
419 };
420
421 let res2 = #crate_::OverlayedChanges::rollback_transaction(
422 &mut std::cell::RefCell::borrow_mut(&self.changes)
423 );
424
425 std::result::Result::and(res, std::result::Result::map_err(res2, drop))
428 };
429
430 std::result::Result::expect(res, proof);
431 }
432
433 fn start_transaction(&self) {
434 #crate_::OverlayedChanges::start_transaction(
435 &mut std::cell::RefCell::borrow_mut(&self.changes)
436 );
437 if let Some(recorder) = &self.recorder {
438 #crate_::ProofRecorder::<Block>::start_transaction(&recorder);
439 }
440 }
441 }
442 }
443 ))
444}
445
446fn extend_with_runtime_decl_path(mut trait_: Path) -> Path {
449 let runtime = {
450 let trait_name = &trait_
451 .segments
452 .last()
453 .as_ref()
454 .expect("Trait path should always contain at least one item; qed")
455 .ident;
456
457 generate_runtime_mod_name_for_trait(trait_name)
458 };
459
460 let pos = trait_.segments.len() - 1;
461 trait_.segments.insert(pos, runtime.into());
462 trait_
463}
464
465fn extend_with_api_version(mut trait_: Path, version: Option<u32>) -> Path {
466 let version = if let Some(v) = version {
467 v
468 } else {
469 return trait_;
471 };
472
473 let trait_name = &mut trait_
474 .segments
475 .last_mut()
476 .expect("Trait path should always contain at least one item; qed")
477 .ident;
478 *trait_name = versioned_trait_name(trait_name, version);
479
480 trait_
481}
482
483fn add_feature_guard(attrs: &mut Vec<Attribute>, feature_name: &str, enable: bool) {
488 let attr = match enable {
489 true => parse_quote!(#[cfg(feature = #feature_name)]),
490 false => parse_quote!(#[cfg(not(feature = #feature_name))]),
491 };
492 attrs.push(attr);
493}
494
495fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result<TokenStream> {
497 let mut impls_prepared = Vec::new();
498
499 for impl_ in impls.iter() {
502 let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
503
504 let mut impl_ = impl_.clone();
505 impl_.attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
506
507 let trait_ = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone();
508 let trait_ = extend_with_runtime_decl_path(trait_);
509 if let Some(feature_gated) = trait_api_ver.feature_gated {
513 let mut feature_gated_impl = impl_.clone();
514 add_feature_guard(&mut feature_gated_impl.attrs, &feature_gated.0, true);
515 feature_gated_impl.trait_.as_mut().unwrap().1 =
516 extend_with_api_version(trait_.clone(), Some(feature_gated.1));
517
518 impls_prepared.push(feature_gated_impl);
519
520 add_feature_guard(&mut impl_.attrs, &feature_gated.0, false);
523 }
524
525 let trait_ = extend_with_api_version(trait_, trait_api_ver.custom);
527 impl_.trait_.as_mut().unwrap().1 = trait_;
528 impls_prepared.push(impl_);
529 }
530
531 Ok(quote!( #( #impls_prepared )* ))
532}
533
534struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
540 runtime_block: &'a TypePath,
541}
542
543impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> {
544 fn process(mut self, input: ItemImpl) -> ItemImpl {
546 let mut input = self.fold_item_impl(input);
547
548 let crate_ = generate_crate_access();
549
550 input.items.clear();
554 input.items.push(parse_quote! {
555 fn __runtime_api_internal_call_api_at(
556 &self,
557 at: <__SrApiBlock__ as #crate_::BlockT>::Hash,
558 params: std::vec::Vec<u8>,
559 fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
560 ) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError> {
561 let transaction_depth = *std::cell::RefCell::borrow(&self.transaction_depth);
564
565 if transaction_depth == 0 {
566 self.start_transaction();
567 }
568
569 let res = (|| {
570 let version = #crate_::CallApiAt::<__SrApiBlock__>::runtime_version_at(
571 self.call,
572 at,
573 )?;
574
575 match &mut *std::cell::RefCell::borrow_mut(&self.extensions_generated_for) {
576 Some(generated_for) => {
577 if *generated_for != at {
578 return std::result::Result::Err(
579 #crate_::ApiError::UsingSameInstanceForDifferentBlocks
580 )
581 }
582 },
583 generated_for @ None => {
584 #crate_::CallApiAt::<__SrApiBlock__>::initialize_extensions(
585 self.call,
586 at,
587 &mut std::cell::RefCell::borrow_mut(&self.extensions),
588 )?;
589
590 *generated_for = Some(at);
591 }
592 }
593
594 let params = #crate_::CallApiAtParams {
595 at,
596 function: (*fn_name)(version),
597 arguments: params,
598 overlayed_changes: &self.changes,
599 call_context: self.call_context,
600 recorder: &self.recorder,
601 extensions: &self.extensions,
602 };
603
604 #crate_::CallApiAt::<__SrApiBlock__>::call_api_at(
605 self.call,
606 params,
607 )
608 })();
609
610 if transaction_depth == 0 {
611 self.commit_or_rollback_transaction(std::result::Result::is_ok(&res));
612 }
613
614 res
615 }
616 });
617
618 input
619 }
620}
621
622impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
623 fn fold_type_path(&mut self, input: TypePath) -> TypePath {
624 let new_ty_path =
625 if input == *self.runtime_block { parse_quote!(__SrApiBlock__) } else { input };
626
627 fold::fold_type_path(self, new_ty_path)
628 }
629
630 fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl {
631 let crate_ = generate_crate_access();
632
633 input.self_ty =
635 Box::new(parse_quote!( RuntimeApiImpl<__SrApiBlock__, RuntimeApiImplCall> ));
636
637 input.generics.params.push(parse_quote!(
638 __SrApiBlock__: #crate_::BlockT
639 ));
640
641 input
642 .generics
643 .params
644 .push(parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SrApiBlock__> + 'static ));
645
646 let where_clause = input.generics.make_where_clause();
647
648 where_clause.predicates.push(parse_quote! {
649 RuntimeApiImplCall::StateBackend:
650 #crate_::StateBackend<#crate_::HashingFor<__SrApiBlock__>>
651 });
652
653 where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send });
654
655 input.attrs = filter_cfg_and_allow_attrs(&input.attrs);
656
657 fold::fold_item_impl(self, input)
658 }
659}
660
661fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result<TokenStream> {
663 let mut result = Vec::with_capacity(impls.len());
664
665 for impl_ in impls {
666 let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
667 let runtime_block = extract_block_type_from_trait_path(impl_trait_path)?;
668 let mut runtime_mod_path = extend_with_runtime_decl_path(impl_trait_path.clone());
669 runtime_mod_path.segments.pop();
671
672 let mut processed_impl =
673 ApiRuntimeImplToApiRuntimeApiImpl { runtime_block }.process(impl_.clone());
674
675 processed_impl.attrs.push(parse_quote!(#[automatically_derived]));
676
677 result.push(processed_impl);
678 }
679
680 let crate_ = generate_crate_access();
681
682 Ok(quote!( #crate_::std_enabled! { #( #result )* } ))
683}
684
685fn populate_runtime_api_versions(
686 result: &mut Vec<TokenStream>,
687 sections: &mut Vec<TokenStream>,
688 attrs: Vec<Attribute>,
689 id: Path,
690 version: TokenStream,
691 crate_access: &TokenStream,
692) {
693 result.push(quote!(
694 #( #attrs )*
695 (#id, #version)
696 ));
697
698 sections.push(quote!(
699 #crate_access::std_disabled! {
700 #( #attrs )*
701 const _: () = {
702 #[link_section = "runtime_apis"]
704 static SECTION_CONTENTS: [u8; 12] = #crate_access::serialize_runtime_api_info(#id, #version);
705 };
706 }
707 ));
708}
709
710fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
713 let mut result = Vec::<TokenStream>::with_capacity(impls.len());
714 let mut sections = Vec::<TokenStream>::with_capacity(impls.len());
715 let mut processed_traits = HashMap::new();
716
717 let c = generate_crate_access();
718
719 for impl_ in impls {
720 let versions = extract_api_version(&impl_.attrs, impl_.span())?;
721 let api_ver = versions.custom.map(|a| a as u32);
722
723 let mut path = extend_with_runtime_decl_path(
724 extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?.clone(),
725 );
726 let trait_ = path
728 .segments
729 .pop()
730 .expect("extract_impl_trait already checks that this is valid; qed")
731 .into_value()
732 .ident;
733
734 let span = trait_.span();
735 if let Some(other_span) = processed_traits.insert(trait_, span) {
736 let mut error = Error::new(
737 span,
738 "Two traits with the same name detected! \
739 The trait name is used to generate its ID. \
740 Please rename one trait at the declaration!",
741 );
742
743 error.combine(Error::new(other_span, "First trait implementation."));
744
745 return Err(error);
746 }
747
748 let id: Path = parse_quote!( #path ID );
749 let mut attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
750
751 if let Some(feature_gated) = versions.feature_gated {
754 let feature_gated_version = feature_gated.1 as u32;
755 let mut feature_gated_attrs = attrs.clone();
757 add_feature_guard(&mut feature_gated_attrs, &feature_gated.0, true);
758 populate_runtime_api_versions(
759 &mut result,
760 &mut sections,
761 feature_gated_attrs,
762 id.clone(),
763 quote!( #feature_gated_version ),
764 &c,
765 );
766
767 add_feature_guard(&mut attrs, &feature_gated.0, false);
770 }
771
772 let base_api_version = quote!( #path VERSION );
775 let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| base_api_version);
776 populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c);
777 }
778
779 Ok(quote!(
780 pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]);
781
782 #( #sections )*
783 ))
784}
785
786struct ReplaceSelfImpl {
788 self_ty: Box<Type>,
789}
790
791impl ReplaceSelfImpl {
792 fn replace(&mut self, trait_: &mut ItemImpl) {
794 visit_mut::visit_item_impl_mut(self, trait_)
795 }
796}
797
798impl VisitMut for ReplaceSelfImpl {
799 fn visit_type_mut(&mut self, ty: &mut syn::Type) {
800 match ty {
801 Type::Path(p) if p.path.is_ident("Self") => {
802 *ty = *self.self_ty.clone();
803 },
804 ty => syn::visit_mut::visit_type_mut(self, ty),
805 }
806 }
807}
808
809fn rename_self_in_trait_impls(impls: &mut [ItemImpl]) {
811 impls.iter_mut().for_each(|i| {
812 let mut checker = ReplaceSelfImpl { self_ty: i.self_ty.clone() };
813 checker.replace(i);
814 });
815}
816
817pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
819 let RuntimeApiImpls { impls: mut api_impls } = parse_macro_input!(input as RuntimeApiImpls);
821
822 impl_runtime_apis_impl_inner(&mut api_impls)
823 .unwrap_or_else(|e| e.to_compile_error())
824 .into()
825}
826
827fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result<TokenStream> {
828 rename_self_in_trait_impls(api_impls);
829
830 let dispatch_impl = generate_dispatch_function(api_impls)?;
831 let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?;
832 let base_runtime_api = generate_runtime_api_base_structures()?;
833 let runtime_api_versions = generate_runtime_api_versions(api_impls)?;
834 let wasm_interface = generate_wasm_interface(api_impls)?;
835 let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
836
837 let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?;
838
839 let impl_ = quote!(
840 #base_runtime_api
841
842 #api_impls_for_runtime
843
844 #api_impls_for_runtime_api
845
846 #runtime_api_versions
847
848 #runtime_metadata
849
850 pub mod api {
851 use super::*;
852
853 #dispatch_impl
854
855 #wasm_interface
856 }
857 );
858
859 let impl_ = expander::Expander::new("impl_runtime_apis")
860 .dry(std::env::var("EXPAND_MACROS").is_err())
861 .verbose(true)
862 .write_to_out_dir(impl_)
863 .expect("Does not fail because of IO in OUT_DIR; qed");
864
865 Ok(impl_)
866}
867
868fn filter_cfg_and_allow_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
870 attrs
871 .iter()
872 .filter(|a| a.path().is_ident("cfg") || a.path().is_ident("allow"))
873 .cloned()
874 .collect()
875}
876
877#[cfg(test)]
878mod tests {
879 use super::*;
880
881 #[test]
882 fn filter_non_cfg_attributes() {
883 let cfg_std: Attribute = parse_quote!(#[cfg(feature = "std")]);
884 let cfg_benchmarks: Attribute = parse_quote!(#[cfg(feature = "runtime-benchmarks")]);
885 let allow: Attribute = parse_quote!(#[allow(non_camel_case_types)]);
886
887 let attrs = vec![
888 cfg_std.clone(),
889 parse_quote!(#[derive(Debug)]),
890 parse_quote!(#[test]),
891 cfg_benchmarks.clone(),
892 parse_quote!(#[allow(non_camel_case_types)]),
893 ];
894
895 let filtered = filter_cfg_and_allow_attrs(&attrs);
896 assert_eq!(filtered.len(), 3);
897 assert_eq!(cfg_std, filtered[0]);
898 assert_eq!(cfg_benchmarks, filtered[1]);
899 assert_eq!(allow, filtered[2]);
900 }
901
902 #[test]
903 fn impl_trait_rename_self_param() {
904 let code = quote::quote! {
905 impl client::Core<Block> for Runtime {
906 fn initialize_block(header: &HeaderFor<Self>) -> Output<Self> {
907 let _: HeaderFor<Self> = header.clone();
908 example_fn::<Self>(header)
909 }
910 }
911 };
912 let expected = quote::quote! {
913 impl client::Core<Block> for Runtime {
914 fn initialize_block(header: &HeaderFor<Runtime>) -> Output<Runtime> {
915 let _: HeaderFor<Runtime> = header.clone();
916 example_fn::<Runtime>(header)
917 }
918 }
919 };
920
921 let RuntimeApiImpls { impls: mut api_impls } =
923 syn::parse2::<RuntimeApiImpls>(code).unwrap();
924
925 rename_self_in_trait_impls(&mut api_impls);
927 let result: TokenStream = quote::quote! { #(#api_impls)* };
928
929 assert_eq!(result.to_string(), expected.to_string());
930 }
931}