Run cargo fmt on the whole code base (#9394)

* Run cargo fmt on the whole code base

* Second run

* Add CI check

* Fix compilation

* More unnecessary braces

* Handle weights

* Use --all

* Use correct attributes...

* Fix UI tests

* AHHHHHHHHH

* 🤦

* Docs

* Fix compilation

* 🤷

* Please stop

* 🤦 x 2

* More

* make rustfmt.toml consistent with polkadot

Co-authored-by: André Silva <andrerfosilva@gmail.com>
This commit is contained in:
Bastian Köcher
2021-07-21 16:32:32 +02:00
committed by GitHub
parent d451c38c1c
commit 7b56ab15b4
1010 changed files with 53339 additions and 51208 deletions
@@ -16,21 +16,25 @@
// limitations under the License.
use crate::utils::{
generate_crate_access, generate_hidden_includes, generate_runtime_mod_name_for_trait,
fold_fn_decl_for_client_side, extract_parameter_names_types_and_borrows,
generate_native_call_generator_fn_name, return_type_extract_type,
generate_method_runtime_api_impl_name, generate_call_api_at_fn_name, prefix_function_with_trait,
replace_wild_card_parameter_names, AllowSelfRefInParameters,
extract_parameter_names_types_and_borrows, fold_fn_decl_for_client_side,
generate_call_api_at_fn_name, generate_crate_access, generate_hidden_includes,
generate_method_runtime_api_impl_name, generate_native_call_generator_fn_name,
generate_runtime_mod_name_for_trait, prefix_function_with_trait,
replace_wild_card_parameter_names, return_type_extract_type, AllowSelfRefInParameters,
};
use proc_macro2::{TokenStream, Span};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
spanned::Spanned, parse_macro_input, parse::{Parse, ParseStream, Result, Error}, ReturnType,
fold::{self, Fold}, parse_quote, ItemTrait, Generics, GenericParam, Attribute, FnArg, Type,
visit::{Visit, self}, TraitBound, Meta, NestedMeta, Lit, TraitItem, Ident, TraitItemMethod,
fold::{self, Fold},
parse::{Error, Parse, ParseStream, Result},
parse_macro_input, parse_quote,
spanned::Spanned,
visit::{self, Visit},
Attribute, FnArg, GenericParam, Generics, Ident, ItemTrait, Lit, Meta, NestedMeta, ReturnType,
TraitBound, TraitItem, TraitItemMethod, Type,
};
use std::collections::HashMap;
@@ -59,9 +63,8 @@ const CHANGED_IN_ATTRIBUTE: &str = "changed_in";
/// Is used when a trait method was renamed.
const RENAMED_ATTRIBUTE: &str = "renamed";
/// All attributes that we support in the declaration of a runtime api trait.
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] = &[
CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE,
];
const SUPPORTED_ATTRIBUTE_NAMES: &[&str] =
&[CORE_TRAIT_ATTRIBUTE, API_VERSION_ATTRIBUTE, CHANGED_IN_ATTRIBUTE, RENAMED_ATTRIBUTE];
/// The structure used for parsing the runtime api declarations.
struct RuntimeApiDecls {
@@ -94,14 +97,12 @@ fn extend_generics_with_block(generics: &mut Generics) {
/// attribute body as `TokenStream`.
fn remove_supported_attributes(attrs: &mut Vec<Attribute>) -> HashMap<&'static str, Attribute> {
let mut result = HashMap::new();
attrs.retain(|v| {
match SUPPORTED_ATTRIBUTE_NAMES.iter().find(|a| v.path.is_ident(a)) {
Some(attribute) => {
result.insert(*attribute, v.clone());
false
},
None => true,
}
attrs.retain(|v| match SUPPORTED_ATTRIBUTE_NAMES.iter().find(|a| v.path.is_ident(a)) {
Some(attribute) => {
result.insert(*attribute, v.clone());
false
},
None => true,
});
result
@@ -226,16 +227,17 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result<TokenStream> {
)
)
} else {
quote!( Ok(res) )
quote!(Ok(res))
};
let input_names = params.iter().map(|v| &v.0);
// If the type is using the block generic type, we will encode/decode it to make it
// compatible. To ensure that we forward it by ref/value, we use the value given by the
// the user. Otherwise if it is not using the block, we don't need to add anything.
let input_borrows = params
.iter()
.map(|v| if type_is_using_block(&v.1) { v.2.clone() } else { None });
let input_borrows =
params
.iter()
.map(|v| if type_is_using_block(&v.1) { v.2.clone() } else { None });
// Replace all `Block` with `NodeBlock`, add `'a` lifetime to references and collect
// all the function inputs.
@@ -304,28 +306,23 @@ fn parse_renamed_attribute(renamed: &Attribute) -> Result<(String, u32)> {
);
match meta {
Meta::List(list) => {
Meta::List(list) =>
if list.nested.len() > 2 && list.nested.is_empty() {
err
} else {
let mut itr = list.nested.iter();
let old_name = match itr.next() {
Some(NestedMeta::Lit(Lit::Str(i))) => {
i.value()
},
Some(NestedMeta::Lit(Lit::Str(i))) => i.value(),
_ => return err,
};
let version = match itr.next() {
Some(NestedMeta::Lit(Lit::Int(i))) => {
i.base10_parse()?
},
Some(NestedMeta::Lit(Lit::Int(i))) => i.base10_parse()?,
_ => return err,
};
Ok((old_name, version))
}
},
},
_ => err,
}
}
@@ -353,23 +350,19 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
fn_.span(),
format!(
"`{}` and `{}` are not supported at once.",
RENAMED_ATTRIBUTE,
CHANGED_IN_ATTRIBUTE
)
));
RENAMED_ATTRIBUTE, CHANGED_IN_ATTRIBUTE
),
))
}
// We do not need to generate this function for a method that signature was changed.
if attrs.contains_key(CHANGED_IN_ATTRIBUTE) {
continue;
continue
}
// Parse the renamed attributes.
let mut renames = Vec::new();
if let Some((_, a)) = attrs
.iter()
.find(|a| a.0 == &RENAMED_ATTRIBUTE)
{
if let Some((_, a)) = attrs.iter().find(|a| a.0 == &RENAMED_ATTRIBUTE) {
let (old_name, version) = parse_renamed_attribute(a)?;
renames.push((version, prefix_function_with_trait(&trait_name, &old_name)));
}
@@ -381,7 +374,7 @@ fn generate_call_api_at_calls(decl: &ItemTrait) -> Result<TokenStream> {
versions.push(version);
old_names.push(old_name);
(versions, old_names)
}
},
);
// Generate the generator function
@@ -456,27 +449,32 @@ fn generate_runtime_decls(decls: &[ItemTrait]) -> Result<TokenStream> {
extend_generics_with_block(&mut decl.generics);
let mod_name = generate_runtime_mod_name_for_trait(&decl.ident);
let found_attributes = remove_supported_attributes(&mut decl.attrs);
let api_version = get_api_version(&found_attributes).map(|v| {
generate_runtime_api_version(v as u32)
})?;
let api_version =
get_api_version(&found_attributes).map(|v| generate_runtime_api_version(v as u32))?;
let id = generate_runtime_api_id(&decl.ident.to_string());
let call_api_at_calls = generate_call_api_at_calls(&decl)?;
// Remove methods that have the `changed_in` attribute as they are not required for the
// runtime anymore.
decl.items = decl.items.iter_mut().filter_map(|i| match i {
TraitItem::Method(ref mut method) => {
if remove_supported_attributes(&mut method.attrs).contains_key(CHANGED_IN_ATTRIBUTE) {
None
} else {
// Make sure we replace all the wild card parameter names.
replace_wild_card_parameter_names(&mut method.sig);
Some(TraitItem::Method(method.clone()))
}
}
r => Some(r.clone()),
}).collect();
decl.items = decl
.items
.iter_mut()
.filter_map(|i| match i {
TraitItem::Method(ref mut method) => {
if remove_supported_attributes(&mut method.attrs)
.contains_key(CHANGED_IN_ATTRIBUTE)
{
None
} else {
// Make sure we replace all the wild card parameter names.
replace_wild_card_parameter_names(&mut method.sig);
Some(TraitItem::Method(method.clone()))
}
},
r => Some(r.clone()),
})
.collect();
let native_call_generators = generate_native_call_generators(&decl)?;
@@ -533,8 +531,10 @@ impl<'a> ToClientSideDecl<'a> {
result
}
fn fold_trait_item_method(&mut self, method: TraitItemMethod)
-> (TraitItemMethod, Option<TraitItemMethod>, TraitItemMethod) {
fn fold_trait_item_method(
&mut self,
method: TraitItemMethod,
) -> (TraitItemMethod, Option<TraitItemMethod>, TraitItemMethod) {
let crate_ = self.crate_;
let context = quote!( #crate_::ExecutionContext::OffchainCall(None) );
let fn_impl = self.create_method_runtime_api_impl(method.clone());
@@ -547,8 +547,9 @@ impl<'a> ToClientSideDecl<'a> {
fn create_method_decl_with_context(&mut self, method: TraitItemMethod) -> TraitItemMethod {
let crate_ = self.crate_;
let context_arg: syn::FnArg = parse_quote!( context: #crate_::ExecutionContext );
let mut fn_decl_ctx = self.create_method_decl(method, quote!( context ));
fn_decl_ctx.sig.ident = Ident::new(&format!("{}_with_context", &fn_decl_ctx.sig.ident), Span::call_site());
let mut fn_decl_ctx = self.create_method_decl(method, quote!(context));
fn_decl_ctx.sig.ident =
Ident::new(&format!("{}_with_context", &fn_decl_ctx.sig.ident), Span::call_site());
fn_decl_ctx.sig.inputs.insert(2, context_arg);
fn_decl_ctx
@@ -556,9 +557,12 @@ impl<'a> ToClientSideDecl<'a> {
/// Takes the given method and creates a `method_runtime_api_impl` method that will be
/// implemented in the runtime for the client side.
fn create_method_runtime_api_impl(&mut self, mut method: TraitItemMethod) -> Option<TraitItemMethod> {
fn create_method_runtime_api_impl(
&mut self,
mut method: TraitItemMethod,
) -> Option<TraitItemMethod> {
if remove_supported_attributes(&mut method.attrs).contains_key(CHANGED_IN_ATTRIBUTE) {
return None;
return None
}
let fn_sig = &method.sig;
@@ -566,36 +570,35 @@ impl<'a> ToClientSideDecl<'a> {
// Get types and if the value is borrowed from all parameters.
// If there is an error, we push it as the block to the user.
let param_types = match extract_parameter_names_types_and_borrows(
fn_sig,
AllowSelfRefInParameters::No,
) {
Ok(res) => res.into_iter().map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
}).collect::<Vec<_>>(),
Err(e) => {
self.errors.push(e.to_compile_error());
Vec::new()
}
};
let param_types =
match extract_parameter_names_types_and_borrows(fn_sig, AllowSelfRefInParameters::No) {
Ok(res) => res
.into_iter()
.map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
})
.collect::<Vec<_>>(),
Err(e) => {
self.errors.push(e.to_compile_error());
Vec::new()
},
};
let name = generate_method_runtime_api_impl_name(&self.trait_, &method.sig.ident);
let block_id = self.block_id;
let crate_ = self.crate_;
Some(
parse_quote!{
#[doc(hidden)]
fn #name(
&self,
at: &#block_id,
context: #crate_::ExecutionContext,
params: Option<( #( #param_types ),* )>,
params_encoded: Vec<u8>,
) -> std::result::Result<#crate_::NativeOrEncoded<#ret_type>, #crate_::ApiError>;
}
)
Some(parse_quote! {
#[doc(hidden)]
fn #name(
&self,
at: &#block_id,
context: #crate_::ExecutionContext,
params: Option<( #( #param_types ),* )>,
params_encoded: Vec<u8>,
) -> std::result::Result<#crate_::NativeOrEncoded<#ret_type>, #crate_::ApiError>;
})
}
/// Takes the method declared by the user and creates the declaration we require for the runtime
@@ -614,7 +617,7 @@ impl<'a> ToClientSideDecl<'a> {
Err(e) => {
self.errors.push(e.to_compile_error());
Vec::new()
}
},
};
let params2 = params.clone();
let ret_type = return_type_extract_type(&method.sig.output);
@@ -635,7 +638,8 @@ impl<'a> ToClientSideDecl<'a> {
Error::new(
method.span(),
"`changed_in` version can not be greater than the `api_version`",
).to_compile_error()
)
.to_compile_error(),
);
}
@@ -646,49 +650,48 @@ impl<'a> ToClientSideDecl<'a> {
method.sig.ident = ident;
method.attrs.push(parse_quote!( #[deprecated] ));
let panic = format!("Calling `{}` should not return a native value!", method.sig.ident);
(quote!( panic!(#panic) ), quote!( None ))
let panic =
format!("Calling `{}` should not return a native value!", method.sig.ident);
(quote!(panic!(#panic)), quote!(None))
},
Ok(None) => (quote!( Ok(n) ), quote!( Some(( #( #params2 ),* )) )),
Ok(None) => (quote!(Ok(n)), quote!( Some(( #( #params2 ),* )) )),
Err(e) => {
self.errors.push(e.to_compile_error());
(quote!( unimplemented!() ), quote!( None ))
}
(quote!(unimplemented!()), quote!(None))
},
};
let function_name = method.sig.ident.to_string();
// Generate the default implementation that calls the `method_runtime_api_impl` method.
method.default = Some(
parse_quote! {
{
let runtime_api_impl_params_encoded =
#crate_::Encode::encode(&( #( &#params ),* ));
method.default = Some(parse_quote! {
{
let runtime_api_impl_params_encoded =
#crate_::Encode::encode(&( #( &#params ),* ));
self.#name_impl(
__runtime_api_at_param__,
#context,
#param_tuple,
runtime_api_impl_params_encoded,
).and_then(|r|
match r {
#crate_::NativeOrEncoded::Native(n) => {
#native_handling
},
#crate_::NativeOrEncoded::Encoded(r) => {
<#ret_type as #crate_::Decode>::decode(&mut &r[..])
.map_err(|err|
#crate_::ApiError::FailedToDecodeReturnValue {
function: #function_name,
error: err,
}
)
}
self.#name_impl(
__runtime_api_at_param__,
#context,
#param_tuple,
runtime_api_impl_params_encoded,
).and_then(|r|
match r {
#crate_::NativeOrEncoded::Native(n) => {
#native_handling
},
#crate_::NativeOrEncoded::Encoded(r) => {
<#ret_type as #crate_::Decode>::decode(&mut &r[..])
.map_err(|err|
#crate_::ApiError::FailedToDecodeReturnValue {
function: #function_name,
error: err,
}
)
}
)
}
}
)
}
);
});
method
}
@@ -705,11 +708,7 @@ impl<'a> Fold for ToClientSideDecl<'a> {
if is_core_trait {
// Add all the supertraits we want to have for `Core`.
input.supertraits = parse_quote!(
'static
+ Send
+ Sync
);
input.supertraits = parse_quote!('static + Send + Sync);
} else {
// Add the `Core` runtime api as super trait.
let crate_ = &self.crate_;
@@ -729,24 +728,22 @@ fn parse_runtime_api_version(version: &Attribute) -> Result<u64> {
let meta = version.parse_meta()?;
let err = Err(Error::new(
meta.span(),
&format!(
"Unexpected `{api_version}` attribute. The supported format is `{api_version}(1)`",
api_version = API_VERSION_ATTRIBUTE
)
)
);
meta.span(),
&format!(
"Unexpected `{api_version}` attribute. The supported format is `{api_version}(1)`",
api_version = API_VERSION_ATTRIBUTE
),
));
match meta {
Meta::List(list) => {
Meta::List(list) =>
if list.nested.len() != 1 {
err
} else if let Some(NestedMeta::Lit(Lit::Int(i))) = list.nested.first() {
i.base10_parse()
} else {
err
}
},
},
_ => err,
}
}
@@ -798,14 +795,18 @@ fn generate_runtime_info_impl(trait_: &ItemTrait, version: u64) -> TokenStream {
/// Get changed in version from the user given attribute or `Ok(None)`, if no attribute was given.
fn get_changed_in(found_attributes: &HashMap<&'static str, Attribute>) -> Result<Option<u64>> {
found_attributes.get(&CHANGED_IN_ATTRIBUTE)
found_attributes
.get(&CHANGED_IN_ATTRIBUTE)
.map(|v| parse_runtime_api_version(v).map(Some))
.unwrap_or(Ok(None))
}
/// Get the api version from the user given attribute or `Ok(1)`, if no attribute was given.
fn get_api_version(found_attributes: &HashMap<&'static str, Attribute>) -> Result<u64> {
found_attributes.get(&API_VERSION_ATTRIBUTE).map(parse_runtime_api_version).unwrap_or(Ok(1))
found_attributes
.get(&API_VERSION_ATTRIBUTE)
.map(parse_runtime_api_version)
.unwrap_or(Ok(1))
}
/// Generate the declaration of the trait for the client side.
@@ -863,7 +864,10 @@ impl CheckTraitDecl {
/// Check that the given method declarations are correct.
///
/// Any error is stored in `self.errors`.
fn check_method_declarations<'a>(&mut self, methods: impl Iterator<Item = &'a TraitItemMethod>) {
fn check_method_declarations<'a>(
&mut self,
methods: impl Iterator<Item = &'a TraitItemMethod>,
) {
let mut method_to_signature_changed = HashMap::<Ident, Vec<Option<u64>>>::new();
methods.into_iter().for_each(|method| {
@@ -871,7 +875,10 @@ impl CheckTraitDecl {
let changed_in = match get_changed_in(&attributes) {
Ok(r) => r,
Err(e) => { self.errors.push(e); return; },
Err(e) => {
self.errors.push(e);
return
},
};
method_to_signature_changed
@@ -912,16 +919,13 @@ impl<'ast> Visit<'ast> for CheckTraitDecl {
fn visit_generic_param(&mut self, input: &'ast GenericParam) {
match input {
GenericParam::Type(ty) if ty.ident == BLOCK_GENERIC_IDENT => {
self.errors.push(
Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
`decl_runtime_apis!` macro!"
)
)
},
_ => {}
GenericParam::Type(ty) if ty.ident == BLOCK_GENERIC_IDENT =>
self.errors.push(Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
`decl_runtime_apis!` macro!",
)),
_ => {},
}
visit::visit_generic_param(self, input);
@@ -930,14 +934,12 @@ impl<'ast> Visit<'ast> for CheckTraitDecl {
fn visit_trait_bound(&mut self, input: &'ast TraitBound) {
if let Some(last_ident) = input.path.segments.last().map(|v| &v.ident) {
if last_ident == "BlockT" || last_ident == BLOCK_GENERIC_IDENT {
self.errors.push(
Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
self.errors.push(Error::new(
input.span(),
"`Block: BlockT` generic parameter will be added automatically by the \
`decl_runtime_apis!` macro! If you try to use a different trait than the \
substrate `Block` trait, please rename it locally."
)
)
substrate `Block` trait, please rename it locally.",
))
}
}
@@ -965,7 +967,9 @@ pub fn decl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok
// Parse all trait declarations
let RuntimeApiDecls { decls: api_decls } = parse_macro_input!(input as RuntimeApiDecls);
decl_runtime_apis_impl_inner(&api_decls).unwrap_or_else(|e| e.to_compile_error()).into()
decl_runtime_apis_impl_inner(&api_decls)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
fn decl_runtime_apis_impl_inner(api_decls: &[ItemTrait]) -> Result<TokenStream> {
@@ -975,13 +979,11 @@ fn decl_runtime_apis_impl_inner(api_decls: &[ItemTrait]) -> Result<TokenStream>
let runtime_decls = generate_runtime_decls(api_decls)?;
let client_side_decls = generate_client_side_decls(api_decls)?;
Ok(
quote!(
#hidden_includes
Ok(quote!(
#hidden_includes
#runtime_decls
#runtime_decls
#client_side_decls
)
)
#client_side_decls
))
}
@@ -16,12 +16,12 @@
// limitations under the License.
use crate::utils::{
generate_crate_access, generate_hidden_includes,
generate_runtime_mod_name_for_trait, generate_method_runtime_api_impl_name,
extract_parameter_names_types_and_borrows, generate_native_call_generator_fn_name,
return_type_extract_type, generate_call_api_at_fn_name, prefix_function_with_trait,
extract_all_signature_types, extract_block_type_from_trait_path, extract_impl_trait,
AllowSelfRefInParameters, RequireQualifiedTraitPath,
extract_parameter_names_types_and_borrows, generate_call_api_at_fn_name, generate_crate_access,
generate_hidden_includes, generate_method_runtime_api_impl_name,
generate_native_call_generator_fn_name, generate_runtime_mod_name_for_trait,
prefix_function_with_trait, return_type_extract_type, AllowSelfRefInParameters,
RequireQualifiedTraitPath,
};
use proc_macro2::{Span, TokenStream};
@@ -29,9 +29,12 @@ use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{
spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, Path, Signature, Attribute,
ImplItem, parse::{Parse, ParseStream, Result, Error}, PathArguments, GenericArgument, TypePath,
fold::{self, Fold}, parse_quote,
fold::{self, Fold},
parse::{Error, Parse, ParseStream, Result},
parse_macro_input, parse_quote,
spanned::Spanned,
Attribute, GenericArgument, Ident, ImplItem, ItemImpl, Path, PathArguments, Signature, Type,
TypePath,
};
use std::collections::HashSet;
@@ -66,9 +69,10 @@ fn generate_impl_call(
signature: &Signature,
runtime: &Type,
input: &Ident,
impl_trait: &Path
impl_trait: &Path,
) -> Result<TokenStream> {
let params = extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
let params =
extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
let fn_name = &signature.ident;
@@ -78,27 +82,25 @@ fn generate_impl_call(
let ptypes = params.iter().map(|v| &v.1);
let pborrow = params.iter().map(|v| &v.2);
Ok(
quote!(
let (#( #pnames ),*) : ( #( #ptypes ),* ) =
match #c::DecodeLimit::decode_all_with_depth_limit(
#c::MAX_EXTRINSIC_DEPTH,
&#input,
) {
Ok(res) => res,
Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e),
};
Ok(quote!(
let (#( #pnames ),*) : ( #( #ptypes ),* ) =
match #c::DecodeLimit::decode_all_with_depth_limit(
#c::MAX_EXTRINSIC_DEPTH,
&#input,
) {
Ok(res) => res,
Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e),
};
#[allow(deprecated)]
<#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*)
)
)
#[allow(deprecated)]
<#runtime as #impl_trait>::#fn_name(#( #pborrow #pnames2 ),*)
))
}
/// Generate all the implementation calls for the given functions.
fn generate_impl_calls(
impls: &[ItemImpl],
input: &Ident
input: &Ident,
) -> Result<Vec<(Ident, Ident, TokenStream, Vec<Attribute>)>> {
let mut impl_calls = Vec::new();
@@ -113,12 +115,8 @@ fn generate_impl_calls(
for item in &impl_.items {
if let ImplItem::Method(method) = item {
let impl_call = generate_impl_call(
&method.sig,
&impl_.self_ty,
input,
&impl_trait
)?;
let impl_call =
generate_impl_call(&method.sig, &impl_.self_ty, input, &impl_trait)?;
impl_calls.push((
impl_trait_ident.clone(),
@@ -137,15 +135,16 @@ fn generate_impl_calls(
fn generate_dispatch_function(impls: &[ItemImpl]) -> Result<TokenStream> {
let data = Ident::new("__sp_api__input_data", Span::call_site());
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
let impl_calls = generate_impl_calls(impls, &data)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let name = prefix_function_with_trait(&trait_, &fn_name);
quote!(
#( #attrs )*
#name => Some(#c::Encode::encode(&{ #impl_ })),
)
});
let impl_calls =
generate_impl_calls(impls, &data)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let name = prefix_function_with_trait(&trait_, &fn_name);
quote!(
#( #attrs )*
#name => Some(#c::Encode::encode(&{ #impl_ })),
)
});
Ok(quote!(
#[cfg(feature = "std")]
@@ -163,34 +162,33 @@ fn generate_wasm_interface(impls: &[ItemImpl]) -> Result<TokenStream> {
let input = Ident::new("input", Span::call_site());
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
let impl_calls = generate_impl_calls(impls, &input)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let fn_name = Ident::new(
&prefix_function_with_trait(&trait_, &fn_name),
Span::call_site()
);
let impl_calls =
generate_impl_calls(impls, &input)?
.into_iter()
.map(|(trait_, fn_name, impl_, attrs)| {
let fn_name =
Ident::new(&prefix_function_with_trait(&trait_, &fn_name), Span::call_site());
quote!(
#( #attrs )*
#[cfg(not(feature = "std"))]
#[no_mangle]
pub unsafe fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
let mut #input = if input_len == 0 {
&[0u8; 0]
} else {
unsafe {
#c::slice::from_raw_parts(input_data, input_len)
}
};
quote!(
#( #attrs )*
#[cfg(not(feature = "std"))]
#[no_mangle]
pub unsafe fn #fn_name(input_data: *mut u8, input_len: usize) -> u64 {
let mut #input = if input_len == 0 {
&[0u8; 0]
} else {
unsafe {
#c::slice::from_raw_parts(input_data, input_len)
}
};
#c::init_runtime_logger();
#c::init_runtime_logger();
let output = (move || { #impl_ })();
#c::to_substrate_wasm_fn_return_value(&output)
}
)
});
let output = (move || { #impl_ })();
#c::to_substrate_wasm_fn_return_value(&output)
}
)
});
Ok(quote!( #( #impl_calls )* ))
}
@@ -414,7 +412,6 @@ fn generate_api_impl_for_runtime(impls: &[ItemImpl]) -> Result<TokenStream> {
Ok(quote!( #( #impls_prepared )* ))
}
/// Auxiliary data structure that is used to convert `impl Api for Runtime` to
/// `impl Api for RuntimeApi`.
/// This requires us to replace the runtime `Block` with the node `Block`,
@@ -430,11 +427,8 @@ struct ApiRuntimeImplToApiRuntimeApiImpl<'a> {
impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
fn fold_type_path(&mut self, input: TypePath) -> TypePath {
let new_ty_path = if input == *self.runtime_block {
parse_quote!( __SR_API_BLOCK__ )
} else {
input
};
let new_ty_path =
if input == *self.runtime_block { parse_quote!(__SR_API_BLOCK__) } else { input };
fold::fold_type_path(self, new_ty_path)
}
@@ -451,12 +445,18 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
// Generate the access to the native parameters
let param_tuple_access = if input.sig.inputs.len() == 1 {
vec![ quote!( p ) ]
vec![quote!(p)]
} else {
input.sig.inputs.iter().enumerate().map(|(i, _)| {
let i = syn::Index::from(i);
quote!( p.#i )
}).collect::<Vec<_>>()
input
.sig
.inputs
.iter()
.enumerate()
.map(|(i, _)| {
let i = syn::Index::from(i);
quote!( p.#i )
})
.collect::<Vec<_>>()
};
let (param_types, error) = match extract_parameter_names_types_and_borrows(
@@ -464,12 +464,14 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
AllowSelfRefInParameters::No,
) {
Ok(res) => (
res.into_iter().map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
}).collect::<Vec<_>>(),
None
res.into_iter()
.map(|v| {
let ty = v.1;
let borrow = v.2;
quote!( #borrow #ty )
})
.collect::<Vec<_>>(),
None,
),
Err(e) => (Vec::new(), Some(e.to_compile_error())),
};
@@ -483,10 +485,8 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
params_encoded: Vec<u8>,
};
input.sig.ident = generate_method_runtime_api_impl_name(
&self.impl_trait,
&input.sig.ident,
);
input.sig.ident =
generate_method_runtime_api_impl_name(&self.impl_trait, &input.sig.ident);
let ret_type = return_type_extract_type(&input.sig.output);
// Generate the correct return type.
@@ -544,43 +544,34 @@ impl<'a> Fold for ApiRuntimeImplToApiRuntimeApiImpl<'a> {
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
// Implement the trait for the `RuntimeApiImpl`
input.self_ty = Box::new(
parse_quote!( RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall> )
);
input.self_ty =
Box::new(parse_quote!( RuntimeApiImpl<__SR_API_BLOCK__, RuntimeApiImplCall> ));
input.generics.params.push(parse_quote!(
__SR_API_BLOCK__: #crate_::BlockT + std::panic::UnwindSafe +
std::panic::RefUnwindSafe
));
input.generics.params.push(
parse_quote!(
__SR_API_BLOCK__: #crate_::BlockT + std::panic::UnwindSafe +
std::panic::RefUnwindSafe
)
);
input.generics.params.push(
parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SR_API_BLOCK__> + 'static )
parse_quote!( RuntimeApiImplCall: #crate_::CallApiAt<__SR_API_BLOCK__> + 'static ),
);
let where_clause = input.generics.make_where_clause();
where_clause.predicates.push(
parse_quote! {
RuntimeApiImplCall::StateBackend:
#crate_::StateBackend<#crate_::HashFor<__SR_API_BLOCK__>>
}
);
where_clause.predicates.push(parse_quote! {
RuntimeApiImplCall::StateBackend:
#crate_::StateBackend<#crate_::HashFor<__SR_API_BLOCK__>>
});
// Require that all types used in the function signatures are unwind safe.
extract_all_signature_types(&input.items).iter().for_each(|i| {
where_clause.predicates.push(
parse_quote! {
#i: std::panic::UnwindSafe + std::panic::RefUnwindSafe
}
);
where_clause.predicates.push(parse_quote! {
#i: std::panic::UnwindSafe + std::panic::RefUnwindSafe
});
});
where_clause.predicates.push(
parse_quote! {
__SR_API_BLOCK__::Header: std::panic::UnwindSafe + std::panic::RefUnwindSafe
}
);
where_clause.predicates.push(parse_quote! {
__SR_API_BLOCK__::Header: std::panic::UnwindSafe + std::panic::RefUnwindSafe
});
input.attrs = filter_cfg_attrs(&input.attrs);
@@ -650,14 +641,12 @@ fn generate_runtime_api_versions(impls: &[ItemImpl]) -> Result<TokenStream> {
let span = trait_.span();
if !processed_traits.insert(trait_) {
return Err(
Error::new(
span,
"Two traits with the same name detected! \
return Err(Error::new(
span,
"Two traits with the same name detected! \
The trait name is used to generate its ID. \
Please rename one trait at the declaration!"
)
)
Please rename one trait at the declaration!",
))
}
let id: Path = parse_quote!( #path ID );
@@ -692,7 +681,9 @@ pub fn impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro::Tok
// Parse all impl blocks
let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls);
impl_runtime_apis_impl_inner(&api_impls).unwrap_or_else(|e| e.to_compile_error()).into()
impl_runtime_apis_impl_inner(&api_impls)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
@@ -704,27 +695,25 @@ fn impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
let wasm_interface = generate_wasm_interface(api_impls)?;
let api_impls_for_runtime_api = generate_api_impl_for_runtime_api(api_impls)?;
Ok(
quote!(
#hidden_includes
Ok(quote!(
#hidden_includes
#base_runtime_api
#base_runtime_api
#api_impls_for_runtime
#api_impls_for_runtime
#api_impls_for_runtime_api
#api_impls_for_runtime_api
#runtime_api_versions
#runtime_api_versions
pub mod api {
use super::*;
pub mod api {
use super::*;
#dispatch_impl
#dispatch_impl
#wasm_interface
}
)
)
#wasm_interface
}
))
}
// Filters all attributes except the cfg ones.
@@ -21,9 +21,9 @@
use proc_macro::TokenStream;
mod decl_runtime_apis;
mod impl_runtime_apis;
mod mock_impl_runtime_apis;
mod decl_runtime_apis;
mod utils;
#[proc_macro]
@@ -16,10 +16,10 @@
// limitations under the License.
use crate::utils::{
generate_crate_access, generate_hidden_includes,
generate_method_runtime_api_impl_name, extract_parameter_names_types_and_borrows,
return_type_extract_type, extract_block_type_from_trait_path, extract_impl_trait,
AllowSelfRefInParameters, RequireQualifiedTraitPath,
extract_block_type_from_trait_path, extract_impl_trait,
extract_parameter_names_types_and_borrows, generate_crate_access, generate_hidden_includes,
generate_method_runtime_api_impl_name, return_type_extract_type, AllowSelfRefInParameters,
RequireQualifiedTraitPath,
};
use proc_macro2::{Span, TokenStream};
@@ -27,8 +27,11 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned};
use syn::{
spanned::Spanned, parse_macro_input, Ident, Type, ItemImpl, TypePath, parse_quote,
parse::{Parse, ParseStream, Result, Error}, fold::{self, Fold}, Attribute, Pat,
fold::{self, Fold},
parse::{Error, Parse, ParseStream, Result},
parse_macro_input, parse_quote,
spanned::Spanned,
Attribute, Ident, ItemImpl, Pat, Type, TypePath,
};
/// Unique identifier used to make the hidden includes unique for this macro.
@@ -62,10 +65,7 @@ impl Parse for RuntimeApiImpls {
}
/// Implement the `ApiExt` trait and the `Core` runtime api.
fn implement_common_api_traits(
block_type: TypePath,
self_ty: Type,
) -> Result<TokenStream> {
fn implement_common_api_traits(block_type: TypePath, self_ty: Type) -> Result<TokenStream> {
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
Ok(quote!(
@@ -168,11 +168,13 @@ fn implement_common_api_traits(
/// If the attribute was found, it will be automatically removed from the vec.
fn has_advanced_attribute(attributes: &mut Vec<Attribute>) -> bool {
let mut found = false;
attributes.retain(|attr| if attr.path.is_ident(ADVANCED_ATTRIBUTE) {
found = true;
false
} else {
true
attributes.retain(|attr| {
if attr.path.is_ident(ADVANCED_ATTRIBUTE) {
found = true;
false
} else {
true
}
});
found
@@ -214,7 +216,7 @@ fn get_at_param_name(
let name = param_names.remove(0);
Ok((quote!( #name ), ptype_and_borrows.0))
} else {
Ok((quote!( _ ), default_block_id_type.clone()))
Ok((quote!(_), default_block_id_type.clone()))
}
}
@@ -235,24 +237,27 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> {
let is_advanced = has_advanced_attribute(&mut input.attrs);
let mut errors = Vec::new();
let (mut param_names, mut param_types_and_borrows) = match extract_parameter_names_types_and_borrows(
&input.sig,
AllowSelfRefInParameters::YesButIgnore,
) {
Ok(res) => (
res.iter().map(|v| v.0.clone()).collect::<Vec<_>>(),
res.iter().map(|v| {
let ty = &v.1;
let borrow = &v.2;
(quote_spanned!(ty.span() => #borrow #ty ), v.2.is_some())
}).collect::<Vec<_>>(),
),
Err(e) => {
errors.push(e.to_compile_error());
let (mut param_names, mut param_types_and_borrows) =
match extract_parameter_names_types_and_borrows(
&input.sig,
AllowSelfRefInParameters::YesButIgnore,
) {
Ok(res) => (
res.iter().map(|v| v.0.clone()).collect::<Vec<_>>(),
res.iter()
.map(|v| {
let ty = &v.1;
let borrow = &v.2;
(quote_spanned!(ty.span() => #borrow #ty ), v.2.is_some())
})
.collect::<Vec<_>>(),
),
Err(e) => {
errors.push(e.to_compile_error());
(Default::default(), Default::default())
}
};
(Default::default(), Default::default())
},
};
let block_type = &self.block_type;
let block_id_type = quote!( &#crate_::BlockId<#block_type> );
@@ -267,8 +272,8 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> {
Ok(res) => res,
Err(e) => {
errors.push(e.to_compile_error());
(quote!( _ ), block_id_type)
}
(quote!(_), block_id_type)
},
};
let param_types = param_types_and_borrows.iter().map(|v| &v.0);
@@ -281,10 +286,8 @@ impl<'a> Fold for FoldRuntimeApiImpl<'a> {
_: Vec<u8>,
};
input.sig.ident = generate_method_runtime_api_impl_name(
&self.impl_trait,
&input.sig.ident,
);
input.sig.ident =
generate_method_runtime_api_impl_name(&self.impl_trait, &input.sig.ident);
// When using advanced, the user needs to declare the correct return type on its own,
// otherwise do it for the user.
@@ -360,28 +363,24 @@ fn generate_runtime_api_impls(impls: &[ItemImpl]) -> Result<GeneratedRuntimeApiI
let block_type = extract_block_type_from_trait_path(impl_trait_path)?;
self_ty = match self_ty.take() {
Some(self_ty) => {
Some(self_ty) =>
if self_ty == impl_.self_ty {
Some(self_ty)
} else {
let mut error =Error::new(
let mut error = Error::new(
impl_.self_ty.span(),
"Self type should not change between runtime apis",
);
error.combine(Error::new(
self_ty.span(),
"First self type found here",
));
error.combine(Error::new(self_ty.span(), "First self type found here"));
return Err(error)
}
},
},
None => Some(impl_.self_ty.clone()),
};
global_block_type = match global_block_type.take() {
Some(global_block_type) => {
Some(global_block_type) =>
if global_block_type == *block_type {
Some(global_block_type)
} else {
@@ -396,15 +395,11 @@ fn generate_runtime_api_impls(impls: &[ItemImpl]) -> Result<GeneratedRuntimeApiI
));
return Err(error)
}
},
},
None => Some(block_type.clone()),
};
let mut visitor = FoldRuntimeApiImpl {
block_type,
impl_trait: &impl_trait.ident,
};
let mut visitor = FoldRuntimeApiImpl { block_type, impl_trait: &impl_trait.ident };
result.push(visitor.fold_item_impl(impl_.clone()));
}
@@ -421,7 +416,9 @@ pub fn mock_impl_runtime_apis_impl(input: proc_macro::TokenStream) -> proc_macro
// Parse all impl blocks
let RuntimeApiImpls { impls: api_impls } = parse_macro_input!(input as RuntimeApiImpls);
mock_impl_runtime_apis_impl_inner(&api_impls).unwrap_or_else(|e| e.to_compile_error()).into()
mock_impl_runtime_apis_impl_inner(&api_impls)
.unwrap_or_else(|e| e.to_compile_error())
.into()
}
fn mock_impl_runtime_apis_impl_inner(api_impls: &[ItemImpl]) -> Result<TokenStream> {
@@ -15,11 +15,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use proc_macro2::{TokenStream, Span};
use proc_macro2::{Span, TokenStream};
use syn::{
Result, Ident, Signature, parse_quote, Type, Pat, spanned::Spanned, FnArg, Error, token::And,
ImplItem, ReturnType, PathArguments, Path, GenericArgument, TypePath, ItemImpl,
parse_quote, spanned::Spanned, token::And, Error, FnArg, GenericArgument, Ident, ImplItem,
ItemImpl, Pat, Path, PathArguments, Result, ReturnType, Signature, Type, TypePath,
};
use quote::quote;
@@ -49,18 +49,19 @@ pub fn generate_hidden_includes(unique_id: &'static str) -> TokenStream {
Err(e) => {
let err = Error::new(Span::call_site(), e).to_compile_error();
quote!( #err )
}
},
}
}
/// Generates the access to the `sc_client` crate.
pub fn generate_crate_access(unique_id: &'static str) -> TokenStream {
if env::var("CARGO_PKG_NAME").unwrap() == "sp-api" {
quote!( sp_api )
quote!(sp_api)
} else {
let mod_name = generate_hidden_includes_mod_name(unique_id);
quote!( self::#mod_name::sp_api )
}.into()
}
.into()
}
/// Generates the name of the module that contains the trait declaration for the runtime.
@@ -76,7 +77,7 @@ pub fn generate_method_runtime_api_impl_name(trait_: &Ident, method: &Ident) ->
/// Get the type of a `syn::ReturnType`.
pub fn return_type_extract_type(rt: &ReturnType) -> Type {
match rt {
ReturnType::Default => parse_quote!( () ),
ReturnType::Default => parse_quote!(()),
ReturnType::Type(_, ref ty) => *ty.clone(),
}
}
@@ -84,10 +85,13 @@ pub fn return_type_extract_type(rt: &ReturnType) -> Type {
/// Replace the `_` (wild card) parameter names in the given signature with unique identifiers.
pub fn replace_wild_card_parameter_names(input: &mut Signature) {
let mut generated_pattern_counter = 0;
input.inputs.iter_mut().for_each(|arg| if let FnArg::Typed(arg) = arg {
arg.pat = Box::new(
generate_unique_pattern((*arg.pat).clone(), &mut generated_pattern_counter),
);
input.inputs.iter_mut().for_each(|arg| {
if let FnArg::Typed(arg) = arg {
arg.pat = Box::new(generate_unique_pattern(
(*arg.pat).clone(),
&mut generated_pattern_counter,
));
}
});
}
@@ -101,7 +105,7 @@ pub fn fold_fn_decl_for_client_side(
// Add `&self, at:& BlockId` as parameters to each function at the beginning.
input.inputs.insert(0, parse_quote!( __runtime_api_at_param__: &#block_id ));
input.inputs.insert(0, parse_quote!( &self ));
input.inputs.insert(0, parse_quote!(&self));
// Wrap the output in a `Result`
input.output = {
@@ -114,10 +118,8 @@ pub fn fold_fn_decl_for_client_side(
pub fn generate_unique_pattern(pat: Pat, counter: &mut u32) -> Pat {
match pat {
Pat::Wild(_) => {
let generated_name = Ident::new(
&format!("__runtime_api_generated_name_{}__", counter),
pat.span(),
);
let generated_name =
Ident::new(&format!("__runtime_api_generated_name_{}__", counter), pat.span());
*counter += 1;
parse_quote!( #generated_name )
@@ -145,26 +147,20 @@ pub fn extract_parameter_names_types_and_borrows(
match input {
FnArg::Typed(arg) => {
let (ty, borrow) = match &*arg.ty {
Type::Reference(t) => {
((*t.elem).clone(), Some(t.and_token))
},
t => { (t.clone(), None) },
Type::Reference(t) => ((*t.elem).clone(), Some(t.and_token)),
t => (t.clone(), None),
};
let name = generate_unique_pattern(
(*arg.pat).clone(),
&mut generated_pattern_counter,
);
let name =
generate_unique_pattern((*arg.pat).clone(), &mut generated_pattern_counter);
result.push((name, ty, borrow));
},
FnArg::Receiver(_) if matches!(allow_self, AllowSelfRefInParameters::No) => {
return Err(Error::new(input.span(), "`self` parameter not supported!"))
},
FnArg::Receiver(recv) => {
FnArg::Receiver(_) if matches!(allow_self, AllowSelfRefInParameters::No) =>
return Err(Error::new(input.span(), "`self` parameter not supported!")),
FnArg::Receiver(recv) =>
if recv.mutability.is_some() || recv.reference.is_none() {
return Err(Error::new(recv.span(), "Only `&self` is supported!"))
}
},
},
}
}
@@ -190,7 +186,8 @@ pub fn prefix_function_with_trait<F: ToString>(trait_: &Ident, function: &F) ->
///
/// If a type is a reference, the inner type is extracted (without the reference).
pub fn extract_all_signature_types(items: &[ImplItem]) -> Vec<Type> {
items.iter()
items
.iter()
.filter_map(|i| match i {
ImplItem::Method(method) => Some(&method.sig),
_ => None,
@@ -201,13 +198,17 @@ pub fn extract_all_signature_types(items: &[ImplItem]) -> Vec<Type> {
ReturnType::Type(_, ty) => Some((**ty).clone()),
};
sig.inputs.iter().filter_map(|i| match i {
FnArg::Typed(arg) => Some(&arg.ty),
_ => None,
}).map(|ty| match &**ty {
Type::Reference(t) => (*t.elem).clone(),
_ => (**ty).clone(),
}).chain(ret_ty)
sig.inputs
.iter()
.filter_map(|i| match i {
FnArg::Typed(arg) => Some(&arg.ty),
_ => None,
})
.map(|ty| match &**ty {
Type::Reference(t) => (*t.elem).clone(),
_ => (**ty).clone(),
})
.chain(ret_ty)
})
.collect()
}
@@ -223,19 +224,20 @@ pub fn extract_block_type_from_trait_path(trait_: &Path) -> Result<&TypePath> {
.ok_or_else(|| Error::new(span, "Empty path not supported"))?;
match &generics.arguments {
PathArguments::AngleBracketed(ref args) => {
args.args.first().and_then(|v| match v {
PathArguments::AngleBracketed(ref args) => args
.args
.first()
.and_then(|v| match v {
GenericArgument::Type(Type::Path(ref block)) => Some(block),
_ => None
}).ok_or_else(|| Error::new(args.span(), "Missing `Block` generic parameter."))
},
_ => None,
})
.ok_or_else(|| Error::new(args.span(), "Missing `Block` generic parameter.")),
PathArguments::None => {
let span = trait_.segments.last().as_ref().unwrap().span();
Err(Error::new(span, "Missing `Block` generic parameter."))
},
PathArguments::Parenthesized(_) => {
Err(Error::new(generics.arguments.span(), "Unexpected parentheses in path!"))
},
PathArguments::Parenthesized(_) =>
Err(Error::new(generics.arguments.span(), "Unexpected parentheses in path!")),
}
}
@@ -252,19 +254,20 @@ pub fn extract_impl_trait<'a>(
impl_: &'a ItemImpl,
require: RequireQualifiedTraitPath,
) -> Result<&'a Path> {
impl_.trait_.as_ref().map(|v| &v.1).ok_or_else(
|| Error::new(impl_.span(), "Only implementation of traits are supported!")
).and_then(|p| {
if p.segments.len() > 1 || matches!(require, RequireQualifiedTraitPath::No) {
Ok(p)
} else {
Err(
Error::new(
impl_
.trait_
.as_ref()
.map(|v| &v.1)
.ok_or_else(|| Error::new(impl_.span(), "Only implementation of traits are supported!"))
.and_then(|p| {
if p.segments.len() > 1 || matches!(require, RequireQualifiedTraitPath::No) {
Ok(p)
} else {
Err(Error::new(
p.span(),
"The implemented trait has to be referenced with a path, \
e.g. `impl client::Core for Runtime`."
)
)
}
})
e.g. `impl client::Core for Runtime`.",
))
}
})
}