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::>();
}