Don't panic if parameter can not be converted between node and native runtime (#1659)

* Don't panic if parameter can not be converted between node and native runtime

* FIxes after merge

* Use correct copyright year
This commit is contained in:
Bastian Köcher
2019-02-02 14:13:50 +01:00
committed by Gav Wood
parent 4983f113e6
commit ef4dc12a5d
21 changed files with 216 additions and 67 deletions
@@ -17,7 +17,7 @@
use utils::{
generate_crate_access, generate_hidden_includes, generate_runtime_mod_name_for_trait,
fold_fn_decl_for_client_side, unwrap_or_error, extract_parameter_names_types_and_borrows,
generate_native_call_generator_fn_name
generate_native_call_generator_fn_name, return_type_extract_type,
};
use proc_macro;
@@ -157,12 +157,15 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result<TokenStream> {
// Auxilariy function that is used to convert between types that use different block types.
// The function expects that both a convertable by encoding the one and decoding the other.
result.push(quote!(
#[cfg(any(feature = "std", test))]
fn convert_between_block_types
<I: #crate_::runtime_api::Encode, R: #crate_::runtime_api::Decode>(input: &I) -> R
<I: #crate_::runtime_api::Encode, R: #crate_::runtime_api::Decode>(
input: &I, error_desc: &'static str,
) -> ::std::result::Result<R, &'static str>
{
<R as #crate_::runtime_api::Decode>::decode(
&mut &#crate_::runtime_api::Encode::encode(input)[..]
).unwrap()
).ok_or_else(|| error_desc)
}
));
@@ -172,20 +175,30 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result<TokenStream> {
let trait_fn_name = &fn_.ident;
let fn_name = generate_native_call_generator_fn_name(&fn_.ident);
let output = return_type_replace_block_with_node_block(fn_.decl.output.clone());
let output_ty = return_type_extract_type(&output);
let output = quote!( ::std::result::Result<#output_ty, &'static str> );
// Every type that is using the `Block` generic parameter, we need to encode/decode,
// to make it compatible between the runtime/node.
let conversions = params.iter().filter(|v| type_is_using_block(&v.1)).map(|(n, t, _)| {
let name_str = format!(
"Could not convert parameter `{}` between node and runtime!", quote!(#n)
);
quote!(
let #n: #t = convert_between_block_types(&#n);
let #n: #t = convert_between_block_types(&#n, #name_str)?;
)
});
// Same as for the input types, we need to check if we also need to convert the output,
// before returning it.
let output_conversion = if return_type_is_using_block(&fn_.decl.output) {
quote!( convert_between_block_types(&res) )
quote!(
convert_between_block_types(
&res,
"Could not convert return value from runtime to node!"
)
)
} else {
quote!( res )
quote!( Ok(res) )
};
let input_names = params.iter().map(|v| &v.0);
@@ -240,7 +253,7 @@ fn generate_native_call_generators(decl: &ItemTrait) -> Result<TokenStream> {
#(, #impl_generics_params)*
>(
#( #fn_inputs ),*
) -> impl FnOnce() #output + 'a #where_clause {
) -> impl FnOnce() -> #output + 'a #where_clause {
move || {
#( #conversions )*
let res = ApiImpl::#trait_fn_name(#( #input_borrows #input_names ),*);
@@ -330,7 +330,7 @@ fn generate_runtime_api_base_structures(impls: &[ItemImpl]) -> Result<TokenStrea
impl<C: #crate_::runtime_api::CallRuntimeAt<#block>> RuntimeApiImpl<C> {
fn call_api_at<
R: #crate_::runtime_api::Encode + #crate_::runtime_api::Decode + PartialEq,
NC: FnOnce() -> R + ::std::panic::UnwindSafe,
NC: FnOnce() -> ::std::result::Result<R, &'static str> + ::std::panic::UnwindSafe,
>(
&self,
at: &#block_id,
+1 -1
View File
@@ -16,7 +16,7 @@
//! Macros for declaring and implementing runtime apis.
#![recursion_limit = "256"]
#![recursion_limit = "512"]
extern crate proc_macro;
extern crate proc_macro2;
extern crate quote;
+10 -8
View File
@@ -58,6 +58,14 @@ pub fn generate_runtime_mod_name_for_trait(trait_: &Ident) -> Ident {
Ident::new(&format!("runtime_decl_for_{}", trait_.to_string()), Span::call_site())
}
/// Get the type of a `syn::ReturnType`.
pub fn return_type_extract_type(rt: &syn::ReturnType) -> Type {
match rt {
syn::ReturnType::Default => parse_quote!( () ),
syn::ReturnType::Type(_, ref ty) => *ty.clone(),
}
}
/// Fold the given `FnDecl` to make it usable on the client side.
pub fn fold_fn_decl_for_client_side(
mut input: FnDecl,
@@ -70,14 +78,8 @@ pub fn fold_fn_decl_for_client_side(
// Wrap the output in a `Result`
input.output = {
let generate_result = |ty: &Type| {
parse_quote!( -> ::std::result::Result<#ty, #crate_::error::Error> )
};
match &input.output {
syn::ReturnType::Default => generate_result(&parse_quote!( () )),
syn::ReturnType::Type(_, ref ty) => generate_result(&ty),
}
let ty = return_type_extract_type(&input.output);
parse_quote!( -> ::std::result::Result<#ty, #crate_::error::Error> )
};
input