// Copyright 2018-2020 Parity Technologies (UK) Ltd.
// This file is part of Substrate.
// Substrate is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Substrate is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Substrate. If not, see .
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,
};
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,
};
use std::{collections::HashSet, iter};
/// Unique identifier used to make the hidden includes unique for this macro.
const HIDDEN_INCLUDES_ID: &str = "IMPL_RUNTIME_APIS";
/// The structure used for parsing the runtime api implementations.
struct RuntimeApiImpls {
impls: Vec,
}
impl Parse for RuntimeApiImpls {
fn parse(input: ParseStream) -> Result {
let mut impls = Vec::new();
while !input.is_empty() {
impls.push(ItemImpl::parse(input)?);
}
if impls.is_empty() {
Err(Error::new(Span::call_site(), "No api implementation given!"))
} else {
Ok(Self { impls })
}
}
}
/// Generates the call to the implementation of the requested function.
/// The generated code includes decoding of the input arguments and encoding of the output.
fn generate_impl_call(
signature: &Signature,
runtime: &Type,
input: &Ident,
impl_trait: &Path
) -> Result {
let params = extract_parameter_names_types_and_borrows(signature, AllowSelfRefInParameters::No)?;
let c = generate_crate_access(HIDDEN_INCLUDES_ID);
let c_iter = iter::repeat(&c);
let fn_name = &signature.ident;
let fn_name_str = iter::repeat(fn_name.to_string());
let input = iter::repeat(input);
let pnames = params.iter().map(|v| &v.0);
let pnames2 = params.iter().map(|v| &v.0);
let ptypes = params.iter().map(|v| &v.1);
let pborrow = params.iter().map(|v| &v.2);
Ok(
quote!(
#(
let #pnames : #ptypes = match #c_iter::Decode::decode(&mut #input) {
Ok(input) => input,
Err(e) => panic!("Bad input data provided to {}: {}", #fn_name_str, e.what()),
};
)*
#[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
) -> Result)>> {
let mut impl_calls = Vec::new();
for impl_ in impls {
let impl_trait_path = extract_impl_trait(impl_, RequireQualifiedTraitPath::Yes)?;
let impl_trait = extend_with_runtime_decl_path(impl_trait_path.clone());
let impl_trait_ident = &impl_trait_path
.segments
.last()
.ok_or_else(|| Error::new(impl_trait_path.span(), "Empty trait path not possible!"))?
.ident;
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
)?;
impl_calls.push((
impl_trait_ident.clone(),
method.sig.ident.clone(),
impl_call,
filter_cfg_attrs(&impl_.attrs),
));
}
}
}
Ok(impl_calls)
}
/// Generate the dispatch function that is used in native to call into the runtime.
fn generate_dispatch_function(impls: &[ItemImpl]) -> Result {
let data = Ident::new("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_ })),
)
});
Ok(quote!(
#[cfg(feature = "std")]
pub fn dispatch(method: &str, mut #data: &[u8]) -> Option> {
match method {
#( #impl_calls )*
_ => None,
}
}
))
}
/// Generate the interface functions that are used to call into the runtime in wasm.
fn generate_wasm_interface(impls: &[ItemImpl]) -> Result {
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()
);
quote!(
#( #attrs )*
#[cfg(not(feature = "std"))]
#[no_mangle]
pub 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)
}
};
let output = { #impl_ };
#c::to_substrate_wasm_fn_return_value(&output)
}
)
});
Ok(quote!( #( #impl_calls )* ))
}
fn generate_runtime_api_base_structures() -> Result {
let crate_ = generate_crate_access(HIDDEN_INCLUDES_ID);
Ok(quote!(
pub struct RuntimeApi {}
/// Implements all runtime apis for the client side.
#[cfg(any(feature = "std", test))]
pub struct RuntimeApiImpl + 'static>
where
// Rust bug: https://github.com/rust-lang/rust/issues/24159
C::StateBackend: #crate_::StateBackend<#crate_::HashFor>,
{
call: &'static C,
commit_on_success: std::cell::RefCell,
initialized_block: std::cell::RefCell