From 543444ca33676f31db2ab2e7c92a3410894444a7 Mon Sep 17 00:00:00 2001 From: Pavlo Khrystenko Date: Wed, 8 Jan 2025 17:02:11 +0100 Subject: [PATCH] review comments --- substrate/primitives/api/output.rs | 0 .../api/proc-macro/src/impl_runtime_apis.rs | 145 +++++++++++------- .../api/proc-macro/src/runtime_metadata.rs | 4 +- .../api/test/tests/decl_and_impl.rs | 23 ++- 4 files changed, 109 insertions(+), 63 deletions(-) create mode 100644 substrate/primitives/api/output.rs diff --git a/substrate/primitives/api/output.rs b/substrate/primitives/api/output.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs index c4be1e63ff68..701b6dfbca7f 100644 --- a/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs +++ b/substrate/primitives/api/proc-macro/src/impl_runtime_apis.rs @@ -44,7 +44,13 @@ use std::collections::HashMap; /// The structure used for parsing the runtime api implementations. struct RuntimeApiImpls { impls: Vec, - uses: Vec, + uses: Vec, +} + +mod custom_kw { + use syn::custom_keyword; + + custom_keyword!(external_impls); } impl Parse for RuntimeApiImpls { @@ -52,9 +58,15 @@ impl Parse for RuntimeApiImpls { let mut impls = Vec::new(); let mut uses = Vec::new(); while !input.is_empty() { - if input.peek(syn::Token![use]) || input.peek2(syn::Token![use]) { - let item = input.parse::()?; - uses.push(item); + if input.peek(custom_kw::external_impls) || input.peek2(syn::Token![!]) { + let content; + input.parse::()?; + input.parse::()?; + syn::braced!(content in input); + let items = content.parse_terminated(syn::TypePath::parse, syn::Token![,])?; + for item in items.into_iter() { + uses.push(item) + } } else { impls.push(input.parse::()?); } @@ -221,7 +233,7 @@ fn generate_dispatch_function(impls: &[ItemImpl], kind: Kind) -> Result Result { let api_ver = api_ver.map(|a| quote!( #a )).unwrap_or_else(|| base_api_version); populate_runtime_api_versions(&mut result, &mut sections, attrs, id, api_ver, &c); } - Ok(quote!( - pub const RUNTIME_API_VERSIONS: #c::ApisVec = #c::create_apis_vec!([ #( #result ),* ]); + pub const PARTIAL_RUNTIME_API_VERSIONS: &[([u8;8], u32)] = &[ #( #result ),* ]; #( #sections )* )) @@ -856,9 +867,27 @@ pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok .into() } +fn parse_path(path: &mut Vec, item: &UseTree) -> Result<()> { + match &item { + syn::UseTree::Path(use_path) => { + path.push(use_path.ident.clone()); + parse_path(path, use_path.tree.as_ref()) + }, + syn::UseTree::Glob(_) => Ok(()), + syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => { + let error = Error::new( + item.span(), + "Unsupported syntax used to import api implementaions from an extension module. \ + Try using `pub use ::*` or `use ::*`", + ); + return Err(error) + }, + } +} + fn impl_runtime_apis_impl_inner( api_impls: &mut [ItemImpl], - uses: &[ItemUse], + uses: &[TypePath], ) -> Result { rename_self_in_trait_impls(api_impls); @@ -867,49 +896,48 @@ fn impl_runtime_apis_impl_inner( let runtime_api_versions = generate_runtime_api_versions(api_impls)?; let wasm_interface = generate_wasm_interface(api_impls)?; let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?; - let modules = match uses - .iter() - .map(|item| { - let mut path: Vec = vec![]; - fn call(path: &mut Vec, item: &UseTree) -> Result<()> { - match &item { - syn::UseTree::Path(use_path) => { - path.push(use_path.ident.clone()); - call(path, use_path.tree.as_ref()) - }, - syn::UseTree::Glob(_) => Ok(()), - syn::UseTree::Name(_) | syn::UseTree::Rename(_) | syn::UseTree::Group(_) => { - let error = Error::new( - item.span(), - "Unsupported syntax used to import api implementaions from an extension module. \ - Try using `pub use ::*` or `use ::*`", - ); - return Err(error) - }, - } - } - call(&mut path, &item.tree)?; - let tok = quote::quote! {#(#path)::*}; - Ok(syn::parse::(tok.into()) - .expect("Can't happen, a valid TypePath was used in the `UseTree`")) - }) - .collect::>>() - .map_err(|e| e.into_compile_error()) - { - Ok(items) => items, - Err(e) => return Ok(e), - }; - let dispatch_impl = generate_dispatch_function(api_impls, Kind::Main(&modules))?; + let dispatch_impl = generate_dispatch_function(api_impls, Kind::Main(&uses))?; let runtime_metadata = - crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Main(&modules))?; + crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Main(&uses))?; let c = generate_crate_access(); - let impl_ = quote!( + let runtime_api_versions_full = quote! { + + pub const RUNTIME_API_VERSIONS: #c::ApisVec = { + const LEN: usize = #(#uses::internal::PARTIAL_RUNTIME_API_VERSIONS.len() + )* PARTIAL_RUNTIME_API_VERSIONS.len() + 0; + const ARR: [([u8;8], u32); LEN] = { + let mut arr: [([u8;8], u32); LEN] = [([0;8],0); LEN]; + let mut base: usize = 0; + { + let mut i = 0; + while i < PARTIAL_RUNTIME_API_VERSIONS.len() { + arr[base + i] = PARTIAL_RUNTIME_API_VERSIONS[i]; + i += 1; + } + base += PARTIAL_RUNTIME_API_VERSIONS.len(); + } + #({ + let s = #uses::internal::PARTIAL_RUNTIME_API_VERSIONS; + let mut i = 0; + while i < s.len() { + arr[base + i] = s[i]; + i += 1; + } + base += s.len(); + })* + if base != LEN { panic!("invalid length"); } + arr + }; + #c::create_apis_vec!(ARR) + }; + }; + + let impl_ = quote! { #( #[allow(unused_imports)] - #uses + pub use #uses::*; )* #base_runtime_api @@ -922,10 +950,7 @@ fn impl_runtime_apis_impl_inner( #runtime_metadata - pub fn runtime_api_versions() -> #c::ApisVec { - let api = #c::vec::Vec::from([RUNTIME_API_VERSIONS.into_owned(), #(#modules::RUNTIME_API_VERSIONS.into_owned()),*]).concat(); - api.into() - } + #runtime_api_versions_full pub mod api { use super::*; @@ -934,7 +959,7 @@ fn impl_runtime_apis_impl_inner( #wasm_interface } - ); + }; let impl_ = expander::Expander::new("impl_runtime_apis") .dry(std::env::var("EXPAND_MACROS").is_err()) @@ -963,7 +988,7 @@ pub fn impl_runtime_apis_impl_ext(input: proc_macro::TokenStream) -> proc_macro: fn impl_runtime_apis_impl_inner_ext( module: Ident, api_impls: &mut [ItemImpl], - uses: &[ItemUse], + uses: &[TypePath], ) -> Result { rename_self_in_trait_impls(api_impls); let dispatch_impl = generate_dispatch_function(api_impls, Kind::Ext)?; @@ -976,22 +1001,28 @@ fn impl_runtime_apis_impl_inner_ext( crate::runtime_metadata::generate_impl_runtime_metadata(api_impls, Kind::Ext)?; let impl_ = quote!( pub mod #module { - #(#uses)* + #( + pub use #uses::*; + )* #api_impls_for_runtime #api_impls_for_runtime_api - #runtime_api_versions + pub mod internal { + use super::*; - #runtime_metadata + #runtime_api_versions - pub mod api { - use super::*; + #runtime_metadata - #dispatch_impl + pub mod api { + use super::*; - #wasm_interface + #dispatch_impl + + #wasm_interface + } } } ); diff --git a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs index 1c594ff31467..e01c0ae73c94 100644 --- a/substrate/primitives/api/proc-macro/src/runtime_metadata.rs +++ b/substrate/primitives/api/proc-macro/src/runtime_metadata.rs @@ -309,7 +309,7 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl], kind: Kind) -> Result< #[doc(hidden)] impl #crate_::metadata_ir::InternalImplRuntimeApis for #runtime_name { fn runtime_metadata(&self) -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { - let other_apis: #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> = #crate_::vec::Vec::from([#crate_::vec![ #( #metadata, )*], #(#paths::runtime_metadata(),)*]).concat(); + let other_apis: #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> = #crate_::vec::Vec::from([#crate_::vec![ #( #metadata, )*], #(#paths::internal::partial_metadata(),)*]).concat(); other_apis } } @@ -318,7 +318,7 @@ pub fn generate_impl_runtime_metadata(impls: &[ItemImpl], kind: Kind) -> Result< Kind::Ext => quote! { #[doc(hidden)] #[inline(always)] - pub fn runtime_metadata() -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { + pub fn partial_metadata() -> #crate_::vec::Vec<#crate_::metadata_ir::RuntimeApiMetadataIR> { #crate_::vec![ #( #metadata, )* ] } diff --git a/substrate/primitives/api/test/tests/decl_and_impl.rs b/substrate/primitives/api/test/tests/decl_and_impl.rs index 11441ae6ade2..e7651b71621c 100644 --- a/substrate/primitives/api/test/tests/decl_and_impl.rs +++ b/substrate/primitives/api/test/tests/decl_and_impl.rs @@ -45,6 +45,10 @@ decl_runtime_apis! { fn same_name() -> String; } + pub trait Example2 { + fn same_name() -> String; + } + #[api_version(2)] pub trait ApiWithMultipleVersions { fn stable_one(data: u64); @@ -146,13 +150,13 @@ impl_runtime_apis! { unimplemented!() } } - - pub use ext::*; + external_impls!{ext, ext2} } #[sp_api::impl_runtime_apis_ext] mod ext { - use super::*; + external_impls! {super} + impl super::Example for Runtime { fn same_name() -> String { "example".to_string() @@ -160,6 +164,16 @@ mod ext { } } +#[sp_api::impl_runtime_apis_ext] +mod ext2 { + external_impls! {super} + impl super::Example2 for Runtime { + fn same_name() -> String { + "example".to_string() + } + } +} + struct MockApi { block: Option, } @@ -251,7 +265,7 @@ fn check_runtime_api_info() { } fn check_runtime_api_versions_contains() { - assert!(self::runtime_api_versions().iter().any(|v| v == &(T::ID, T::VERSION))); + assert!(RUNTIME_API_VERSIONS.iter().any(|v| v == &(T::ID, T::VERSION))); } fn check_staging_runtime_api_versions(_staging_ver: u32) { @@ -387,4 +401,5 @@ fn runtime_api_metadata_matches_version_implemented() { #[test] fn runtime_api_works_with_ext() { check_runtime_api_versions_contains::>(); + check_runtime_api_versions_contains::>(); }