mirror of
https://github.com/fluencelabs/marine-rs-sdk-test
synced 2025-03-15 12:40:50 +00:00
Merge pull request #33 from fluencelabs/fce_test_tetraplets
Support CallParameters in generated by fce_test functions
This commit is contained in:
commit
8bc484d2be
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fluence-sdk-test-macro-impl"
|
name = "fluence-sdk-test-macro-impl"
|
||||||
version = "0.1.4" # remember to update html_root_url
|
version = "0.1.5" # remember to update html_root_url
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Implementation of the `#[fce_test]` macro"
|
description = "Implementation of the `#[fce_test]` macro"
|
||||||
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro-test"
|
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro-test"
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
mod methods_generator;
|
mod methods_generator;
|
||||||
|
mod methods_generator_utils;
|
||||||
mod record_type_generator;
|
mod record_type_generator;
|
||||||
|
|
||||||
use crate::fce_test::utils;
|
use crate::fce_test::utils;
|
||||||
|
@ -14,149 +14,30 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::fce_test::utils;
|
use super::methods_generator_utils::*;
|
||||||
use crate::TResult;
|
use crate::TResult;
|
||||||
use crate::TestGeneratorError;
|
|
||||||
|
|
||||||
use fce_wit_parser::interface::it::IType;
|
|
||||||
use fce_wit_parser::interface::it::IFunctionArg;
|
|
||||||
use fce_wit_parser::interface::FCERecordTypes;
|
use fce_wit_parser::interface::FCERecordTypes;
|
||||||
use fce_wit_parser::interface::FCEFunctionSignature;
|
use fce_wit_parser::interface::FCEFunctionSignature;
|
||||||
|
|
||||||
use proc_macro2::TokenStream;
|
|
||||||
use quote::quote;
|
|
||||||
|
|
||||||
pub(super) fn generate_module_methods<'m, 'r>(
|
pub(super) fn generate_module_methods<'m, 'r>(
|
||||||
module_name: &str,
|
module_name: &str,
|
||||||
method_signatures: impl ExactSizeIterator<Item = &'m FCEFunctionSignature>,
|
mut method_signatures: impl ExactSizeIterator<Item = &'m FCEFunctionSignature>,
|
||||||
records: &'r FCERecordTypes,
|
records: &'r FCERecordTypes,
|
||||||
) -> TResult<Vec<TokenStream>> {
|
) -> TResult<Vec<proc_macro2::TokenStream>> {
|
||||||
method_signatures
|
use CallParametersSettings::*;
|
||||||
.map(|signature| -> TResult<_> {
|
|
||||||
let func_name = utils::new_ident(&signature.name)?;
|
|
||||||
let arguments = generate_arguments(signature.arguments.iter(), records)?;
|
|
||||||
let output_type = generate_output_type(&signature.outputs, records)?;
|
|
||||||
let fce_call = generate_fce_call(module_name, &signature, records)?;
|
|
||||||
|
|
||||||
let module_method = quote! {
|
let methods_count = 2 * method_signatures.len();
|
||||||
pub fn #func_name(&mut self, #(#arguments),*) #output_type {
|
method_signatures.try_fold::<_, _, TResult<_>>(
|
||||||
#fce_call
|
Vec::with_capacity(methods_count),
|
||||||
}
|
|mut methods, signature| {
|
||||||
};
|
let default_cp = generate_module_method(module_name, &signature, Default, records)?;
|
||||||
|
let user_cp = generate_module_method(module_name, &signature, UserDefined, records)?;
|
||||||
|
|
||||||
Ok(module_method)
|
methods.push(default_cp);
|
||||||
})
|
methods.push(user_cp);
|
||||||
.collect::<TResult<Vec<_>>>()
|
|
||||||
}
|
Ok(methods)
|
||||||
|
},
|
||||||
fn generate_fce_call(
|
)
|
||||||
module_name: &str,
|
|
||||||
method_signature: &FCEFunctionSignature,
|
|
||||||
records: &FCERecordTypes,
|
|
||||||
) -> TResult<TokenStream> {
|
|
||||||
let args = method_signature.arguments.iter().map(|a| a.name.as_str());
|
|
||||||
let convert_arguments = generate_arguments_converter(args)?;
|
|
||||||
|
|
||||||
let output_type = get_output_type(&method_signature.outputs)?;
|
|
||||||
let set_result = generate_set_result(&output_type);
|
|
||||||
let function_call = generate_function_call(module_name, &method_signature.name);
|
|
||||||
let convert_result_to_output_type = generate_convert_to_output(&output_type, records)?;
|
|
||||||
let ret = generate_ret(&output_type);
|
|
||||||
|
|
||||||
let function_call = quote! {
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
#convert_arguments
|
|
||||||
|
|
||||||
#set_result #function_call
|
|
||||||
|
|
||||||
#convert_result_to_output_type
|
|
||||||
|
|
||||||
#ret
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(function_call)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates type convertor to json because of AppService receives them in json.
|
|
||||||
fn generate_arguments_converter<'a>(
|
|
||||||
args: impl ExactSizeIterator<Item = &'a str>,
|
|
||||||
) -> TResult<TokenStream> {
|
|
||||||
let arg_idents: Vec<syn::Ident> = args.map(utils::new_ident).collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
let args_converter =
|
|
||||||
quote! { let arguments = fluence_test::internal::serde_json::json!([#(#arg_idents),*]); };
|
|
||||||
|
|
||||||
Ok(args_converter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_function_call(module_name: &str, method_name: &str) -> TokenStream {
|
|
||||||
quote! { self.fce.as_ref().borrow_mut().call_module(#module_name, #method_name, arguments, <_>::default()).expect("call to FCE failed"); }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_set_result(output_type: &Option<&IType>) -> TokenStream {
|
|
||||||
match output_type {
|
|
||||||
Some(_) => quote! { let result = },
|
|
||||||
None => TokenStream::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_convert_to_output(
|
|
||||||
output_type: &Option<&IType>,
|
|
||||||
records: &FCERecordTypes,
|
|
||||||
) -> TResult<TokenStream> {
|
|
||||||
let result_stream = match output_type {
|
|
||||||
Some(ty) => {
|
|
||||||
let ty = utils::itype_to_tokens(ty, records)?;
|
|
||||||
quote! {
|
|
||||||
let result: #ty = fluence_test::internal::serde_json::from_value(result).expect("the default deserializer shouldn't fail");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => TokenStream::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(result_stream)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_ret(output_type: &Option<&IType>) -> TokenStream {
|
|
||||||
match output_type {
|
|
||||||
Some(_) => quote! { result },
|
|
||||||
None => TokenStream::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_arguments<'a, 'r>(
|
|
||||||
arguments: impl ExactSizeIterator<Item = &'a IFunctionArg>,
|
|
||||||
records: &'r FCERecordTypes,
|
|
||||||
) -> TResult<Vec<TokenStream>> {
|
|
||||||
arguments
|
|
||||||
.map(|argument| -> TResult<_> {
|
|
||||||
let arg_name = utils::new_ident(&argument.name)?;
|
|
||||||
let arg_type = utils::itype_to_tokens(&argument.ty, records)?;
|
|
||||||
|
|
||||||
let arg = quote! { #arg_name: #arg_type };
|
|
||||||
Ok(arg)
|
|
||||||
})
|
|
||||||
.collect::<TResult<Vec<_>>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TResult<TokenStream> {
|
|
||||||
let output_type = get_output_type(output_types)?;
|
|
||||||
match output_type {
|
|
||||||
None => Ok(TokenStream::new()),
|
|
||||||
Some(ty) => {
|
|
||||||
let output_type = utils::itype_to_tokens(&ty, records)?;
|
|
||||||
let output_type = quote! { -> #output_type };
|
|
||||||
|
|
||||||
Ok(output_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_output_type(output_types: &[IType]) -> TResult<Option<&IType>> {
|
|
||||||
match output_types.len() {
|
|
||||||
0 => Ok(None),
|
|
||||||
1 => Ok(Some(&output_types[0])),
|
|
||||||
_ => Err(TestGeneratorError::ManyFnOutputsUnsupported),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::fce_test::utils::new_ident;
|
||||||
|
use crate::fce_test::utils::itype_to_tokens;
|
||||||
|
use crate::TResult;
|
||||||
|
|
||||||
|
use fce_wit_parser::interface::it::IType;
|
||||||
|
use fce_wit_parser::interface::it::IFunctionArg;
|
||||||
|
use fce_wit_parser::interface::FCERecordTypes;
|
||||||
|
use fce_wit_parser::interface::FCEFunctionSignature;
|
||||||
|
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(super) enum CallParametersSettings {
|
||||||
|
Default,
|
||||||
|
UserDefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn generate_module_method(
|
||||||
|
module_name: &str,
|
||||||
|
signature: &FCEFunctionSignature,
|
||||||
|
cp_setting: CallParametersSettings,
|
||||||
|
records: &FCERecordTypes,
|
||||||
|
) -> TResult<TokenStream> {
|
||||||
|
let arguments = generate_arguments(signature.arguments.iter(), records)?;
|
||||||
|
let output_type = generate_output_type(&signature.outputs, records)?;
|
||||||
|
let fce_call = generate_fce_call(module_name, cp_setting, &signature, records)?;
|
||||||
|
|
||||||
|
let (cp, func_name) = match cp_setting {
|
||||||
|
CallParametersSettings::Default => {
|
||||||
|
let func_name = new_ident(&signature.name)?;
|
||||||
|
(TokenStream::new(), func_name)
|
||||||
|
}
|
||||||
|
CallParametersSettings::UserDefined => {
|
||||||
|
let maybe_comma = if signature.arguments.is_empty() {
|
||||||
|
TokenStream::new()
|
||||||
|
} else {
|
||||||
|
quote! { , }
|
||||||
|
};
|
||||||
|
|
||||||
|
let cp = quote! { #maybe_comma cp: fluence_test::CallParameters };
|
||||||
|
let func_name = format!("{}_cp", signature.name);
|
||||||
|
let func_name = new_ident(&func_name)?;
|
||||||
|
(cp, func_name)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let module_method = quote! {
|
||||||
|
pub fn #func_name(&mut self, #(#arguments),* #cp) #output_type {
|
||||||
|
#fce_call
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(module_method)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_fce_call(
|
||||||
|
module_name: &str,
|
||||||
|
cp_settings: CallParametersSettings,
|
||||||
|
method_signature: &FCEFunctionSignature,
|
||||||
|
records: &FCERecordTypes,
|
||||||
|
) -> TResult<TokenStream> {
|
||||||
|
let args = method_signature.arguments.iter().map(|a| a.name.as_str());
|
||||||
|
let convert_arguments = generate_arguments_converter(args)?;
|
||||||
|
|
||||||
|
let output_type = get_output_type(&method_signature.outputs)?;
|
||||||
|
let set_result = generate_set_result(&output_type);
|
||||||
|
let function_call = generate_function_call(module_name, &method_signature.name, cp_settings);
|
||||||
|
let convert_result_to_output_type = generate_convert_to_output(&output_type, records)?;
|
||||||
|
let ret = generate_ret(&output_type);
|
||||||
|
|
||||||
|
let function_call = quote! {
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
|
#convert_arguments
|
||||||
|
|
||||||
|
#set_result #function_call
|
||||||
|
|
||||||
|
#convert_result_to_output_type
|
||||||
|
|
||||||
|
#ret
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(function_call)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates type convertor to json because of AppService receives them in json.
|
||||||
|
fn generate_arguments_converter<'a>(
|
||||||
|
args: impl ExactSizeIterator<Item = &'a str>,
|
||||||
|
) -> TResult<TokenStream> {
|
||||||
|
let arg_idents: Vec<syn::Ident> = args.map(new_ident).collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
|
let args_converter =
|
||||||
|
quote! { let arguments = fluence_test::internal::serde_json::json!([#(#arg_idents),*]); };
|
||||||
|
|
||||||
|
Ok(args_converter)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_function_call(
|
||||||
|
module_name: &str,
|
||||||
|
method_name: &str,
|
||||||
|
cp_setting: CallParametersSettings,
|
||||||
|
) -> TokenStream {
|
||||||
|
let cp = match cp_setting {
|
||||||
|
CallParametersSettings::Default => quote! { <_>::default() },
|
||||||
|
CallParametersSettings::UserDefined => quote! { cp },
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! { self.fce.as_ref().borrow_mut().call_module(#module_name, #method_name, arguments, #cp).expect("call to Marine failed"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_set_result(output_type: &Option<&IType>) -> TokenStream {
|
||||||
|
match output_type {
|
||||||
|
Some(_) => quote! { let result = },
|
||||||
|
None => TokenStream::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_convert_to_output(
|
||||||
|
output_type: &Option<&IType>,
|
||||||
|
records: &FCERecordTypes,
|
||||||
|
) -> TResult<TokenStream> {
|
||||||
|
let result_stream = match output_type {
|
||||||
|
Some(ty) => {
|
||||||
|
let ty = itype_to_tokens(ty, records)?;
|
||||||
|
quote! {
|
||||||
|
let result: #ty = fluence_test::internal::serde_json::from_value(result).expect("the default deserializer shouldn't fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => TokenStream::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result_stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_ret(output_type: &Option<&IType>) -> TokenStream {
|
||||||
|
match output_type {
|
||||||
|
Some(_) => quote! { result },
|
||||||
|
None => TokenStream::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_arguments<'a, 'r>(
|
||||||
|
arguments: impl ExactSizeIterator<Item = &'a IFunctionArg>,
|
||||||
|
records: &'r FCERecordTypes,
|
||||||
|
) -> TResult<Vec<TokenStream>> {
|
||||||
|
arguments
|
||||||
|
.map(|argument| -> TResult<_> {
|
||||||
|
let arg_name = new_ident(&argument.name)?;
|
||||||
|
let arg_type = itype_to_tokens(&argument.ty, records)?;
|
||||||
|
|
||||||
|
let arg = quote! { #arg_name: #arg_type };
|
||||||
|
Ok(arg)
|
||||||
|
})
|
||||||
|
.collect::<TResult<Vec<_>>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TResult<TokenStream> {
|
||||||
|
let output_type = get_output_type(output_types)?;
|
||||||
|
match output_type {
|
||||||
|
None => Ok(TokenStream::new()),
|
||||||
|
Some(ty) => {
|
||||||
|
let output_type = itype_to_tokens(&ty, records)?;
|
||||||
|
let output_type = quote! { -> #output_type };
|
||||||
|
|
||||||
|
Ok(output_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_output_type(output_types: &[IType]) -> TResult<Option<&IType>> {
|
||||||
|
use crate::TestGeneratorError::ManyFnOutputsUnsupported;
|
||||||
|
|
||||||
|
match output_types.len() {
|
||||||
|
0 => Ok(None),
|
||||||
|
1 => Ok(Some(&output_types[0])),
|
||||||
|
_ => Err(ManyFnOutputsUnsupported),
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fluence-sdk-test-macro"
|
name = "fluence-sdk-test-macro"
|
||||||
version = "0.1.4" # remember to update html_root_url
|
version = "0.1.5" # remember to update html_root_url
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Definition of the `#[fce_test]` macro"
|
description = "Definition of the `#[fce_test]` macro"
|
||||||
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro-test"
|
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro-test"
|
||||||
@ -17,7 +17,7 @@ proc-macro = true
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fluence-sdk-test-macro-impl = { path = "../fce-test-macro-impl", version = "0.1.4" }
|
fluence-sdk-test-macro-impl = { path = "../fce-test-macro-impl", version = "0.1.5" }
|
||||||
|
|
||||||
quote = "1.0.9"
|
quote = "1.0.9"
|
||||||
proc-macro2 = "1.0.24"
|
proc-macro2 = "1.0.24"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fluence-test"
|
name = "fluence-test"
|
||||||
version = "0.1.4" # remember to update html_root_url
|
version = "0.1.5" # remember to update html_root_url
|
||||||
description = "Fluence backend SDK for testing"
|
description = "Fluence backend SDK for testing"
|
||||||
documentation = "https://docs.rs/fluence/"
|
documentation = "https://docs.rs/fluence/"
|
||||||
repository = "https://github.com/fluencelabs/rust-sdk"
|
repository = "https://github.com/fluencelabs/rust-sdk"
|
||||||
@ -19,7 +19,7 @@ path = "src/lib.rs"
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fluence-sdk-test-macro = { path = "../crates/fce-test-macro", version = "0.1.4" }
|
fluence-sdk-test-macro = { path = "../crates/fce-test-macro", version = "0.1.5" }
|
||||||
fluence-app-service = { version = "0.7.0", features = ["raw-module-api"] }
|
fluence-app-service = { version = "0.7.0", features = ["raw-module-api"] }
|
||||||
|
|
||||||
serde = { version = "1.0.118", features = ["derive"] }
|
serde = { version = "1.0.118", features = ["derive"] }
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#![warn(rust_2018_idioms)]
|
#![warn(rust_2018_idioms)]
|
||||||
|
|
||||||
pub use fluence_sdk_test_macro::fce_test;
|
pub use fluence_sdk_test_macro::fce_test;
|
||||||
|
pub use fluence_app_service::CallParameters;
|
||||||
|
pub use fluence_app_service::SecurityTetraplet;
|
||||||
|
|
||||||
/// These API functions are intended for internal usage in generated code.
|
/// These API functions are intended for internal usage in generated code.
|
||||||
/// Normally, you shouldn't use them.
|
/// Normally, you shouldn't use them.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user