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 record_proof_with_recorder(&mut self, recorder: #crate_::ProofRecorder<Block>) {
328 self.recorder = std::option::Option::Some(recorder);
329 }
330
331 fn proof_recorder(&self) -> std::option::Option<#crate_::ProofRecorder<Block>> {
332 std::clone::Clone::clone(&self.recorder)
333 }
334
335 fn extract_proof(
336 &mut self,
337 ) -> std::option::Option<#crate_::StorageProof> {
338 let recorder = std::option::Option::take(&mut self.recorder);
339 std::option::Option::map(recorder, |recorder| {
340 #crate_::ProofRecorder::<Block>::drain_storage_proof(recorder)
341 })
342 }
343
344 fn into_storage_changes<B: #crate_::StateBackend<#crate_::HashingFor<Block>>>(
345 &self,
346 backend: &B,
347 parent_hash: Block::Hash,
348 ) -> ::core::result::Result<
349 #crate_::StorageChanges<Block>,
350 String
351 > where Self: Sized {
352 let state_version = #crate_::CallApiAt::<Block>::runtime_version_at(self.call, std::clone::Clone::clone(&parent_hash))
353 .map(|v| #crate_::RuntimeVersion::state_version(&v))
354 .map_err(|e| format!("Failed to get state version: {}", e))?;
355
356 #crate_::OverlayedChanges::drain_storage_changes(
357 &mut std::cell::RefCell::borrow_mut(&self.changes),
358 backend,
359 state_version,
360 )
361 }
362
363 fn set_call_context(&mut self, call_context: #crate_::CallContext) {
364 self.call_context = call_context;
365 }
366
367 fn register_extension<E: #crate_::Extension>(&mut self, extension: E) {
368 std::cell::RefCell::borrow_mut(&self.extensions).register(extension);
369 }
370 }
371
372 #[automatically_derived]
373 impl<Block: #crate_::BlockT, C> #crate_::ConstructRuntimeApi<Block, C>
374 for RuntimeApi
375 where
376 C: #crate_::CallApiAt<Block> + 'static,
377 {
378 type RuntimeApi = RuntimeApiImpl<Block, C>;
379
380 fn construct_runtime_api<'a>(
381 call: &'a C,
382 ) -> #crate_::ApiRef<'a, Self::RuntimeApi> {
383 RuntimeApiImpl {
384 call: unsafe { std::mem::transmute(call) },
385 transaction_depth: 0.into(),
386 changes: std::default::Default::default(),
387 recorder: std::default::Default::default(),
388 call_context: #crate_::CallContext::Offchain,
389 extensions: std::default::Default::default(),
390 extensions_generated_for: std::default::Default::default(),
391 }.into()
392 }
393 }
394
395 #[automatically_derived]
396 impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> RuntimeApiImpl<Block, C> {
397 fn commit_or_rollback_transaction(&self, commit: bool) {
398 let proof = "\
399 We only close a transaction when we opened one ourself.
400 Other parts of the runtime that make use of transactions (state-machine)
401 also balance their transactions. The runtime cannot close client initiated
402 transactions; qed";
403
404 let res = if commit {
405 let res = if let Some(recorder) = &self.recorder {
406 #crate_::ProofRecorder::<Block>::commit_transaction(&recorder)
407 } else {
408 Ok(())
409 };
410
411 let res2 = #crate_::OverlayedChanges::commit_transaction(
412 &mut std::cell::RefCell::borrow_mut(&self.changes)
413 );
414
415 std::result::Result::and(res, std::result::Result::map_err(res2, drop))
418 } else {
419 let res = if let Some(recorder) = &self.recorder {
420 #crate_::ProofRecorder::<Block>::rollback_transaction(&recorder)
421 } else {
422 Ok(())
423 };
424
425 let res2 = #crate_::OverlayedChanges::rollback_transaction(
426 &mut std::cell::RefCell::borrow_mut(&self.changes)
427 );
428
429 std::result::Result::and(res, std::result::Result::map_err(res2, drop))
432 };
433
434 std::result::Result::expect(res, proof);
435 }
436
437 fn start_transaction(&self) {
438 #crate_::OverlayedChanges::start_transaction(
439 &mut std::cell::RefCell::borrow_mut(&self.changes)
440 );
441 if let Some(recorder) = &self.recorder {
442 #crate_::ProofRecorder::<Block>::start_transaction(&recorder);
443 }
444 }
445 }
446 }
447 ))
448}
449
450fn extend_with_runtime_decl_path(mut trait_: Path) -> Path {
453 let runtime = {
454 let trait_name = &trait_
455 .segments
456 .last()
457 .as_ref()
458 .expect("Trait path should always contain at least one item; qed")
459 .ident;
460
461 generate_runtime_mod_name_for_trait(trait_name)
462 };
463
464 let pos = trait_.segments.len() - 1;
465 trait_.segments.insert(pos, runtime.into());
466 trait_
467}
468
469fn extend_with_api_version(mut trait_: Path, version: Option<u32>) -> Path {
470 let version = if let Some(v) = version {
471 v
472 } else {
473 return trait_;
475 };
476
477 let trait_name = &mut trait_
478 .segments
479 .last_mut()
480 .expect("Trait path should always contain at least one item; qed")
481 .ident;
482 *trait_name = versioned_trait_name(trait_name, version);
483
484 trait_
485}
486
487fn add_feature_guard(attrs: &mut Vec<Attribute>, feature_name: &str, enable: bool) {
492 let attr = match enable {
493 true => parse_quote!(#[cfg(feature = #feature_name)]),
494 false => parse_quote!(#[cfg(not(feature = #feature_name))]),
495 };
496 attrs.push(attr);
497}
498
499fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result<TokenStream> {
501 let mut impls_prepared = Vec::new();
502
503 for impl_ in impls.iter() {
506 let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
507
508 let mut impl_ = impl_.clone();
509 impl_.attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
510
511 let trait_ = extract_impl_trait(&impl_, RequireQualifiedTraitPath::Yes)?.clone();
512 let trait_ = extend_with_runtime_decl_path(trait_);
513 if let Some(feature_gated) = trait_api_ver.feature_gated {
517 let mut feature_gated_impl = impl_.clone();
518 add_feature_guard(&mut feature_gated_impl.attrs, &feature_gated.0, true);
519 feature_gated_impl.trait_.as_mut().unwrap().1 =
520 extend_with_api_version(trait_.clone(), Some(feature_gated.1));
521
522 impls_prepared.push(feature_gated_impl);
523
524 add_feature_guard(&mut impl_.attrs, &feature_gated.0, false);
527 }
528
529 let trait_ = extend_with_api_version(trait_, trait_api_ver.custom);
531 impl_.trait_.as_mut().unwrap().1 = trait_;
532 impls_prepared.push(impl_);
533 }
534
535 Ok(quote!( #( #impls_prepared )* ))
536}
537
538struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
544 runtime_block: &'a TypePath,
545}
546
547impl<'a> ApiRuntimeImplToApiRuntimeApiImpl<'a> {
548 fn process(mut self, input: ItemImpl) -> ItemImpl {
550 let mut input = self.fold_item_impl(input);
551
552 let crate_ = generate_crate_access();
553
554 input.items.clear();
558 input.items.push(parse_quote! {
559 fn __runtime_api_internal_call_api_at(
560 &self,
561 at: <__SrApiBlock__ as #crate_::BlockT>::Hash,
562 params: std::vec::Vec<u8>,
563 fn_name: &dyn Fn(#crate_::RuntimeVersion) -> &'static str,
564 ) -> std::result::Result<std::vec::Vec<u8>, #crate_::ApiError> {
565 let transaction_depth = *std::cell::RefCell::borrow(&self.transaction_depth);
568
569 if transaction_depth == 0 {
570 self.start_transaction();
571 }
572
573 let res = (|| {
574 let version = #crate_::CallApiAt::<__SrApiBlock__>::runtime_version_at(
575 self.call,
576 at,
577 )?;
578
579 match &mut *std::cell::RefCell::borrow_mut(&self.extensions_generated_for) {
580 Some(generated_for) => {
581 if *generated_for != at {
582 return std::result::Result::Err(
583 #crate_::ApiError::UsingSameInstanceForDifferentBlocks
584 )
585 }
586 },
587 generated_for @ None => {
588 #crate_::CallApiAt::<__SrApiBlock__>::initialize_extensions(
589 self.call,
590 at,
591 &mut std::cell::RefCell::borrow_mut(&self.extensions),
592 )?;
593
594 *generated_for = Some(at);
595 }
596 }
597
598 let params = #crate_::CallApiAtParams {
599 at,
600 function: (*fn_name)(version),
601 arguments: params,
602 overlayed_changes: &self.changes,
603 call_context: self.call_context,
604 recorder: &self.recorder,
605 extensions: &self.extensions,
606 };
607
608 #crate_::CallApiAt::<__SrApiBlock__>::call_api_at(
609 self.call,
610 params,
611 )
612 })();
613
614 if transaction_depth == 0 {
615 self.commit_or_rollback_transaction(std::result::Result::is_ok(&res));
616 }
617
618 res
619 }
620 });
621
622 input
623 }
624}
625
626impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
627 fn fold_type_path(&mut self, input: TypePath) -> TypePath {
628 let new_ty_path =
629 if input == *self.runtime_block { parse_quote!(__SrApiBlock__) } else { input };
630
631 fold::fold_type_path(self, new_ty_path)
632 }
633
634 fn fold_item_impl(&mut self, mut input: ItemImpl) -> ItemImpl {
635 let crate_ = generate_crate_access();
636
637 input.self_ty =
639 Box::new(parse_quote!( RuntimeApiImpl<__SrApiBlock__, RuntimeApiImplCall> ));
640
641 input.generics.params.push(parse_quote!(
642 __SrApiBlock__: #crate_::BlockT
643 ));
644
645 input
646 .generics
647 .params
648 .push(parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SrApiBlock__> + 'static ));
649
650 let where_clause = input.generics.make_where_clause();
651
652 where_clause.predicates.push(parse_quote! {
653 RuntimeApiImplCall::StateBackend:
654 #crate_::StateBackend<#crate_::HashingFor<__SrApiBlock__>>
655 });
656
657 where_clause.predicates.push(parse_quote! { &'static RuntimeApiImplCall: Send });
658
659 input.attrs = filter_cfg_and_allow_attrs(&input.attrs);
660
661 fold::fold_item_impl(self, input)
662 }
663}
664
665fn generate_api_impl_for_runtime_api(impls: &[ItemImpl]) -> Result<TokenStream> {
667 let mut result = Vec::with_capacity(impls.len());
668
669 for impl_ in impls {
670 let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
671 let runtime_block = extract_block_type_from_trait_path(impl_trait_path)?;
672 let mut runtime_mod_path = extend_with_runtime_decl_path(impl_trait_path.clone());
673 runtime_mod_path.segments.pop();
675
676 let mut processed_impl =
677 ApiRuntimeImplToApiRuntimeApiImpl { runtime_block }.process(impl_.clone());
678
679 processed_impl.attrs.push(parse_quote!(#[automatically_derived]));
680
681 result.push(processed_impl);
682 }
683
684 let crate_ = generate_crate_access();
685
686 Ok(quote!( #crate_::std_enabled! { #( #result )* } ))
687}
688
689fn populate_runtime_api_versions(
690 result: &mut Vec<TokenStream>,
691 sections: &mut Vec<TokenStream>,
692 attrs: Vec<Attribute>,
693 id: Path,
694 version: TokenStream,
695 crate_access: &TokenStream,
696) {
697 result.push(quote!(
698 #( #attrs )*
699 (#id, #version)
700 ));
701
702 sections.push(quote!(
703 #crate_access::std_disabled! {
704 #( #attrs )*
705 const _: () = {
706 #[link_section = "runtime_apis"]
708 static SECTION_CONTENTS: [u8; 12] = #crate_access::serialize_runtime_api_info(#id, #version);
709 };
710 }
711 ));
712}
713
714fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
717 let mut result = Vec::<TokenStream>::with_capacity(impls.len());
718 let mut sections = Vec::<TokenStream>::with_capacity(impls.len());
719 let mut processed_traits = HashMap::new();
720
721 let c = generate_crate_access();
722
723 for impl_ in impls {
724 let versions = extract_api_version(&impl_.attrs, impl_.span())?;
725 let api_ver = versions.custom.map(|a| a as u32);
726
727 let mut path = extend_with_runtime_decl_path(
728 extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?.clone(),
729 );
730 let trait_ = path
732 .segments
733 .pop()
734 .expect("extract_impl_trait already checks that this is valid; qed")
735 .into_value()
736 .ident;
737
738 let span = trait_.span();
739 if let Some(other_span) = processed_traits.insert(trait_, span) {
740 let mut error = Error::new(
741 span,
742 "Two traits with the same name detected! \
743 The trait name is used to generate its ID. \
744 Please rename one trait at the declaration!",
745 );
746
747 error.combine(Error::new(other_span, "First trait implementation."));
748
749 return Err(error);
750 }
751
752 let id: Path = parse_quote!( #path ID );
753 let mut attrs = filter_cfg_and_allow_attrs(&impl_.attrs);
754
755 if let Some(feature_gated) = versions.feature_gated {
758 let feature_gated_version = feature_gated.1 as u32;
759 let mut feature_gated_attrs = attrs.clone();
761 add_feature_guard(&mut feature_gated_attrs, &feature_gated.0, true);
762 populate_runtime_api_versions(
763 &mut result,
764 &mut sections,
765 feature_gated_attrs,
766 id.clone(),
767 quote!( #feature_gated_version ),
768 &c,
769 );
770
771 add_feature_guard(&mut attrs, &feature_gated.0, false);
774 }
775
776 let base_api_version = quote!( #path VERSION );
779 let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| base_api_version);
780 populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c);
781 }
782
783 Ok(quote!(
784 pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]);
785
786 #( #sections )*
787 ))
788}
789
790struct ReplaceSelfImpl {
792 self_ty: Box<Type>,
793}
794
795impl ReplaceSelfImpl {
796 fn replace(&mut self, trait_: &mut ItemImpl) {
798 visit_mut::visit_item_impl_mut(self, trait_)
799 }
800}
801
802impl VisitMut for ReplaceSelfImpl {
803 fn visit_type_mut(&mut self, ty: &mut syn::Type) {
804 match ty {
805 Type::Path(p) if p.path.is_ident("Self") => {
806 *ty = *self.self_ty.clone();
807 },
808 ty => syn::visit_mut::visit_type_mut(self, ty),
809 }
810 }
811}
812
813fn rename_self_in_trait_impls(impls: &mut [ItemImpl]) {
815 impls.iter_mut().for_each(|i| {
816 let mut checker = ReplaceSelfImpl { self_ty: i.self_ty.clone() };
817 checker.replace(i);
818 });
819}
820
821pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
823 let RuntimeApiImpls { impls: mut api_impls } = parse_macro_input!(input as RuntimeApiImpls);
825
826 impl_runtime_apis_impl_inner(&mut api_impls)
827 .unwrap_or_else(|e| e.to_compile_error())
828 .into()
829}
830
831fn impl_runtime_apis_impl_inner(api_impls: &mut [ItemImpl]) -> Result<TokenStream> {
832 rename_self_in_trait_impls(api_impls);
833
834 let dispatch_impl = generate_dispatch_function(api_impls)?;
835 let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?;
836 let base_runtime_api = generate_runtime_api_base_structures()?;
837 let runtime_api_versions = generate_runtime_api_versions(api_impls)?;
838 let wasm_interface = generate_wasm_interface(api_impls)?;
839 let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
840
841 let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?;
842
843 let impl_ = quote!(
844 #base_runtime_api
845
846 #api_impls_for_runtime
847
848 #api_impls_for_runtime_api
849
850 #runtime_api_versions
851
852 #runtime_metadata
853
854 pub mod api {
855 use super::*;
856
857 #dispatch_impl
858
859 #wasm_interface
860 }
861 );
862
863 let impl_ = expander::Expander::new("impl_runtime_apis")
864 .dry(std::env::var("EXPAND_MACROS").is_err())
865 .verbose(true)
866 .write_to_out_dir(impl_)
867 .expect("Does not fail because of IO in OUT_DIR; qed");
868
869 Ok(impl_)
870}
871
872fn filter_cfg_and_allow_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
874 attrs
875 .iter()
876 .filter(|a| a.path().is_ident("cfg") || a.path().is_ident("allow"))
877 .cloned()
878 .collect()
879}
880
881#[cfg(test)]
882mod tests {
883 use super::*;
884
885 #[test]
886 fn filter_non_cfg_attributes() {
887 let cfg_std: Attribute = parse_quote!(#[cfg(feature = "std")]);
888 let cfg_benchmarks: Attribute = parse_quote!(#[cfg(feature = "runtime-benchmarks")]);
889 let allow: Attribute = parse_quote!(#[allow(non_camel_case_types)]);
890
891 let attrs = vec![
892 cfg_std.clone(),
893 parse_quote!(#[derive(Debug)]),
894 parse_quote!(#[test]),
895 cfg_benchmarks.clone(),
896 parse_quote!(#[allow(non_camel_case_types)]),
897 ];
898
899 let filtered = filter_cfg_and_allow_attrs(&attrs);
900 assert_eq!(filtered.len(), 3);
901 assert_eq!(cfg_std, filtered[0]);
902 assert_eq!(cfg_benchmarks, filtered[1]);
903 assert_eq!(allow, filtered[2]);
904 }
905
906 #[test]
907 fn impl_trait_rename_self_param() {
908 let code = quote::quote! {
909 impl client::Core<Block> for Runtime {
910 fn initialize_block(header: &HeaderFor<Self>) -> Output<Self> {
911 let _: HeaderFor<Self> = header.clone();
912 example_fn::<Self>(header)
913 }
914 }
915 };
916 let expected = quote::quote! {
917 impl client::Core<Block> for Runtime {
918 fn initialize_block(header: &HeaderFor<Runtime>) -> Output<Runtime> {
919 let _: HeaderFor<Runtime> = header.clone();
920 example_fn::<Runtime>(header)
921 }
922 }
923 };
924
925 let RuntimeApiImpls { impls: mut api_impls } =
927 syn::parse2::<RuntimeApiImpls>(code).unwrap();
928
929 rename_self_in_trait_impls(&mut api_impls);
931 let result: TokenStream = quote::quote! { #(#api_impls)* };
932
933 assert_eq!(result.to_string(), expected.to_string());
934 }
935}