mirror of
https://github.com/fluencelabs/marine-rs-sdk-test
synced 2024-12-04 15:20:18 +00:00
Merge branch 'master' into support_references
This commit is contained in:
commit
ea11a617cd
@ -12,16 +12,20 @@ jobs:
|
||||
keys:
|
||||
- backendsdk01-{{ checksum "Cargo.toml" }}
|
||||
- run: | #TODO: enable 'stable' and 'beta' once `allocator_api` becomes stable
|
||||
rustup toolchain install nightly-2020-04-20
|
||||
rustup default nightly-2020-04-20
|
||||
rustup override set nightly-2020-04-20
|
||||
rustup target add wasm32-unknown-unknown
|
||||
rustup toolchain install nightly-2021-02-27
|
||||
rustup default nightly-2021-02-27
|
||||
rustup override set nightly-2021-02-27
|
||||
rustup target add wasm32-wasi
|
||||
rustup component add rustfmt
|
||||
rustup component add clippy
|
||||
cargo fmt --all -- --check --color always
|
||||
cargo build -v --target wasm32-unknown-unknown --all-features
|
||||
|
||||
(cd fluence; cargo build -v --target wasm32-wasi --all-features)
|
||||
(cd fluence; cargo clippy -v --target wasm32-wasi)
|
||||
(cd fluence-test; cargo build)
|
||||
|
||||
cargo test -v --all-features
|
||||
cargo clippy -v --target wasm32-unknown-unknown
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.cargo
|
||||
|
38
Cargo.toml
38
Cargo.toml
@ -1,38 +1,10 @@
|
||||
[package]
|
||||
name = "fluence"
|
||||
version = "0.5.0" # remember to update html_root_url
|
||||
description = "Fluence backend SDK for developing backend applications for the Fluence network"
|
||||
documentation = "https://docs.rs/fluence/"
|
||||
repository = "https://github.com/fluencelabs/rust-sdk"
|
||||
authors = ["Fluence Labs"]
|
||||
readme = "README.md"
|
||||
keywords = ["fluence", "sdk", "webassembly"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata.docs.rs] # https://docs.rs/about
|
||||
all-features = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
name = "fluence"
|
||||
|
||||
[dependencies]
|
||||
fluence-sdk-macro = { path = "crates/macro", version = "=0.5.0" }
|
||||
fluence-sdk-main = { path = "crates/main", version = "=0.5.0" }
|
||||
serde = "=1.0.118"
|
||||
|
||||
[features]
|
||||
# Print some internal logs by log_utf8_string
|
||||
debug = ["fluence-sdk-main/debug"]
|
||||
|
||||
# Enable logger (this will cause log_utf8_string to appear in imports)
|
||||
logger = ["fluence-sdk-main/logger"]
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/fce-macro",
|
||||
"crates/fce-test-macro",
|
||||
"crates/fce-test-macro-impl",
|
||||
"crates/main",
|
||||
"crates/macro",
|
||||
"crates/wit",
|
||||
"fluence",
|
||||
"fluence-test"
|
||||
]
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "fluence-sdk-macro"
|
||||
version = "0.5.0" # remember to update html_root_url
|
||||
edition = "2018"
|
||||
description = "Definition of `#[invoke_handler]` attribute"
|
||||
description = "Definition of the `#[fce]` macro"
|
||||
documentation = "https://docs.rs/fluence/fluence-sdk-macro"
|
||||
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro"
|
||||
authors = ["Fluence Labs"]
|
||||
@ -10,11 +10,12 @@ keywords = ["fluence", "sdk", "webassembly", "procedural_macros"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
[package.metadata.docs.rs] # https://docs.rs/about
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fluence-sdk-wit = { path = "../wit", version = "=0.5.0" }
|
@ -23,7 +23,7 @@
|
||||
//! # Examples
|
||||
//!
|
||||
//! This example shows how a function could be exported:
|
||||
//! ```
|
||||
//! ```ignore
|
||||
//! #[fce]
|
||||
//! pub fn greeting(name: String) -> String {
|
||||
//! format!("Hi {}", name)
|
||||
@ -33,23 +33,19 @@
|
||||
//! This more complex example shows how a function could be imported from another Wasm module
|
||||
//! and how a struct could be passed:
|
||||
//!
|
||||
//! ```
|
||||
//! #[fce]
|
||||
//! struct HostReturnValue {
|
||||
//! pub error_code: i32,
|
||||
//! pub outcome: Vec<u8>
|
||||
//! }
|
||||
//! ```ignore
|
||||
//! use fluence::MountedBinaryResult;
|
||||
//!
|
||||
//! #[fce]
|
||||
//! pub fn read_ipfs_file(file_path: String) -> HostReturnValue {
|
||||
//! pub fn read_ipfs_file(file_path: String) -> MountedBinaryResult {
|
||||
//! let hash = calculate_hash(file_path);
|
||||
//! ipfs(hash)
|
||||
//! ipfs(vec![hash])
|
||||
//! }
|
||||
//!
|
||||
//! #[fce]
|
||||
//! #[link(wasm_import_module = "ipfs_node.wasm")]
|
||||
//! #[link(wasm_import_module = "ipfs_node")]
|
||||
//! extern "C" {
|
||||
//! pub fn ipfs(file_hash: String) -> HostReturnValue;
|
||||
//! pub fn ipfs(file_hash: Vec<String>) -> MountedBinaryResult;
|
||||
//! }
|
||||
//!
|
||||
//! ```
|
24
crates/fce-test-macro-impl/Cargo.toml
Normal file
24
crates/fce-test-macro-impl/Cargo.toml
Normal file
@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "fluence-sdk-test-macro-impl"
|
||||
version = "0.5.0" # remember to update html_root_url
|
||||
edition = "2018"
|
||||
description = "Implementation of the `#[fce_test]` macro"
|
||||
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro-test"
|
||||
authors = ["Fluence Labs"]
|
||||
keywords = ["fluence", "sdk", "webassembly", "procedural_macros"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[dependencies]
|
||||
fluence-app-service = { version = "0.5.2", features = ["raw-module-api"] }
|
||||
fce-wit-parser = "0.4.0"
|
||||
|
||||
darling = "0.12.2"
|
||||
quote = "1.0.9"
|
||||
proc-macro2 = "1.0.24"
|
||||
proc-macro-error = { version = "1.0.4", default-features = false }
|
||||
syn = { version = '1.0.64', features = ['full'] }
|
||||
thiserror = "1.0.24"
|
28
crates/fce-test-macro-impl/src/attributes.rs
Normal file
28
crates/fce-test-macro-impl/src/attributes.rs
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2020 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 darling::FromMeta;
|
||||
|
||||
/// Describes attributes of `fce_test` macro.
|
||||
#[derive(Debug, Default, Clone, FromMeta)]
|
||||
pub(crate) struct FCETestAttributes {
|
||||
/// Path to a config file of a tested service.
|
||||
pub(crate) config_path: String,
|
||||
|
||||
/// Path to compiled modules of a service.
|
||||
#[darling(default)]
|
||||
pub(crate) modules_dir: Option<String>,
|
||||
}
|
54
crates/fce-test-macro-impl/src/errors.rs
Normal file
54
crates/fce-test-macro-impl/src/errors.rs
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2020 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 fce_wit_parser::WITParserError;
|
||||
use fluence_app_service::AppServiceError;
|
||||
|
||||
use darling::Error as DarlingError;
|
||||
use syn::Error as SynError;
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum TestGeneratorError {
|
||||
#[error("Can't load Wasm modules into FCE: {0}")]
|
||||
WITParserError(#[from] WITParserError),
|
||||
|
||||
#[error("{0}")]
|
||||
CorruptedITSection(#[from] CorruptedITSection),
|
||||
|
||||
#[error("{0}")]
|
||||
SynError(#[from] SynError),
|
||||
|
||||
#[error("Can't load Wasm modules from the provided config: {0}")]
|
||||
ConfigLoadError(#[from] AppServiceError),
|
||||
|
||||
#[error("{0}")]
|
||||
AttributesError(#[from] DarlingError),
|
||||
|
||||
#[error(
|
||||
"neither modules_dir attribute specified nor service config contains modules_dir, please specify one of them"
|
||||
)]
|
||||
ModulesDirUnspecified,
|
||||
|
||||
#[error("a Wasm file compiled with newer version of sdk that supports multi-value")]
|
||||
ManyFnOutputsUnsupported,
|
||||
}
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum CorruptedITSection {
|
||||
#[error("record with {0} is absent in embedded IT section")]
|
||||
AbsentRecord(u64),
|
||||
}
|
88
crates/fce-test-macro-impl/src/fce_test/config_utils.rs
Normal file
88
crates/fce-test-macro-impl/src/fce_test/config_utils.rs
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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::TResult;
|
||||
|
||||
use fluence_app_service::TomlAppServiceConfig;
|
||||
use fce_wit_parser::module_raw_interface;
|
||||
use fce_wit_parser::interface::FCEModuleInterface;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(super) struct Module<'m> {
|
||||
pub name: &'m str,
|
||||
pub interface: FCEModuleInterface,
|
||||
}
|
||||
|
||||
impl<'m> Module<'m> {
|
||||
fn new(name: &'m str, interface: FCEModuleInterface) -> Self {
|
||||
Self { name, interface }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all modules the provided config consists of.
|
||||
pub(super) fn collect_modules(
|
||||
config: &TomlAppServiceConfig,
|
||||
modules_dir: PathBuf,
|
||||
) -> TResult<Vec<Module<'_>>> {
|
||||
let module_paths = collect_module_paths(config, modules_dir);
|
||||
|
||||
module_paths
|
||||
.into_iter()
|
||||
.map(|(name, path)| {
|
||||
module_raw_interface(path).map(|interface| Module::new(name, interface))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn collect_module_paths(
|
||||
config: &TomlAppServiceConfig,
|
||||
modules_dir: PathBuf,
|
||||
) -> Vec<(&str, PathBuf)> {
|
||||
config
|
||||
.toml_faas_config
|
||||
.module
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let module_file_name = m.file_name.as_ref().unwrap_or_else(|| &m.name);
|
||||
let module_file_name = PathBuf::from(module_file_name);
|
||||
// TODO: is it correct to always have .wasm extension?
|
||||
let module_path = modules_dir.join(module_file_name).with_extension("wasm");
|
||||
|
||||
(m.name.as_str(), module_path)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
/// Tries to determine a dir with compiled Wasm modules according to the following rules:
|
||||
/// - if the modules_dir attribute is specified (by user) it will be chosen,
|
||||
/// - otherwise if modules_dir is specified in AppService config it will be chosen,
|
||||
/// - otherwise None will be returned.
|
||||
pub(super) fn resolve_modules_dir(
|
||||
config: &TomlAppServiceConfig,
|
||||
modules_dir: Option<String>,
|
||||
) -> Option<PathBuf> {
|
||||
match modules_dir {
|
||||
Some(modules_dir) => Some(PathBuf::from(modules_dir)),
|
||||
None => config
|
||||
.toml_faas_config
|
||||
.modules_dir
|
||||
.as_ref()
|
||||
.map(|p| PathBuf::from(p)),
|
||||
}
|
||||
}
|
35
crates/fce-test-macro-impl/src/fce_test/fce_test_impl.rs
Normal file
35
crates/fce-test-macro-impl/src/fce_test/fce_test_impl.rs
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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::attributes::FCETestAttributes;
|
||||
use crate::TResult;
|
||||
use crate::fce_test::glue_code_generator::generate_test_glue_code;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use darling::FromMeta;
|
||||
use syn::parse::Parser;
|
||||
|
||||
pub fn fce_test_impl(attrs: TokenStream, input: TokenStream) -> TResult<TokenStream> {
|
||||
// from https://github.com/dtolnay/syn/issues/788
|
||||
let parser = syn::punctuated::Punctuated::<syn::NestedMeta, syn::Token![,]>::parse_terminated;
|
||||
let attrs = parser.parse2(attrs)?;
|
||||
let attrs: Vec<syn::NestedMeta> = attrs.into_iter().collect();
|
||||
let attrs = FCETestAttributes::from_list(&attrs)?;
|
||||
|
||||
let func_item = syn::parse2::<syn::ItemFn>(input)?;
|
||||
|
||||
generate_test_glue_code(func_item, attrs)
|
||||
}
|
197
crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs
Normal file
197
crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs
Normal file
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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::attributes::FCETestAttributes;
|
||||
use crate::TResult;
|
||||
use crate::TestGeneratorError;
|
||||
use crate::fce_test;
|
||||
use crate::fce_test::config_utils;
|
||||
|
||||
use fluence_app_service::TomlAppServiceConfig;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use quote::ToTokens;
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Generates glue code for tests.
|
||||
/// F.e. for this test for the greeting service
|
||||
///```ignore
|
||||
/// #[fce_test(
|
||||
/// config_path = "/path/to/service/config/Config.toml",
|
||||
/// modules_dir = "/path/to/modules/dir"
|
||||
/// )]
|
||||
/// fn test() {
|
||||
/// let result = greeting.greeting("John".to_string());
|
||||
/// assert_eq(result.as_str(), "Hi, John!");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// the following glue code would be generated:
|
||||
///```ignore
|
||||
/// // (0)
|
||||
/// pub mod __fce_generated_greeting {
|
||||
/// struct FCEGeneratedStructgreeting {
|
||||
/// fce: std::rc::Rc<std::cell::RefCell<fluence_test::internal::AppService>>,
|
||||
/// }
|
||||
///
|
||||
/// impl FCEGeneratedStructgreeting {
|
||||
/// pub fn new(fce: std::rc::Rc<std::cell::RefCell<fluence_test::internal::AppService>>) -> Self {
|
||||
/// Self { fce }
|
||||
/// }
|
||||
///
|
||||
/// pub fn greeting(&mut self, name: String) -> String {
|
||||
/// use std::ops::DerefMut;
|
||||
/// let arguments = fluence_test::internal::json!([name]);
|
||||
/// let result = self
|
||||
/// .fce
|
||||
/// .as_ref
|
||||
/// .borrow_mut()
|
||||
/// .call_with_module_name("greeting", "greeting", arguments, <_>::default())
|
||||
/// .expect("call to FCE failed");
|
||||
/// let result: String = serde_json::from_value(result)
|
||||
/// .expect("the default deserializer shouldn't fail");
|
||||
/// result
|
||||
/// }
|
||||
/// }
|
||||
///}
|
||||
/// // (1)
|
||||
/// let tmp_dir = std::env::temp_dir();
|
||||
/// let service_id = fluence_test::internal::Uuid::new_v4().to_string();
|
||||
///
|
||||
/// let tmp_dir = tmp_dir.join(&service_id);
|
||||
/// let tmp_dir = tmp_dir.to_string_lossy().to_string();
|
||||
/// std::fs::create_dir(&tmp_dir).expect("can't create a directory for service in tmp");
|
||||
///
|
||||
/// let mut __fce__generated_fce_config = fluence_test::internal::TomlAppServiceConfig::load("/path/to/greeting/Config.toml".to_string())
|
||||
/// .unwrap_or_else(|e| {
|
||||
/// panic!(
|
||||
/// "app service located at `{}` config can't be loaded: {}",
|
||||
/// "/path/to/greeting/Config.toml", e
|
||||
/// )
|
||||
/// });
|
||||
///
|
||||
/// __fce__generated_fce_config.service_base_dir = Some("/path/to/tmp".to_string());
|
||||
///
|
||||
/// let fce = fluence_test::internal::AppService::new_with_empty_facade(
|
||||
/// __fce__generated_fce_config,
|
||||
/// "3640e972-92e3-47cb-b95f-4e3c5bcf0f14",
|
||||
/// std::collections::HashMap::new(),
|
||||
/// ).unwrap_or_else(|e| panic!("app service can't be created: {}", e));
|
||||
///
|
||||
/// let fce = std::rc::Rc::new(std::cell::RefCell::new(fce));
|
||||
///
|
||||
/// // (2)
|
||||
///
|
||||
/// let mut greeting = __fce_generated_greeting::FCEGeneratedStructgreeting::new(fce);
|
||||
///
|
||||
/// // (3)
|
||||
///
|
||||
/// let result = greeting.greeting("John".to_string());
|
||||
/// assert_eq(result.as_str(), "Hi, John!");
|
||||
///
|
||||
/// // (4)
|
||||
///```
|
||||
///
|
||||
/// Example code above corresponds to the macro definition in the following way:
|
||||
/// [(0), (1)] - module_definitions*
|
||||
/// [(1), (2)] - app_service_ctor
|
||||
/// [(2), (3)] - module_ctors*
|
||||
/// [(3), (4)] - original_block
|
||||
pub(super) fn generate_test_glue_code(
|
||||
func_item: syn::ItemFn,
|
||||
attrs: FCETestAttributes,
|
||||
) -> TResult<TokenStream> {
|
||||
let fce_config = TomlAppServiceConfig::load(&attrs.config_path)?;
|
||||
let modules_dir = match config_utils::resolve_modules_dir(&fce_config, attrs.modules_dir) {
|
||||
Some(modules_dir) => modules_dir,
|
||||
None => return Err(TestGeneratorError::ModulesDirUnspecified),
|
||||
};
|
||||
|
||||
let app_service_ctor = generate_app_service_ctor(&attrs.config_path, &modules_dir);
|
||||
let module_interfaces = fce_test::config_utils::collect_modules(&fce_config, modules_dir)?;
|
||||
|
||||
let module_definitions =
|
||||
fce_test::module_generator::generate_module_definitions(module_interfaces.iter())?;
|
||||
|
||||
let module_iter = module_interfaces.iter().map(|module| module.name);
|
||||
let module_ctors = generate_module_ctors(module_iter)?;
|
||||
|
||||
let original_block = func_item.block;
|
||||
let signature = func_item.sig;
|
||||
|
||||
let glue_code = quote! {
|
||||
#[test]
|
||||
#signature {
|
||||
// definitions for wasm modules specified in config
|
||||
#(#module_definitions)*
|
||||
|
||||
// AppService constructor and instantiation to implicit `fce` variable
|
||||
#app_service_ctor
|
||||
|
||||
// constructors of all modules of the tested service
|
||||
#(#module_ctors)*
|
||||
|
||||
// original test function as is
|
||||
#original_block
|
||||
}
|
||||
};
|
||||
|
||||
Ok(glue_code)
|
||||
}
|
||||
|
||||
fn generate_app_service_ctor(config_path: &str, modules_dir: &PathBuf) -> TokenStream {
|
||||
let config_path = config_path.to_token_stream();
|
||||
let modules_dir = modules_dir.to_string_lossy().to_string();
|
||||
|
||||
quote! {
|
||||
let tmp_dir = std::env::temp_dir();
|
||||
let service_id = fluence_test::internal::Uuid::new_v4().to_string();
|
||||
|
||||
let tmp_dir = tmp_dir.join(&service_id);
|
||||
let tmp_dir = tmp_dir.to_string_lossy().to_string();
|
||||
std::fs::create_dir(&tmp_dir).expect("can't create a directory for service in tmp");
|
||||
|
||||
let mut __fce_generated_fce_config = fluence_test::internal::TomlAppServiceConfig::load(#config_path.to_string())
|
||||
.unwrap_or_else(|e| panic!("app service located at `{}` config can't be loaded: {}", #config_path, e));
|
||||
__fce_generated_fce_config.service_base_dir = Some(tmp_dir);
|
||||
__fce_generated_fce_config.toml_faas_config.modules_dir = Some(#modules_dir.to_string());
|
||||
|
||||
let fce = fluence_test::internal::AppService::new_with_empty_facade(__fce_generated_fce_config, service_id, std::collections::HashMap::new())
|
||||
.unwrap_or_else(|e| panic!("app service can't be created: {}", e));
|
||||
|
||||
let fce = std::rc::Rc::new(std::cell::RefCell::new(fce));
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_module_ctors<'n>(
|
||||
module_names: impl ExactSizeIterator<Item = &'n str>,
|
||||
) -> TResult<Vec<TokenStream>> {
|
||||
module_names
|
||||
.map(|name| -> TResult<_> {
|
||||
// TODO: optimize these two call because they are called twice for each module name
|
||||
// and internally allocate memory in format call.
|
||||
let module_name = fce_test::utils::generate_module_name(&name)?;
|
||||
let struct_name = fce_test::utils::generate_struct_name(&name)?;
|
||||
let name_for_user = fce_test::utils::new_ident(&name)?;
|
||||
|
||||
let module_ctor =
|
||||
quote! { let mut #name_for_user = #module_name::#struct_name::new(fce.clone()); };
|
||||
|
||||
Ok(module_ctor)
|
||||
})
|
||||
.collect::<TResult<_>>()
|
||||
}
|
23
crates/fce-test-macro-impl/src/fce_test/mod.rs
Normal file
23
crates/fce-test-macro-impl/src/fce_test/mod.rs
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
mod config_utils;
|
||||
mod fce_test_impl;
|
||||
mod glue_code_generator;
|
||||
mod module_generator;
|
||||
mod utils;
|
||||
|
||||
pub use fce_test_impl::fce_test_impl;
|
99
crates/fce-test-macro-impl/src/fce_test/module_generator.rs
Normal file
99
crates/fce-test-macro-impl/src/fce_test/module_generator.rs
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
mod methods_generator;
|
||||
mod record_type_generator;
|
||||
|
||||
use crate::fce_test::utils;
|
||||
use crate::fce_test::config_utils::Module;
|
||||
use crate::TResult;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
/// Generates definitions of modules and records of this modules.
|
||||
/// F.e. for the greeting service the following definitions would be generated:
|
||||
///```ignore
|
||||
/// pub mod __fce_generated_greeting {
|
||||
/// struct FCEGeneratedStructgreeting {
|
||||
/// fce: std::rc::Rc<std::cell::RefCell<fluence_test::internal::AppService>>,
|
||||
/// }
|
||||
///
|
||||
/// impl FCEGeneratedStructgreeting {
|
||||
/// pub fn new(fce: std::rc::Rc<std::cell::RefCell<fluence_test::internal::AppService>>) -> Self {
|
||||
/// Self { fce }
|
||||
/// }
|
||||
///
|
||||
/// pub fn greeting(&mut self, name: String) -> String {
|
||||
/// use std::ops::DerefMut;
|
||||
/// let arguments = fluence_test::internal::json!([name]);
|
||||
/// let result = self
|
||||
/// .fce
|
||||
/// .as_ref
|
||||
/// .borrow_mut()
|
||||
/// .call_with_module_name("greeting", "greeting", arguments, <_>::default())
|
||||
/// .expect("call to FCE failed");
|
||||
/// let result: String = serde_json::from_value(result)
|
||||
/// .expect("the default deserializer shouldn't fail");
|
||||
/// result
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///```
|
||||
pub(super) fn generate_module_definitions<'i>(
|
||||
modules: impl ExactSizeIterator<Item = &'i Module<'i>>,
|
||||
) -> TResult<Vec<TokenStream>> {
|
||||
modules
|
||||
.into_iter()
|
||||
.map(generate_module_definition)
|
||||
.collect::<TResult<Vec<_>>>()
|
||||
}
|
||||
|
||||
fn generate_module_definition(module: &Module<'_>) -> TResult<TokenStream> {
|
||||
let module_name = module.name;
|
||||
let module_name_ident = utils::generate_module_name(module_name)?;
|
||||
let struct_name_ident = utils::generate_struct_name(module_name)?;
|
||||
|
||||
let module_interface = &module.interface;
|
||||
let module_records = record_type_generator::generate_records(&module_interface.record_types)?;
|
||||
let module_functions = methods_generator::generate_module_methods(
|
||||
module_name,
|
||||
module_interface.function_signatures.iter(),
|
||||
&module_interface.record_types,
|
||||
)?;
|
||||
|
||||
let module_definition = quote! {
|
||||
pub mod #module_name_ident {
|
||||
#(#module_records)*
|
||||
|
||||
pub struct #struct_name_ident {
|
||||
fce: std::rc::Rc<std::cell::RefCell<fluence_test::internal::AppService>>,
|
||||
}
|
||||
|
||||
impl #struct_name_ident {
|
||||
pub fn new(fce: std::rc::Rc<std::cell::RefCell<fluence_test::internal::AppService>>) -> Self {
|
||||
Self { fce }
|
||||
}
|
||||
}
|
||||
|
||||
impl #struct_name_ident {
|
||||
#(#module_functions)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(module_definition)
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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;
|
||||
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::FCEFunctionSignature;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
pub(super) fn generate_module_methods<'m, 'r>(
|
||||
module_name: &str,
|
||||
method_signatures: impl ExactSizeIterator<Item = &'m FCEFunctionSignature>,
|
||||
records: &'r FCERecordTypes,
|
||||
) -> TResult<Vec<TokenStream>> {
|
||||
method_signatures
|
||||
.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! {
|
||||
pub fn #func_name(&mut self, #(#arguments),*) #output_type {
|
||||
#fce_call
|
||||
}
|
||||
};
|
||||
|
||||
Ok(module_method)
|
||||
})
|
||||
.collect::<TResult<Vec<_>>>()
|
||||
}
|
||||
|
||||
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::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_with_module_name(#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 = 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,59 @@
|
||||
/*
|
||||
* 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;
|
||||
use crate::TResult;
|
||||
|
||||
use fce_wit_parser::interface::it::IRecordFieldType;
|
||||
use fce_wit_parser::interface::FCERecordTypes;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
pub(super) fn generate_records(records: &FCERecordTypes) -> TResult<Vec<TokenStream>> {
|
||||
use std::ops::Deref;
|
||||
|
||||
records.iter().map(|(_, record)| -> TResult<_> {
|
||||
let record_name_ident = utils::generate_record_name(&record.name)?;
|
||||
let fields = prepare_field(record.fields.deref().iter(), records)?;
|
||||
|
||||
let generated_record = quote! {
|
||||
#[derive(Clone, fluence_test::internal::Serialize, fluence_test::internal::Deserialize)]
|
||||
pub struct #record_name_ident {
|
||||
#(#fields),*
|
||||
}
|
||||
};
|
||||
|
||||
Ok(generated_record)
|
||||
}
|
||||
).collect::<TResult<Vec<_>>>()
|
||||
}
|
||||
|
||||
fn prepare_field<'f>(
|
||||
fields: impl ExactSizeIterator<Item = &'f IRecordFieldType>,
|
||||
records: &FCERecordTypes,
|
||||
) -> TResult<Vec<TokenStream>> {
|
||||
fields
|
||||
.map(|field| -> TResult<_> {
|
||||
let field_name = utils::new_ident(&field.name)?;
|
||||
let field_type = utils::itype_to_tokens(&field.ty, records)?;
|
||||
|
||||
let generated_field = quote! { #field_name: #field_type };
|
||||
|
||||
Ok(generated_field)
|
||||
})
|
||||
.collect::<TResult<Vec<_>>>()
|
||||
}
|
77
crates/fce-test-macro-impl/src/fce_test/utils.rs
Normal file
77
crates/fce-test-macro-impl/src/fce_test/utils.rs
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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::TResult;
|
||||
use fce_wit_parser::interface::FCERecordTypes;
|
||||
use fce_wit_parser::interface::it::IType;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
pub(super) fn generate_module_name(module_name: &str) -> TResult<syn::Ident> {
|
||||
let extended_module_name = format!("__fce_generated_{}", module_name);
|
||||
new_ident(&extended_module_name)
|
||||
}
|
||||
|
||||
pub(super) fn generate_record_name(record_name: &str) -> TResult<syn::Ident> {
|
||||
let extended_record_name = format!("{}", record_name);
|
||||
new_ident(&extended_record_name)
|
||||
}
|
||||
|
||||
pub(super) fn generate_struct_name(struct_name: &str) -> TResult<syn::Ident> {
|
||||
let extended_struct_name = format!("FCEGeneratedStruct{}", struct_name);
|
||||
new_ident(&extended_struct_name)
|
||||
}
|
||||
|
||||
pub(super) fn new_ident(ident_str: &str) -> TResult<syn::Ident> {
|
||||
syn::parse_str::<syn::Ident>(ident_str).map_err(Into::into)
|
||||
}
|
||||
|
||||
pub(super) fn itype_to_tokens(itype: &IType, records: &FCERecordTypes) -> TResult<TokenStream> {
|
||||
let token_stream = match itype {
|
||||
IType::Record(record_id) => {
|
||||
let record = records
|
||||
.get(record_id)
|
||||
.ok_or_else(|| crate::errors::CorruptedITSection::AbsentRecord(*record_id))?;
|
||||
let record_name = new_ident(&record.name)?;
|
||||
let token_stream = quote! { #record_name };
|
||||
token_stream
|
||||
}
|
||||
IType::Array(ty) => {
|
||||
let inner_ty_token_stream = itype_to_tokens(ty, records)?;
|
||||
let token_stream = quote! { Vec<#inner_ty_token_stream> };
|
||||
token_stream
|
||||
}
|
||||
IType::String => quote! { String },
|
||||
IType::S8 => quote! { i8 },
|
||||
IType::S16 => quote! { i16 },
|
||||
IType::S32 => quote! { i32 },
|
||||
IType::S64 => quote! { i64 },
|
||||
IType::U8 => quote! { u8 },
|
||||
IType::U16 => quote! { u16 },
|
||||
IType::U32 => quote! { u32 },
|
||||
IType::U64 => quote! { u64 },
|
||||
IType::I32 => quote! { i32 },
|
||||
IType::I64 => quote! { i64 },
|
||||
IType::F32 => quote! { f32 },
|
||||
IType::F64 => quote! { f64 },
|
||||
IType::Anyref => {
|
||||
unimplemented!("anyrefs aren't supported and will be deleted from IType soon")
|
||||
}
|
||||
};
|
||||
|
||||
Ok(token_stream)
|
||||
}
|
36
crates/fce-test-macro-impl/src/lib.rs
Normal file
36
crates/fce-test-macro-impl/src/lib.rs
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
mod attributes;
|
||||
mod errors;
|
||||
mod fce_test;
|
||||
|
||||
pub use fce_test::fce_test_impl;
|
||||
pub use errors::TestGeneratorError;
|
||||
|
||||
pub(crate) type TResult<T> = std::result::Result<T, TestGeneratorError>;
|
25
crates/fce-test-macro/Cargo.toml
Normal file
25
crates/fce-test-macro/Cargo.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "fluence-sdk-test-macro"
|
||||
version = "0.5.0" # remember to update html_root_url
|
||||
edition = "2018"
|
||||
description = "Definition of the `#[fce_test]` macro"
|
||||
repository = "https://github.com/fluencelabs/rust-sdk/crates/macro-test"
|
||||
authors = ["Fluence Labs"]
|
||||
keywords = ["fluence", "sdk", "webassembly", "procedural_macros"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fluence-sdk-test-macro-impl = { path = "../fce-test-macro-impl", version = "=0.5.0" }
|
||||
|
||||
quote = "1.0.9"
|
||||
proc-macro2 = "1.0.24"
|
||||
proc-macro-error = { version = "1.0.4", default-features = false }
|
||||
syn = { version = '1.0.64', features = ['full'] }
|
53
crates/fce-test-macro/src/lib.rs
Normal file
53
crates/fce-test-macro/src/lib.rs
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.5.0")]
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
use fluence_sdk_test_macro_impl::fce_test_impl;
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro_error::proc_macro_error;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// This macro allows user to write tests for services in the following form:
|
||||
///```ignore
|
||||
/// #[fce_test(config = "/path/to/Config.toml", modules_dir = "path/to/service/modules")]
|
||||
/// fn test() {
|
||||
/// let service_result = greeting.greeting("John".to_string());
|
||||
/// assert_eq!(&service_result, "Hi, name!");
|
||||
/// }
|
||||
///```
|
||||
#[proc_macro_error]
|
||||
#[proc_macro_attribute]
|
||||
pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let attrs: proc_macro2::TokenStream = attrs.into();
|
||||
let attrs_span = attrs.span();
|
||||
|
||||
match fce_test_impl(attrs, input.into()) {
|
||||
Ok(stream) => stream.into(),
|
||||
Err(e) => proc_macro_error::abort!(attrs_span, format!("{}", e)),
|
||||
}
|
||||
}
|
@ -10,15 +10,16 @@ keywords = ["fluence", "sdk", "webassembly"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
[package.metadata.docs.rs] # https://docs.rs/about
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["rlib"]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fluence-sdk-macro = { path = "../macro", version = "=0.5.0" }
|
||||
fluence-sdk-macro = { path = "../fce-macro", version = "=0.5.0" }
|
||||
|
||||
log = { version = "0.4.8", features = ["std"] }
|
||||
serde = "=1.0.118"
|
||||
|
@ -34,7 +34,9 @@
|
||||
mod export_allocator;
|
||||
#[cfg(any(feature = "debug", feature = "logger"))]
|
||||
mod logger;
|
||||
mod module_manifest;
|
||||
mod result;
|
||||
mod sdk_version_embedder;
|
||||
|
||||
pub use export_allocator::allocate;
|
||||
pub use export_allocator::deallocate;
|
||||
@ -53,6 +55,9 @@ pub use result::set_result_size;
|
||||
pub use result::release_objects;
|
||||
pub use result::add_object_to_release;
|
||||
|
||||
pub use module_manifest::MANIFEST_SECTION_NAME;
|
||||
pub use sdk_version_embedder::VERSION_SECTION_NAME;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn log<S: AsRef<str>>(msg: S) {
|
||||
// logs will be printed only if debug feature is enabled
|
||||
|
88
crates/main/src/module_manifest.rs
Normal file
88
crates/main/src/module_manifest.rs
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
// TODO: avoid duplication with the link_section when key-value attributes become stable
|
||||
pub const MANIFEST_SECTION_NAME: &str = "__fluence_wasm_module_manifest";
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! module_manifest {
|
||||
($authors:expr, $version:expr, $description:expr, $repository:expr) => {
|
||||
const __FCE_SDK_AUTHORS_SIZE: usize = $authors.as_bytes().len();
|
||||
const __FCE_SDK_VERSION_SIZE: usize = $version.as_bytes().len();
|
||||
const __FCE_SDK_DESCRIPTION_SIZE: usize = $description.as_bytes().len();
|
||||
const __FCE_SDK_REPOSITORY_SIZE: usize = $repository.as_bytes().len();
|
||||
const __FCE_SDK_FIELD_PREFIX_SIZE: usize = std::mem::size_of::<u64>();
|
||||
|
||||
const __FCE_MANIFEST_SIZE: usize = __FCE_SDK_AUTHORS_SIZE
|
||||
+ __FCE_SDK_VERSION_SIZE
|
||||
+ __FCE_SDK_DESCRIPTION_SIZE
|
||||
+ __FCE_SDK_REPOSITORY_SIZE
|
||||
+ __FCE_SDK_FIELD_PREFIX_SIZE * 4;
|
||||
|
||||
const fn __fce_sdk_append_data(
|
||||
mut manifest: [u8; __FCE_MANIFEST_SIZE],
|
||||
data: &'static str,
|
||||
offset: usize,
|
||||
) -> ([u8; __FCE_MANIFEST_SIZE], usize) {
|
||||
let data_as_bytes = data.as_bytes();
|
||||
let data_len = data_as_bytes.len();
|
||||
|
||||
// write data prefix with data size in LE
|
||||
let data_len_u64 = data_len as u64;
|
||||
let data_len_le_bytes = data_len_u64.to_le_bytes();
|
||||
let mut byte_idx = 0;
|
||||
while byte_idx < __FCE_SDK_FIELD_PREFIX_SIZE {
|
||||
manifest[offset + byte_idx] = data_len_le_bytes[byte_idx];
|
||||
byte_idx += 1;
|
||||
}
|
||||
|
||||
// write data
|
||||
let mut byte_idx = 0;
|
||||
while byte_idx < data_len {
|
||||
manifest[__FCE_SDK_FIELD_PREFIX_SIZE + offset + byte_idx] = data_as_bytes[byte_idx];
|
||||
byte_idx += 1;
|
||||
}
|
||||
|
||||
(manifest, offset + __FCE_SDK_FIELD_PREFIX_SIZE + data_len)
|
||||
}
|
||||
|
||||
const fn generate_manifest() -> [u8; __FCE_MANIFEST_SIZE] {
|
||||
let manifest: [u8; __FCE_MANIFEST_SIZE] = [0; __FCE_MANIFEST_SIZE];
|
||||
|
||||
let offset = 0;
|
||||
let (manifest, offset) = __fce_sdk_append_data(manifest, $authors, offset);
|
||||
let (manifest, offset) = __fce_sdk_append_data(manifest, $version, offset);
|
||||
let (manifest, offset) = __fce_sdk_append_data(manifest, $description, offset);
|
||||
let (manifest, _) = __fce_sdk_append_data(manifest, $repository, offset);
|
||||
|
||||
manifest
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[link_section = "__fluence_wasm_module_manifest"]
|
||||
#[doc(hidden)]
|
||||
pub static __FCE_WASM_MODULE_MANIFEST: [u8; __FCE_MANIFEST_SIZE] = generate_manifest();
|
||||
};
|
||||
|
||||
() => {
|
||||
module_manifest!(
|
||||
env!("CARGO_PKG_AUTHORS"),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
env!("CARGO_PKG_DESCRIPTION"),
|
||||
env!("CARGO_PKG_REPOSITORY")
|
||||
);
|
||||
};
|
||||
}
|
41
crates/main/src/sdk_version_embedder.rs
Normal file
41
crates/main/src/sdk_version_embedder.rs
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
const PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
const VERSION_SIZE: usize = PKG_VERSION.len();
|
||||
|
||||
const fn sdk_version() -> [u8; VERSION_SIZE] {
|
||||
let version_as_slice = PKG_VERSION.as_bytes();
|
||||
|
||||
let mut version_as_array: [u8; VERSION_SIZE] = [0; VERSION_SIZE];
|
||||
let mut byte_id = 0;
|
||||
while byte_id < VERSION_SIZE {
|
||||
version_as_array[byte_id] = version_as_slice[byte_id];
|
||||
byte_id += 1;
|
||||
}
|
||||
|
||||
version_as_array
|
||||
}
|
||||
|
||||
// TODO: avoid duplication with the link_section when key-value attributes become stable
|
||||
pub const VERSION_SECTION_NAME: &str = "__fluence_sdk_version";
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[link_section = "__fluence_sdk_version"]
|
||||
#[doc(hidden)]
|
||||
pub static __FCE_SDK_VERSION: [u8; VERSION_SIZE] = sdk_version();
|
@ -10,13 +10,13 @@ keywords = ["fluence", "sdk", "webassembly", "wit", "interface-types"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
|
||||
[package.metadata.docs.rs] # https://docs.rs/about
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.7"
|
||||
proc-macro2 = "1.0.18"
|
||||
quote = "1.0.9"
|
||||
proc-macro2 = "1.0.24"
|
||||
serde = { version = "=1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.56"
|
||||
syn = { version = '1.0.33', features = ['full'] }
|
||||
uuid = { version = "0.8.1", features = ["v4"] }
|
||||
syn = { version = '1.0.64', features = ['full'] }
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
|
@ -99,7 +99,7 @@ impl ParsedType {
|
||||
}
|
||||
_ if !type_segment.arguments.is_empty() => Err(Error::new(
|
||||
type_segment.span(),
|
||||
"type with lifetimes or generics aren't allowed".to_string(),
|
||||
"types with lifetimes or generics aren't allowed".to_string(),
|
||||
)),
|
||||
_ => Ok(ParsedType::Record(
|
||||
(&type_segment.ident).into_token_stream().to_string(),
|
||||
|
@ -31,7 +31,7 @@ pub(crate) struct FnEpilogDescriptor {
|
||||
|
||||
/// This trait could be used to generate various parts needed to construct epilog of an export
|
||||
/// function. They are marked with # in the following example:
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// quote! {
|
||||
/// pub unsafe fn foo(...) #fn_return_type {
|
||||
/// ...
|
||||
|
@ -34,7 +34,7 @@ pub(crate) struct FnPrologDescriptor {
|
||||
|
||||
/// This trait could be used to generate various parts needed to construct prolog of an export
|
||||
/// function. They are marked with # in the following example:
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// quote! {
|
||||
/// fn foo(#(#raw_arg_names: #raw_arg_types),*) {
|
||||
/// #prolog
|
||||
|
@ -34,7 +34,7 @@ pub(crate) struct ExternDescriptor {
|
||||
|
||||
/// This trait could be used to generate various parts needed to construct prolog of an wrapper
|
||||
/// function or extern block. They are marked with # in the following examples:
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// quote! {
|
||||
/// fn foo(#(#arg_names: #arg_types), *) {
|
||||
/// let arg_1 = std::mem::ManuallyDrop::new(arg_1);
|
||||
@ -45,7 +45,7 @@ pub(crate) struct ExternDescriptor {
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// ```ignore
|
||||
/// quote! {
|
||||
/// extern "C" {
|
||||
/// #[link_name = "foo_link_name"]
|
||||
|
27
fluence-test/Cargo.toml
Normal file
27
fluence-test/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "fluence-test"
|
||||
version = "0.5.0" # remember to update html_root_url
|
||||
description = "Fluence backend SDK for testing"
|
||||
documentation = "https://docs.rs/fluence/"
|
||||
repository = "https://github.com/fluencelabs/rust-sdk"
|
||||
authors = ["Fluence Labs"]
|
||||
readme = "README.md"
|
||||
keywords = ["fluence", "sdk", "webassembly"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fluence-sdk-test-macro = { path = "../crates/fce-test-macro", version = "=0.5.0" }
|
||||
fluence-app-service = { version = "0.5.2", features = ["raw-module-api"] }
|
||||
|
||||
serde = { version = "1.0.118", features = ["derive"] }
|
||||
serde_json = "1.0.64"
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
42
fluence-test/src/lib.rs
Normal file
42
fluence-test/src/lib.rs
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
#![doc(html_root_url = "https://docs.rs/fluence-test/0.5.0")]
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
pub use fluence_sdk_test_macro::fce_test;
|
||||
|
||||
/// These API functions are intended for internal usage in generated code.
|
||||
/// Normally, you shouldn't use them.
|
||||
pub mod internal {
|
||||
pub use fluence_app_service::AppService;
|
||||
pub use fluence_app_service::TomlAppServiceConfig;
|
||||
|
||||
pub use serde::Serialize;
|
||||
pub use serde::Deserialize;
|
||||
pub use serde_json::json;
|
||||
|
||||
pub use uuid::Uuid;
|
||||
}
|
35
fluence/Cargo.toml
Normal file
35
fluence/Cargo.toml
Normal file
@ -0,0 +1,35 @@
|
||||
[package]
|
||||
name = "fluence"
|
||||
version = "0.5.0" # remember to update html_root_url
|
||||
description = "Fluence backend SDK for developing backend applications for the Fluence network"
|
||||
documentation = "https://docs.rs/fluence/"
|
||||
repository = "https://github.com/fluencelabs/rust-sdk"
|
||||
authors = ["Fluence Labs"]
|
||||
readme = "README.md"
|
||||
keywords = ["fluence", "sdk", "webassembly"]
|
||||
categories = ["api-bindings", "wasm"]
|
||||
license = "Apache-2.0"
|
||||
edition = "2018"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fluence-sdk-macro = { path = "../crates/fce-macro", version = "=0.5.0" }
|
||||
fluence-sdk-main = { path = "../crates/main", version = "=0.5.0" }
|
||||
|
||||
serde = { version = "1.0.118", features = ["derive"]}
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = "1.0"
|
||||
|
||||
[features]
|
||||
# Print some internal logs by log_utf8_string
|
||||
debug = ["fluence-sdk-main/debug"]
|
||||
|
||||
# Enable logger (this will cause log_utf8_string to appear in imports)
|
||||
logger = ["fluence-sdk-main/logger"]
|
@ -70,9 +70,11 @@
|
||||
mod call_parameters;
|
||||
mod mounted_binary;
|
||||
|
||||
extern crate self as fluence;
|
||||
// extern crate self as fluence;
|
||||
|
||||
pub use fluence_sdk_macro::fce;
|
||||
#[cfg(feature = "fce-test")]
|
||||
pub use fluence_sdk_test_macro::fce_test;
|
||||
|
||||
pub use call_parameters::CallParameters;
|
||||
pub use call_parameters::SecurityTetraplet;
|
||||
@ -88,6 +90,8 @@ pub use mounted_binary::Result as MountedBinaryResult;
|
||||
pub use mounted_binary::StringResult as MountedBinaryStringResult;
|
||||
pub use mounted_binary::SUCCESS_CODE as BINARY_SUCCESS_CODE;
|
||||
|
||||
pub use fluence_sdk_main::module_manifest;
|
||||
|
||||
/// These API functions are intended for internal usage in generated code.
|
||||
/// Normally, you shouldn't use them.
|
||||
pub mod internal {
|
67
fluence/tests/export_functions/arrays.rs
Normal file
67
fluence/tests/export_functions/arrays.rs
Normal file
@ -0,0 +1,67 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
pub fn main() {}
|
||||
|
||||
#[fce]
|
||||
pub fn byte_type( __arg: Vec<u8>) -> Vec<u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn inner_arrays_1(_arg: Vec<Vec<Vec<Vec<u8>>>>) -> Vec<Vec<Vec<Vec<u8>>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
#[derive(Default)]
|
||||
pub struct TestRecord {
|
||||
pub field_0: i32,
|
||||
pub field_1: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn inner_arrays_2(_arg: Vec<Vec<Vec<Vec<TestRecord>>>>) -> Vec<Vec<Vec<Vec<TestRecord>>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn string_type(_arg: Vec<String>) -> Vec<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn f32_type(_arg: Vec<f32>) -> Vec<f32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn f64_type(_arg: Vec<f64>) -> Vec<f64> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn u32_type(_arg: Vec<u32>) -> Vec<u32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn u64_type(_arg: Vec<u64>) -> Vec<u64> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn i32_type(_arg: Vec<i32>) -> Vec<i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn i64_type(_arg: Vec<i64>) -> Vec<i64> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn empty_type() -> Vec<String> {
|
||||
unimplemented!()
|
||||
}
|
73
fluence/tests/export_functions/basic_types.rs
Normal file
73
fluence/tests/export_functions/basic_types.rs
Normal file
@ -0,0 +1,73 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
pub fn main() {}
|
||||
|
||||
#[fce]
|
||||
pub fn all_types(
|
||||
_arg_0: i8,
|
||||
_arg_1: i16,
|
||||
_arg_2: i32,
|
||||
_arg_3: i64,
|
||||
_arg_4: u8,
|
||||
_arg_5: u16,
|
||||
_arg_6: u32,
|
||||
_arg_7: u64,
|
||||
_arg_8: f32,
|
||||
_arg_9: f64,
|
||||
_arg_10: String,
|
||||
_arg_11: Vec<u8>,
|
||||
) -> Vec<u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn string_type(_arg: String) -> String {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn bytearray_type(_arg: Vec<u8>) -> Vec<u8> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn bool_type(_arg: bool) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn f32_type(_arg: f32) -> f32 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn f64_type(_arg: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn u32_type(_arg: u32) -> u32 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn u64_type(_arg: u64) -> u64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn i32_type(_arg: i32) -> i32 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn i64_type(_arg: i64) -> i64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub fn empty_type() -> String {
|
||||
unimplemented!()
|
||||
}
|
24
fluence/tests/export_functions/improper_types.rs
Normal file
24
fluence/tests/export_functions/improper_types.rs
Normal file
@ -0,0 +1,24 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
pub fn main() {}
|
||||
|
||||
#[fce]
|
||||
fn test(_arg_1: Box<i32>) {}
|
||||
|
||||
#[fce]
|
||||
fn test2(_arg_1: std::rc::Rc<i32>) {}
|
||||
|
||||
#[fce]
|
||||
fn test3(_arg_1: std::collections::HashMap<i32, String>) {}
|
||||
|
||||
#[fce]
|
||||
fn test4(_arg_1: i32) -> (i32, i32) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[fce]
|
||||
fn test5(_arg_1: i32) -> Box<i32> {
|
||||
unimplemented!()
|
||||
}
|
29
fluence/tests/export_functions/improper_types.stderr
Normal file
29
fluence/tests/export_functions/improper_types.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/improper_types.rs:8:17
|
||||
|
|
||||
8 | fn test(_arg_1: Box<i32>) {}
|
||||
| ^^^^^^^^
|
||||
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/improper_types.rs:11:27
|
||||
|
|
||||
11 | fn test2(_arg_1: std::rc::Rc<i32>) {}
|
||||
| ^^^^^^^
|
||||
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/improper_types.rs:14:36
|
||||
|
|
||||
14 | fn test3(_arg_1: std::collections::HashMap<i32, String>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: Incorrect argument type - passing only by value is supported now
|
||||
--> $DIR/improper_types.rs:17:26
|
||||
|
|
||||
17 | fn test4(_arg_1: i32) -> (i32, i32) {
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/improper_types.rs:22:26
|
||||
|
|
||||
22 | fn test5(_arg_1: i32) -> Box<i32> {
|
||||
| ^^^^^^^^
|
40
fluence/tests/import_functions/arrays.rs
Normal file
40
fluence/tests/import_functions/arrays.rs
Normal file
@ -0,0 +1,40 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
pub fn main() {}
|
||||
|
||||
#[fce]
|
||||
#[derive(Default)]
|
||||
pub struct TestRecord {
|
||||
pub field_0: i32,
|
||||
pub field_1: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
#[link(wasm_import_module = "arrays_passing_effector")]
|
||||
extern "C" {
|
||||
pub fn inner_arrays_1(arg: Vec<Vec<Vec<Vec<u8>>>>) -> Vec<Vec<Vec<Vec<u8>>>>;
|
||||
|
||||
pub fn inner_arrays_2(
|
||||
arg: Vec<Vec<Vec<Vec<TestRecord>>>>,
|
||||
) -> Vec<Vec<Vec<Vec<TestRecord>>>>;
|
||||
|
||||
pub fn string_type(arg: Vec<String>) -> Vec<String>;
|
||||
|
||||
pub fn byte_type(arg: Vec<u8>) -> Vec<u8>;
|
||||
|
||||
pub fn f32_type(arg: Vec<f32>) -> Vec<f32>;
|
||||
|
||||
pub fn f64_type(arg: Vec<f64>) -> Vec<f64>;
|
||||
|
||||
pub fn u32_type(arg: Vec<u32>) -> Vec<u32>;
|
||||
|
||||
pub fn u64_type(arg: Vec<u64>) -> Vec<u64>;
|
||||
|
||||
pub fn i32_type(arg: Vec<i32>) -> Vec<i32>;
|
||||
|
||||
pub fn i64_type(arg: Vec<i64>) -> Vec<i64>;
|
||||
|
||||
pub fn empty_type() -> Vec<String>;
|
||||
}
|
40
fluence/tests/import_functions/basic_types.rs
Normal file
40
fluence/tests/import_functions/basic_types.rs
Normal file
@ -0,0 +1,40 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[fce]
|
||||
#[link(wasm_import_module = "arguments_passing_effector")]
|
||||
extern "C" {
|
||||
pub fn all_types(
|
||||
arg_0: i8,
|
||||
arg_1: i16,
|
||||
arg_2: i32,
|
||||
arg_3: i64,
|
||||
arg_4: u8,
|
||||
arg_5: u16,
|
||||
arg_6: u32,
|
||||
arg_7: u64,
|
||||
arg_8: f32,
|
||||
arg_9: f64,
|
||||
arg_10: String,
|
||||
arg_11: Vec<u8>,
|
||||
) -> Vec<u8>;
|
||||
|
||||
pub fn string_type(arg: String) -> String;
|
||||
pub fn bytearray_type(arg: Vec<u8>) -> Vec<u8>;
|
||||
|
||||
pub fn bool_type(arg: bool) -> bool;
|
||||
|
||||
pub fn f32_type(arg: f32) -> f32;
|
||||
pub fn f64_type(arg: f64) -> f64;
|
||||
|
||||
pub fn u32_type(arg: u32) -> u32;
|
||||
pub fn u64_type(arg: u64) -> u64;
|
||||
|
||||
pub fn i32_type(arg: i32) -> i32;
|
||||
pub fn i64_type(arg: i64) -> i64;
|
||||
|
||||
pub fn empty_type() -> String;
|
||||
}
|
24
fluence/tests/import_functions/improper_types.rs
Normal file
24
fluence/tests/import_functions/improper_types.rs
Normal file
@ -0,0 +1,24 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
pub fn main() {}
|
||||
|
||||
#[fce]
|
||||
#[link(wasm_import_module = "arguments_passing_effector")]
|
||||
extern "C" {
|
||||
#[fce]
|
||||
fn test(_arg_1: Box<i32>);
|
||||
|
||||
#[fce]
|
||||
fn test2(_arg_1: std::rc::Rc<i32>);
|
||||
|
||||
#[fce]
|
||||
fn test3(_arg_1: std::collections::HashMap<i32, String>);
|
||||
|
||||
#[fce]
|
||||
fn test4(_arg_1: i32) -> (i32, i32);
|
||||
|
||||
#[fce]
|
||||
fn test5(_arg_1: i32) -> Box<i32>;
|
||||
}
|
5
fluence/tests/import_functions/improper_types.stderr
Normal file
5
fluence/tests/import_functions/improper_types.stderr
Normal file
@ -0,0 +1,5 @@
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/improper_types.rs:11:21
|
||||
|
|
||||
11 | fn test(_arg_1: Box<i32>);
|
||||
| ^^^^^^^^
|
82
fluence/tests/records/basic_structs.rs
Normal file
82
fluence/tests/records/basic_structs.rs
Normal file
@ -0,0 +1,82 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[fce]
|
||||
pub struct TestRecord {
|
||||
pub field_0: bool,
|
||||
pub field_1: i8,
|
||||
pub field_2: i16,
|
||||
pub field_3: i32,
|
||||
pub field_4: i64,
|
||||
pub field_5: u8,
|
||||
pub field_6: u16,
|
||||
pub field_7: u32,
|
||||
pub field_8: u64,
|
||||
pub field_9: f32,
|
||||
pub field_10: f64,
|
||||
pub field_11: String,
|
||||
pub field_12: Vec<u8>,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct Tx {
|
||||
pub block_hash: String,
|
||||
pub block_number: String,
|
||||
pub from: String,
|
||||
pub gas: String,
|
||||
pub gas_price: String,
|
||||
pub hash: String,
|
||||
pub input: String,
|
||||
pub nonce: String,
|
||||
pub to: String,
|
||||
pub transaction_index: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
#[derive(Debug)]
|
||||
pub struct JsonRpcResult {
|
||||
pub json_rpc: String,
|
||||
pub result: String,
|
||||
pub error: String,
|
||||
pub id: u64,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash)]
|
||||
pub struct User {
|
||||
pub peer_id: String,
|
||||
pub relay_id: String,
|
||||
pub signature: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct GetUsersServiceResult {
|
||||
pub ret_code: i32,
|
||||
pub err_msg: String,
|
||||
pub users: Vec<User>,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct EmptyServiceResult {
|
||||
pub ret_code: i32,
|
||||
pub err_msg: String,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct ExistsServiceResult {
|
||||
pub ret_code: i32,
|
||||
pub err_msg: String,
|
||||
pub is_exists: bool,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
pub struct AuthResult {
|
||||
pub ret_code: i32,
|
||||
pub err_msg: String,
|
||||
pub is_authenticated: bool,
|
||||
}
|
8
fluence/tests/records/empty_struct.rs
Normal file
8
fluence/tests/records/empty_struct.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[fce]
|
||||
struct A {}
|
20
fluence/tests/records/struct_with_improper_types.rs
Normal file
20
fluence/tests/records/struct_with_improper_types.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[fce]
|
||||
struct StructWithBox {
|
||||
pub a: Box<i32>,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
struct StructWithRc {
|
||||
pub a: std::rc::Rc<i32>,
|
||||
}
|
||||
|
||||
#[fce]
|
||||
struct StructWithHashMap {
|
||||
pub a: std::collections::HashMap<i32, String>,
|
||||
}
|
17
fluence/tests/records/struct_with_improper_types.stderr
Normal file
17
fluence/tests/records/struct_with_improper_types.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/struct_with_improper_types.rs:9:12
|
||||
|
|
||||
9 | pub a: Box<i32>,
|
||||
| ^^^^^^^^
|
||||
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/struct_with_improper_types.rs:14:21
|
||||
|
|
||||
14 | pub a: std::rc::Rc<i32>,
|
||||
| ^^^^^^^
|
||||
|
||||
error: types with lifetimes or generics aren't allowed
|
||||
--> $DIR/struct_with_improper_types.rs:19:30
|
||||
|
|
||||
19 | pub a: std::collections::HashMap<i32, String>,
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
11
fluence/tests/records/struct_with_private_fields.rs
Normal file
11
fluence/tests/records/struct_with_private_fields.rs
Normal file
@ -0,0 +1,11 @@
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
use fluence::fce;
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[fce]
|
||||
struct StructWithPrivateFields {
|
||||
a: i32,
|
||||
b: usize,
|
||||
}
|
5
fluence/tests/records/struct_with_private_fields.stderr
Normal file
5
fluence/tests/records/struct_with_private_fields.stderr
Normal file
@ -0,0 +1,5 @@
|
||||
error: #[fce] could be applied only to struct with all public fields
|
||||
--> $DIR/struct_with_private_fields.rs:9:5
|
||||
|
|
||||
9 | a: i32,
|
||||
| ^^^^^^
|
16
fluence/tests/test_runner.rs
Normal file
16
fluence/tests/test_runner.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#[test]
|
||||
fn test() {
|
||||
let tests = trybuild::TestCases::new();
|
||||
tests.pass("tests/export_functions/arrays.rs");
|
||||
tests.pass("tests/export_functions/basic_types.rs");
|
||||
tests.compile_fail("tests/export_functions/improper_types.rs");
|
||||
|
||||
tests.pass("tests/import_functions/arrays.rs");
|
||||
tests.pass("tests/import_functions/basic_types.rs");
|
||||
tests.compile_fail("tests/import_functions/improper_types.rs");
|
||||
|
||||
tests.pass("tests/records/basic_structs.rs");
|
||||
tests.pass("tests/records/empty_struct.rs");
|
||||
tests.compile_fail("tests/records/struct_with_improper_types.rs");
|
||||
tests.compile_fail("tests/records/struct_with_private_fields.rs");
|
||||
}
|
Loading…
Reference in New Issue
Block a user