1use crate::{
19 common::API_VERSION_ATTRIBUTE,
20 utils::{
21 extract_block_type_from_trait_path, extract_impl_trait,
22 extract_parameter_names_types_and_borrows, generate_crate_access,
23 generate_runtime_mod_name_for_trait, parse_runtime_api_version, prefix_function_with_trait,
24 versioned_trait_name, AllowSelfRefInParameters, RequireQualifiedTraitPath,
25 },
26};
27
28use proc_macro2::{Span, TokenStream};
29
30use quote::quote;
31
32use syn::{
33 fold::{self, Fold},
34 parenthesized,
35 parse::{Error, Parse, ParseStream, Result},
36 parse_macro_input, parse_quote,
37 spanned::Spanned,
38 Attribute, Ident, ImplItem, ItemImpl, LitInt, LitStr, Path, Signature, Type, TypePath,
39};
40
41use std::collections::HashMap;
42
43struct RuntimeApiImpls {
45 impls: Vec<ItemImpl>,
46}
47
48impl Parse for RuntimeApiImpls {
49 fn parse(input: ParseStream) -> Result<Self> {
50 let mut impls = Vec::new();
51
52 while !input.is_empty() {
53 impls.push(ItemImpl::parse(input)?);
54 }
55
56 if impls.is_empty() {
57 Err(Error::new(Span::call_site(), "No api implementation given!"))
58 } else {
59 Ok(Self { impls })
60 }
61 }
62}
63
64fn generate_impl_call(
67 signature: &Signature,
68 runtime: &Type,
69 input: &Ident,
70 impl_trait: &Path,
71 api_version: &ApiVersion,
72) -> Result<TokenStream> {
73 let params =
74 extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
75
76 let c = generate_crate_access();
77 let fn_name = &signature.ident;
78 let fn_name_str = fn_name.to_string();
79 let pnames = params.iter().map(|v| &v.0);
80 let pnames2 = params.iter().map(|v| &v.0);
81 let ptypes = params.iter().map(|v| &v.1);
82 let pborrow = params.iter().map(|v| &v.2);
83
84 let decode_params = if params.is_empty() {
85 quote!(
86 if !#input.is_empty() {
87 panic!(
88 "Bad input data provided to {}: expected no parameters, but input buffer is not empty.",
89 #fn_name_str
90 );
91 }
92 )
93 } else {
94 let let_binding = if params.len() == 1 {
95 quote! {
96 let #( #pnames )* : #( #ptypes )*
97 }
98 } else {
99 quote! {
100 let ( #( #pnames ),* ) : ( #( #ptypes ),* )
101 }
102 };
103
104 quote!(
105 #let_binding =
106 match #c::DecodeLimit::decode_all_with_depth_limit(
107 #c::MAX_EXTRINSIC_DEPTH,
108 &mut #input,
109 ) {
110 Ok(res) => res,
111 Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e),
112 };
113 )
114 };
115
116 let fn_calls = if let Some(feature_gated) = &api_version.feature_gated {
117 let pnames = pnames2;
118 let pnames2 = pnames.clone();
119 let pborrow2 = pborrow.clone();
120
121 let feature_name = &feature_gated.0;
122 let impl_trait_fg = extend_with_api_version(impl_trait.clone(), Some(feature_gated.1));
123 let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
124
125 quote!(
126 #[cfg(feature = #feature_name)]
127 #[allow(deprecated)]
128 let r = <#runtime as #impl_trait_fg>::#fn_name(#( #pborrow #pnames ),*);
129
130 #[cfg(not(feature = #feature_name))]
131 #[allow(deprecated)]
132 let r = <#runtime as #impl_trait>::#fn_name(#( #pborrow2 #pnames2 ),*);
133
134 r
135 )
136 } else {
137 let pnames = pnames2;
138 let impl_trait = extend_with_api_version(impl_trait.clone(), api_version.custom);
139
140 quote!(
141 #[allow(deprecated)]
142 <#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames ),*)
143 )
144 };
145
146 Ok(quote!(
147 #decode_params
148
149 #fn_calls
150 ))
151}
152
153fn generate_impl_calls(
155 impls: &[ItemImpl],
156 input: &Ident,
157) -> Result<Vec<(Ident, Ident, TokenStream, Vec<Attribute>)>> {
158 let mut impl_calls = Vec::new();
159
160 for impl_ in impls {
161 let trait_api_ver = extract_api_version(&impl_.attrs, impl_.span())?;
162 let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
163 let impl_trait = extend_with_runtime_decl_path(impl_trait_path.clone());
164 let impl_trait_ident = &impl_trait_path
165 .segments
166 .last()
167 .ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))?
168 .ident;
169
170 for item in &impl_.items {
171 if let ImplItem::Fn(method) = item {
172 let impl_call = generate_impl_call(
173 &method.sig,
174 &impl_.self_ty,
175 input,
176 &impl_trait,
177 &trait_api_ver,
178 )?;
179 let mut attrs = filter_cfg_attrs(&impl_.attrs);
180
181 attrs.extend(filter_cfg_attrs(&method.attrs));
183
184 impl_calls.push((
185 impl_trait_ident.clone(),
186 method.sig.ident.clone(),
187 impl_call,
188 attrs,
189 ));
190 }
191 }
192 }
193
194 Ok(impl_calls)
195}
196
197fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
199 let data = Ident::new("_sp_api_input_data_", Span::call_site());
200 let c = generate_crate_access();
201 let impl_calls =
202 generate_impl_calls(impls, &data)?
203 .into_iter()
204 .map(|(trait_, fn_name, impl_, attrs)| {
205 let name = prefix_function_with_trait(&trait_, &fn_name);
206 quote!(
207 #( #attrs )*
208 #name => Some(#c::Encode::encode(&{ #impl_ })),
209 )
210 });
211
212 Ok(quote!(
213 #c::std_enabled! {
214 pub fn dispatch(method: &str, mut #data: &[u8]) -> Option<Vec<u8>> {
215 match method {
216 #( #impl_calls )*
217 _ => None,
218 }
219 }
220 }
221 ))
222}
223
224fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
226 let input = Ident::new("input", Span::call_site());
227 let c = generate_crate_access();
228
229 let impl_calls =
230 generate_impl_calls(impls, &input)?
231 .into_iter()
232 .map(|(trait_, fn_name, impl_, attrs)| {
233 let fn_name =
234 Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site());
235
236 quote!(
237 #c::std_disabled! {
238 #( #attrs )*
239 #[no_mangle]
240 #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), #c::__private::polkavm_export(abi = #c::__private::polkavm_abi))]
241 pub unsafe extern fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
242 let mut #input = if input_len == 0 {
243 &[0u8; 0]
244 } else {
245 unsafe {
246 ::core::slice::from_raw_parts(input_data, input_len)
247 }
248 };
249
250 #c::init_runtime_logger();
251
252 let output = (move || { #impl_ })();
253 #c::to_substrate_wasm_fn_return_value(&output)
254 }
255 }
256 )
257 });
258
259 Ok(quote!( #( #impl_calls )* ))
260}
261
262fn generate_runtime_api_base_structures() -> Result<TokenStream> {
263 let crate_ = generate_crate_access();
264
265 Ok(quote!(
266 pub struct RuntimeApi {}
267 #crate_::std_enabled! {
268 pub struct RuntimeApiImpl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block> + 'static> {
270 call: &'static C,
271 transaction_depth: std::cell::RefCell<u16>,
272 changes: std::cell::RefCell<#crate_::OverlayedChanges<#crate_::HashingFor<Block>>>,
273 recorder: std::option::Option<#crate_::ProofRecorder<Block>>,
274 call_context: #crate_::CallContext,
275 extensions: std::cell::RefCell<#crate_::Extensions>,
276 extensions_generated_for: std::cell::RefCell<std::option::Option<Block::Hash>>,
277 }
278
279 #[automatically_derived]
280 impl<Block: #crate_::BlockT, C: #crate_::CallApiAt<Block>> #crate_::ApiExt<Block> for
281 RuntimeApiImpl<Block, C>
282 {
283 fn execute_in_transaction<F: FnOnce(&Self) -> #crate_::TransactionOutcome<R>, R>(
284 &self,
285 call: F,
286 ) -> R where Self: Sized {
287 self.start_transaction();
288
289 *std::cell::RefCell::borrow_mut(&self.transaction_depth) += 1;
290 let res = call(self);
291 std::cell::RefCell::borrow_mut(&self.transaction_depth)
292 .checked_sub(1)
293 .expect("Transactions are opened and closed together; qed");
294
295 self.commit_or_rollback_transaction(
296 std::matches!(res, #crate_::TransactionOutcome::Commit(_))
297 );
298
299 res.into_inner()
300 }
301
302 fn has_api<A: #crate_::RuntimeApiInfo + ?Sized>(
303 &self,
304 at: <Block as #crate_::BlockT>::Hash,
305 ) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
306 #crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
307 .map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, |v| v == A::VERSION))
308 }
309
310 fn has_api_with<A: #crate_::RuntimeApiInfo + ?Sized, P: Fn(u32) -> bool>(
311 &self,
312 at: <Block as #crate_::BlockT>::Hash,
313 pred: P,
314 ) -> std::result::Result<bool, #crate_::ApiError> where Self: Sized {
315 #crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
316 .map(|v| #crate_::RuntimeVersion::has_api_with(&v, &A::ID, pred))
317 }
318
319 fn api_version<A: #crate_::RuntimeApiInfo + ?Sized>(
320 &self,
321 at: <Block as #crate_::BlockT>::Hash,
322 ) -> std::result::Result<Option<u32>, #crate_::ApiError> where Self: Sized {
323 #crate_::CallApiAt::<Block>::runtime_version_at(self.call, at)
324 .map(|v| #crate_::RuntimeVersion::api_version(&v, &A::ID))
325 }
326
327 fn record_proof(&mut self) {
328 self.recorder = std::option::Option::Some(std::default::Default::default());
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<u64>) -> 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_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_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_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
790pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
792 let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls);
794
795 impl_runtime_apis_impl_inner(&api_impls)
796 .unwrap_or_else(|e| e.to_compile_error())
797 .into()
798}
799
800fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
801 let dispatch_impl = generate_dispatch_function(api_impls)?;
802 let api_impls_for_runtime = generate_api_impl_for_runtime(api_impls)?;
803 let base_runtime_api = generate_runtime_api_base_structures()?;
804 let runtime_api_versions = generate_runtime_api_versions(api_impls)?;
805 let wasm_interface = generate_wasm_interface(api_impls)?;
806 let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
807
808 let runtime_metadata = crate::runtime_metadata::generate_impl_runtime_metadata(api_impls)?;
809
810 let impl_ = quote!(
811 #base_runtime_api
812
813 #api_impls_for_runtime
814
815 #api_impls_for_runtime_api
816
817 #runtime_api_versions
818
819 #runtime_metadata
820
821 pub mod api {
822 use super::*;
823
824 #dispatch_impl
825
826 #wasm_interface
827 }
828 );
829
830 let impl_ = expander::Expander::new("impl_runtime_apis")
831 .dry(std::env::var("EXPAND_MACROS").is_err())
832 .verbose(true)
833 .write_to_out_dir(impl_)
834 .expect("Does not fail because of IO in OUT_DIR; qed");
835
836 Ok(impl_)
837}
838
839fn filter_cfg_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
841 attrs.iter().filter(|a| a.path().is_ident("cfg")).cloned().collect()
842}
843
844fn extract_cfg_api_version(attrs: &Vec<Attribute>, span: Span) -> Result<Option<(String, u64)>> {
847 let cfg_attrs = attrs.iter().filter(|a| a.path().is_ident("cfg_attr")).collect::<Vec<_>>();
848
849 let mut cfg_api_version_attr = Vec::new();
850 for cfg_attr in cfg_attrs {
851 let mut feature_name = None;
852 let mut api_version = None;
853 cfg_attr.parse_nested_meta(|m| {
854 if m.path.is_ident("feature") {
855 let a = m.value()?;
856 let b: LitStr = a.parse()?;
857 feature_name = Some(b.value());
858 } else if m.path.is_ident(API_VERSION_ATTRIBUTE) {
859 let content;
860 parenthesized!(content in m.input);
861 let ver: LitInt = content.parse()?;
862 api_version = Some(ver.base10_parse::<u64>()?);
863 }
864 Ok(())
865 })?;
866
867 if let (Some(feature_name), Some(api_version)) = (feature_name, api_version) {
869 cfg_api_version_attr.push((feature_name, api_version, cfg_attr.span()));
870 }
871 }
872
873 if cfg_api_version_attr.len() > 1 {
874 let mut err = Error::new(span, format!("Found multiple feature gated api versions (cfg attribute with nested `{}` attribute). This is not supported.", API_VERSION_ATTRIBUTE));
875 for (_, _, attr_span) in cfg_api_version_attr {
876 err.combine(Error::new(attr_span, format!("`{}` found here", API_VERSION_ATTRIBUTE)));
877 }
878
879 return Err(err);
880 }
881
882 Ok(cfg_api_version_attr
883 .into_iter()
884 .next()
885 .map(|(feature, name, _)| (feature, name)))
886}
887
888struct ApiVersion {
890 pub custom: Option<u64>,
892 pub feature_gated: Option<(String, u64)>,
895}
896
897fn extract_api_version(attrs: &Vec<Attribute>, span: Span) -> Result<ApiVersion> {
902 let api_ver = attrs
904 .iter()
905 .filter(|a| a.path().is_ident(API_VERSION_ATTRIBUTE))
906 .collect::<Vec<_>>();
907
908 if api_ver.len() > 1 {
909 return Err(Error::new(
910 span,
911 format!(
912 "Found multiple #[{}] attributes for an API implementation. \
913 Each runtime API can have only one version.",
914 API_VERSION_ATTRIBUTE
915 ),
916 ));
917 }
918
919 Ok(ApiVersion {
921 custom: api_ver.first().map(|v| parse_runtime_api_version(v)).transpose()?,
922 feature_gated: extract_cfg_api_version(attrs, span)?,
923 })
924}
925
926#[cfg(test)]
927mod tests {
928 use super::*;
929
930 #[test]
931 fn filter_non_cfg_attributes() {
932 let cfg_std: Attribute = parse_quote!(#[cfg(feature = "std")]);
933 let cfg_benchmarks: Attribute = parse_quote!(#[cfg(feature = "runtime-benchmarks")]);
934
935 let attrs = vec![
936 cfg_std.clone(),
937 parse_quote!(#[derive(Debug)]),
938 parse_quote!(#[test]),
939 cfg_benchmarks.clone(),
940 parse_quote!(#[allow(non_camel_case_types)]),
941 ];
942
943 let filtered = filter_cfg_attrs(&attrs);
944 assert_eq!(filtered.len(), 2);
945 assert_eq!(cfg_std, filtered[0]);
946 assert_eq!(cfg_benchmarks, filtered[1]);
947 }
948}