From cd21f80c59c89df344fd652b1e2ae4520c077e01 Mon Sep 17 00:00:00 2001 From: vms Date: Tue, 2 Mar 2021 11:38:03 +0300 Subject: [PATCH 01/41] initial version --- Cargo.toml | 3 ++- crates/macro-test/Cargo.toml | 21 +++++++++++++++ crates/macro-test/src/fce_test.rs | 16 ++++++++++++ crates/macro-test/src/lib.rs | 43 +++++++++++++++++++++++++++++++ crates/macro/Cargo.toml | 2 +- crates/macro/src/lib.rs | 14 ++++------ 6 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 crates/macro-test/Cargo.toml create mode 100644 crates/macro-test/src/fce_test.rs create mode 100644 crates/macro-test/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index a6d8d2a..0a6d9d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,8 @@ logger = ["fluence-sdk-main/logger"] [workspace] members = [ - "crates/main", "crates/macro", + "crates/macro-test", + "crates/main", "crates/wit", ] diff --git a/crates/macro-test/Cargo.toml b/crates/macro-test/Cargo.toml new file mode 100644 index 0000000..fd30b9a --- /dev/null +++ b/crates/macro-test/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "fluence-sdk-macro-test" +version = "0.4.2" # remember to update html_root_url +edition = "2018" +description = "Definition of the `#[fce_test]` macro" +documentation = "https://docs.rs/fluence/fluence-sdk-macro" +repository = "https://github.com/fluencelabs/rust-sdk/crates/macro" +authors = ["Fluence Labs"] +keywords = ["fluence", "sdk", "webassembly", "procedural_macros"] +categories = ["api-bindings", "wasm"] +license = "Apache-2.0" + +[package.metadata.docs.rs] # https://docs.rs/about +all-features = true + +[lib] +proc-macro = true + +[dependencies] +fluence-app-service = "0.5.2" +#fluence-sdk-wit = { path = "../wit", version = "=0.4.2" } diff --git a/crates/macro-test/src/fce_test.rs b/crates/macro-test/src/fce_test.rs new file mode 100644 index 0000000..3c7d24b --- /dev/null +++ b/crates/macro-test/src/fce_test.rs @@ -0,0 +1,16 @@ +/* + * 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. + */ + diff --git a/crates/macro-test/src/lib.rs b/crates/macro-test/src/lib.rs new file mode 100644 index 0000000..9bf03aa --- /dev/null +++ b/crates/macro-test/src/lib.rs @@ -0,0 +1,43 @@ +/* + * 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.4.2")] +#![deny( + dead_code, + nonstandard_style, + unused_imports, + unused_mut, + unused_unsafe, + unreachable_patterns +)] +#![warn(rust_2018_idioms)] +#![recursion_limit = "1024"] + +mod fce_test; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn fce_test(attr: TokenStream, input: TokenStream) -> TokenStream { + // into converts proc_macro::TokenStream to proc_macro2::TokenStream + match fce_impl(input.into()) { + Ok(v) => v, + // converts syn:error to proc_macro2::TokenStream + Err(e) => e.to_compile_error(), + } + // converts proc_macro2::TokenStream to proc_macro::TokenStream + .into() +} diff --git a/crates/macro/Cargo.toml b/crates/macro/Cargo.toml index 615b031..7bba341 100644 --- a/crates/macro/Cargo.toml +++ b/crates/macro/Cargo.toml @@ -2,7 +2,7 @@ name = "fluence-sdk-macro" version = "0.4.2" # 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"] diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs index 68e3075..9372cac 100644 --- a/crates/macro/src/lib.rs +++ b/crates/macro/src/lib.rs @@ -34,22 +34,18 @@ //! and how a struct could be passed: //! //! ``` -//! #[fce] -//! struct HostReturnValue { -//! pub error_code: i32, -//! pub outcome: Vec -//! } +//! 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) -> MountedBinaryResult; //! } //! //! ``` From 549b1d4a87b3ad399909205a03a5af0b191a5596 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 00:02:25 +0300 Subject: [PATCH 02/41] add sdk version --- Cargo.toml | 2 ++ src/lib.rs | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index a6d8d2a..41ec455 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ path = "src/lib.rs" fluence-sdk-macro = { path = "crates/macro", version = "=0.4.2" } fluence-sdk-main = { path = "crates/main", version = "=0.4.2" } +static_assertions = "1.1.0" + [features] # Print some internal logs by log_utf8_string debug = ["fluence-sdk-main/debug"] diff --git a/src/lib.rs b/src/lib.rs index 6d5250b..0ea598f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,3 +91,23 @@ pub mod internal { pub use fluence_sdk_main::set_result_ptr; pub use fluence_sdk_main::set_result_size; } + +const VERSION_SIZE: usize = env!("CARGO_PKG_VERSION").len(); + +const fn sdk_version() -> [u8; VERSION_SIZE] { + const VERSION_AS_STR: &[u8] = env!("CARGO_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_STR[byte_id]; + byte_id += 1; + } + + version_as_array +} + +#[cfg(target_arch = "wasm32")] +#[link_section = "__fluence_sdk_version"] +#[doc(hidden)] +pub static FLUENCE_SDK_VERSION: [u8; VERSION_SIZE] = sdk_version(); From d6521af102077f03644888ea8c92290e9e952caa Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 00:07:06 +0300 Subject: [PATCH 03/41] simplify the code --- src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0ea598f..ea6e11a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,15 +92,16 @@ pub mod internal { pub use fluence_sdk_main::set_result_size; } -const VERSION_SIZE: usize = env!("CARGO_PKG_VERSION").len(); +const PKG_VERSION: &str = env!("CARGO_PKG_VERSION"); +const VERSION_SIZE: usize = PKG_VERSION.len(); const fn sdk_version() -> [u8; VERSION_SIZE] { - const VERSION_AS_STR: &[u8] = env!("CARGO_PKG_VERSION").as_bytes(); + let version_as_str = 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_STR[byte_id]; + version_as_array[byte_id] = version_as_str[byte_id]; byte_id += 1; } From 695c870964cf51ee2d59171ef57bc89db1b20971 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 13:58:29 +0300 Subject: [PATCH 04/41] add module_manifest macro --- crates/main/src/lib.rs | 1 + crates/main/src/module_manifest.rs | 85 ++++++++++++++++++++++++++++++ src/lib.rs | 25 ++------- src/sdk_version_embedder.rs | 38 +++++++++++++ 4 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 crates/main/src/module_manifest.rs create mode 100644 src/sdk_version_embedder.rs diff --git a/crates/main/src/lib.rs b/crates/main/src/lib.rs index 41ce22e..3e10b3a 100644 --- a/crates/main/src/lib.rs +++ b/crates/main/src/lib.rs @@ -35,6 +35,7 @@ mod call_parameters; mod export_allocator; #[cfg(any(feature = "debug", feature = "logger"))] mod logger; +mod module_manifest; pub mod mounted_binary; mod result; diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs new file mode 100644 index 0000000..cf89979 --- /dev/null +++ b/crates/main/src/module_manifest.rs @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#[macro_export] +macro_rules! module_manifest { + ($authors:expr, $version:expr, $description:expr, $repository:expr) => { + const AUTHORS_SIZE: usize = $authors.as_bytes().len(); + const VERSION_SIZE: usize = $version.as_bytes().len(); + const DESCRIPTION_SIZE: usize = $description.as_bytes().len(); + const REPOSITORY_SIZE: usize = $repository.as_bytes().len(); + const FEILD_PREFIX_SIZE: usize = std::mem::size_of::(); + + const MANIFEST_SIZE: usize = AUTHORS_SIZE + + VERSION_SIZE + + DESCRIPTION_SIZE + + REPOSITORY_SIZE + + FEILD_PREFIX_SIZE * 4; + + const fn append_data( + mut manifest: [u8; MANIFEST_SIZE], + data: &'static str, + offset: usize, + ) -> ([u8; 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_id = 0; + while byte_id < FEILD_PREFIX_SIZE { + manifest[offset + byte_id] = data_len_le_bytes[byte_id]; + byte_id += 1; + } + + // write data + let mut byte_id = 0; + while byte_id < data_len { + manifest[FEILD_PREFIX_SIZE + offset + byte_id] = data_as_bytes[byte_id]; + byte_id += 1; + } + + (manifest, offset + FEILD_PREFIX_SIZE + data_len) + } + + const fn generate_manifest() -> [u8; MANIFEST_SIZE] { + let authors = $authors; + let version = $version; + let description = $description; + let repository = $repository; + + let manifest: [u8; MANIFEST_SIZE] = [0; MANIFEST_SIZE]; + + let offset = 0; + let (manifest, offset) = append_data(manifest, authors, offset); + let (manifest, offset) = append_data(manifest, version, offset); + let (manifest, offset) = append_data(manifest, description, offset); + let (manifest, _) = append_data(manifest, repository, offset); + + manifest + } + + #[cfg(target_arch = "wasm32")] + #[link_section = "__fluence_wasm_module_manifest"] + #[doc(hidden)] + pub static WASM_MODULE_MANIFEST: [u8; MANIFEST_SIZE] = generate_manifest(); + }; + + () => { + module_manifest!(env!("CARGO_PKG_AUTHORS"), env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_DESCRIPTION"), env!("CARGO_PKG_REPOSITORY")); + } +} diff --git a/src/lib.rs b/src/lib.rs index ea6e11a..37bdf06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,8 @@ )] #![warn(rust_2018_idioms)] +mod sdk_version_embedder; + pub use fluence_sdk_macro::fce; pub use fluence_sdk_main::CallParameters; @@ -83,6 +85,8 @@ pub use fluence_sdk_main::mounted_binary::Result as MountedBinaryResult; pub use fluence_sdk_main::mounted_binary::StringResult as MountedBinaryStringResult; pub use fluence_sdk_main::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 { @@ -91,24 +95,3 @@ pub mod internal { pub use fluence_sdk_main::set_result_ptr; pub use fluence_sdk_main::set_result_size; } - -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_str = 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_str[byte_id]; - byte_id += 1; - } - - version_as_array -} - -#[cfg(target_arch = "wasm32")] -#[link_section = "__fluence_sdk_version"] -#[doc(hidden)] -pub static FLUENCE_SDK_VERSION: [u8; VERSION_SIZE] = sdk_version(); diff --git a/src/sdk_version_embedder.rs b/src/sdk_version_embedder.rs new file mode 100644 index 0000000..7d0ec6b --- /dev/null +++ b/src/sdk_version_embedder.rs @@ -0,0 +1,38 @@ +/* + * 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 +} + +#[cfg(target_arch = "wasm32")] +#[link_section = "__fluence_sdk_version"] +#[doc(hidden)] +pub static FLUENCE_SDK_VERSION: [u8; VERSION_SIZE] = sdk_version(); From 66a57c59188dcb772f3ea1e6fe4a2564641d9937 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 14:28:46 +0300 Subject: [PATCH 05/41] fmt --- crates/main/src/module_manifest.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs index cf89979..c9f8d1d 100644 --- a/crates/main/src/module_manifest.rs +++ b/crates/main/src/module_manifest.rs @@ -80,6 +80,11 @@ macro_rules! module_manifest { }; () => { - module_manifest!(env!("CARGO_PKG_AUTHORS"), env!("CARGO_PKG_VERSION"), env!("CARGO_PKG_DESCRIPTION"), env!("CARGO_PKG_REPOSITORY")); - } + module_manifest!( + env!("CARGO_PKG_AUTHORS"), + env!("CARGO_PKG_VERSION"), + env!("CARGO_PKG_DESCRIPTION"), + env!("CARGO_PKG_REPOSITORY") + ); + }; } From 56a4d0a668644d73936a07847a9d4726b415e9c1 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 14:32:46 +0300 Subject: [PATCH 06/41] hard names --- crates/main/src/module_manifest.rs | 36 +++++++++++++++--------------- src/sdk_version_embedder.rs | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs index c9f8d1d..304ccf2 100644 --- a/crates/main/src/module_manifest.rs +++ b/crates/main/src/module_manifest.rs @@ -17,23 +17,23 @@ #[macro_export] macro_rules! module_manifest { ($authors:expr, $version:expr, $description:expr, $repository:expr) => { - const AUTHORS_SIZE: usize = $authors.as_bytes().len(); - const VERSION_SIZE: usize = $version.as_bytes().len(); - const DESCRIPTION_SIZE: usize = $description.as_bytes().len(); - const REPOSITORY_SIZE: usize = $repository.as_bytes().len(); - const FEILD_PREFIX_SIZE: usize = std::mem::size_of::(); + 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_FEILD_PREFIX_SIZE: usize = std::mem::size_of::(); - const MANIFEST_SIZE: usize = AUTHORS_SIZE - + VERSION_SIZE - + DESCRIPTION_SIZE - + REPOSITORY_SIZE - + FEILD_PREFIX_SIZE * 4; + const __FCE_MANIFEST_SIZE: usize = __FCE_SDK_AUTHORS_SIZE + + __FCE_SDK_VERSION_SIZE + + __FCE_SDK_DESCRIPTION_SIZE + + __FCE_SDK_REPOSITORY_SIZE + + __FCE_SDK_FEILD_PREFIX_SIZE * 4; const fn append_data( - mut manifest: [u8; MANIFEST_SIZE], + mut manifest: [u8; __FCE_MANIFEST_SIZE], data: &'static str, offset: usize, - ) -> ([u8; MANIFEST_SIZE], usize) { + ) -> ([u8; __FCE_MANIFEST_SIZE], usize) { let data_as_bytes = data.as_bytes(); let data_len = data_as_bytes.len(); @@ -41,7 +41,7 @@ macro_rules! module_manifest { let data_len_u64 = data_len as u64; let data_len_le_bytes = data_len_u64.to_le_bytes(); let mut byte_id = 0; - while byte_id < FEILD_PREFIX_SIZE { + while byte_id < __FCE_SDK_FEILD_PREFIX_SIZE { manifest[offset + byte_id] = data_len_le_bytes[byte_id]; byte_id += 1; } @@ -49,20 +49,20 @@ macro_rules! module_manifest { // write data let mut byte_id = 0; while byte_id < data_len { - manifest[FEILD_PREFIX_SIZE + offset + byte_id] = data_as_bytes[byte_id]; + manifest[__FCE_SDK_FEILD_PREFIX_SIZE + offset + byte_id] = data_as_bytes[byte_id]; byte_id += 1; } - (manifest, offset + FEILD_PREFIX_SIZE + data_len) + (manifest, offset + __FCE_SDK_FEILD_PREFIX_SIZE + data_len) } - const fn generate_manifest() -> [u8; MANIFEST_SIZE] { + const fn generate_manifest() -> [u8; __FCE_MANIFEST_SIZE] { let authors = $authors; let version = $version; let description = $description; let repository = $repository; - let manifest: [u8; MANIFEST_SIZE] = [0; MANIFEST_SIZE]; + let manifest: [u8; __FCE_MANIFEST_SIZE] = [0; __FCE_MANIFEST_SIZE]; let offset = 0; let (manifest, offset) = append_data(manifest, authors, offset); @@ -76,7 +76,7 @@ macro_rules! module_manifest { #[cfg(target_arch = "wasm32")] #[link_section = "__fluence_wasm_module_manifest"] #[doc(hidden)] - pub static WASM_MODULE_MANIFEST: [u8; MANIFEST_SIZE] = generate_manifest(); + pub static __FCE_SDK_WASM_MODULE_MANIFEST: [u8; __FCE_MANIFEST_SIZE] = generate_manifest(); }; () => { diff --git a/src/sdk_version_embedder.rs b/src/sdk_version_embedder.rs index 7d0ec6b..e3463cc 100644 --- a/src/sdk_version_embedder.rs +++ b/src/sdk_version_embedder.rs @@ -35,4 +35,4 @@ const fn sdk_version() -> [u8; VERSION_SIZE] { #[cfg(target_arch = "wasm32")] #[link_section = "__fluence_sdk_version"] #[doc(hidden)] -pub static FLUENCE_SDK_VERSION: [u8; VERSION_SIZE] = sdk_version(); +pub static __FCE_SDK_VERSION: [u8; VERSION_SIZE] = sdk_version(); From 38d8e6536801780c4dd1066bc38deda3f10bfd98 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 14:35:03 +0300 Subject: [PATCH 07/41] update rust compiler in circleci; bump crate versions --- .circleci/config.yml | 6 +++--- Cargo.toml | 6 +++--- crates/macro/Cargo.toml | 4 ++-- crates/main/Cargo.toml | 4 ++-- crates/wit/Cargo.toml | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bda9682..927365e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,9 +12,9 @@ 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 toolchain install nightly-2021-02-27 + rustup default nightly-2021-02-27 + rustup override set nightly-2021-02-27 rustup target add wasm32-unknown-unknown rustup component add rustfmt rustup component add clippy diff --git a/Cargo.toml b/Cargo.toml index 41ec455..e798e6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence" -version = "0.4.2" # remember to update html_root_url +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" @@ -18,8 +18,8 @@ all-features = true path = "src/lib.rs" [dependencies] -fluence-sdk-macro = { path = "crates/macro", version = "=0.4.2" } -fluence-sdk-main = { path = "crates/main", version = "=0.4.2" } +fluence-sdk-macro = { path = "crates/macro", version = "=0.5.0" } +fluence-sdk-main = { path = "crates/main", version = "=0.5.0" } static_assertions = "1.1.0" diff --git a/crates/macro/Cargo.toml b/crates/macro/Cargo.toml index 615b031..6fb8127 100644 --- a/crates/macro/Cargo.toml +++ b/crates/macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence-sdk-macro" -version = "0.4.2" # remember to update html_root_url +version = "0.5.0" # remember to update html_root_url edition = "2018" description = "Definition of `#[invoke_handler]` attribute" documentation = "https://docs.rs/fluence/fluence-sdk-macro" @@ -17,4 +17,4 @@ all-features = true proc-macro = true [dependencies] -fluence-sdk-wit = { path = "../wit", version = "=0.4.2" } +fluence-sdk-wit = { path = "../wit", version = "=0.5.0" } diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index 10b00ef..7d601b8 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence-sdk-main" -version = "0.4.2" # remember to update html_root_url +version = "0.5.0" # remember to update html_root_url edition = "2018" description = "Rust SDK for applications for the Fluence network" documentation = "https://docs.rs/fluence/fluence-sdk-macro" @@ -18,7 +18,7 @@ path = "src/lib.rs" crate-type = ["rlib"] [dependencies] -fluence-sdk-macro = { path = "../macro", version = "=0.4.2" } +fluence-sdk-macro = { path = "../macro", version = "=0.5.0" } log = { version = "0.4.8", features = ["std"] } serde = "=1.0.118" diff --git a/crates/wit/Cargo.toml b/crates/wit/Cargo.toml index 9bef5a1..791c5d0 100644 --- a/crates/wit/Cargo.toml +++ b/crates/wit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence-sdk-wit" -version = "0.4.2" # remember to update html_root_url +version = "0.5.0" # remember to update html_root_url edition = "2018" description = "Webassembly interface-types generator" documentation = "https://docs.rs/fluence/fluence-sdk-macro" From eab7d746ef489a02cc21a96f11b8ecb375fe456a Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 14:36:01 +0300 Subject: [PATCH 08/41] change doc root link --- crates/macro/src/lib.rs | 2 +- crates/main/src/lib.rs | 2 +- crates/wit/src/lib.rs | 2 +- src/lib.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs index 68e3075..add33a9 100644 --- a/crates/macro/src/lib.rs +++ b/crates/macro/src/lib.rs @@ -54,7 +54,7 @@ //! //! ``` -#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.2")] +#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.5.0")] #![deny( dead_code, nonstandard_style, diff --git a/crates/main/src/lib.rs b/crates/main/src/lib.rs index 3e10b3a..f8b6403 100644 --- a/crates/main/src/lib.rs +++ b/crates/main/src/lib.rs @@ -19,7 +19,7 @@ #![allow(clippy::missing_safety_doc)] #![allow(clippy::needless_doctest_main)] -#![doc(html_root_url = "https://docs.rs/fluence-sdk-main/0.4.2")] +#![doc(html_root_url = "https://docs.rs/fluence-sdk-main/0.5.0")] #![deny( dead_code, nonstandard_style, diff --git a/crates/wit/src/lib.rs b/crates/wit/src/lib.rs index 22e193a..600b12e 100644 --- a/crates/wit/src/lib.rs +++ b/crates/wit/src/lib.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -#![doc(html_root_url = "https://docs.rs/wit-support/0.4.2")] +#![doc(html_root_url = "https://docs.rs/wit-support/0.5.0")] #![deny( dead_code, nonstandard_style, diff --git a/src/lib.rs b/src/lib.rs index 37bdf06..c4e8c21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ //! pub fn curl_get(url: String) -> String; //! } //! ``` -#![doc(html_root_url = "https://docs.rs/fluence/0.4.2")] +#![doc(html_root_url = "https://docs.rs/fluence/0.5.0")] #![deny( dead_code, nonstandard_style, From 3d72d5885e565adbcb21194088efd8ed6a8825bf Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 14:43:47 +0300 Subject: [PATCH 09/41] simplify the code --- crates/main/src/module_manifest.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs index 304ccf2..2dac510 100644 --- a/crates/main/src/module_manifest.rs +++ b/crates/main/src/module_manifest.rs @@ -57,18 +57,13 @@ macro_rules! module_manifest { } const fn generate_manifest() -> [u8; __FCE_MANIFEST_SIZE] { - let authors = $authors; - let version = $version; - let description = $description; - let repository = $repository; - let manifest: [u8; __FCE_MANIFEST_SIZE] = [0; __FCE_MANIFEST_SIZE]; let offset = 0; - let (manifest, offset) = append_data(manifest, authors, offset); - let (manifest, offset) = append_data(manifest, version, offset); - let (manifest, offset) = append_data(manifest, description, offset); - let (manifest, _) = append_data(manifest, repository, offset); + let (manifest, offset) = append_data(manifest, $authors, offset); + let (manifest, offset) = append_data(manifest, $version, offset); + let (manifest, offset) = append_data(manifest, $description, offset); + let (manifest, _) = append_data(manifest, $repository, offset); manifest } From 00c72c6438a2afc8e24cd77f8d52bd79c58562b2 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 19:01:16 +0300 Subject: [PATCH 10/41] rearrange consts --- crates/main/src/lib.rs | 4 ++++ crates/main/src/module_manifest.rs | 3 +++ {src => crates/main/src}/sdk_version_embedder.rs | 3 +++ src/lib.rs | 2 -- 4 files changed, 10 insertions(+), 2 deletions(-) rename {src => crates/main/src}/sdk_version_embedder.rs (88%) diff --git a/crates/main/src/lib.rs b/crates/main/src/lib.rs index f8b6403..1213037 100644 --- a/crates/main/src/lib.rs +++ b/crates/main/src/lib.rs @@ -38,6 +38,7 @@ mod logger; mod module_manifest; pub mod mounted_binary; mod result; +mod sdk_version_embedder; pub use call_parameters::CallParameters; pub use call_parameters::SecurityTetraplet; @@ -59,6 +60,9 @@ pub use result::get_result_size; pub use result::set_result_ptr; pub use result::set_result_size; +pub use module_manifest::MANIFEST_SECTION_NAME; +pub use sdk_version_embedder::VERSION_SECTION_NAME; + #[allow(unused_variables)] pub(crate) fn log>(msg: S) { // logs will be printed only if debug feature is enabled diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs index 2dac510..ac8a97b 100644 --- a/crates/main/src/module_manifest.rs +++ b/crates/main/src/module_manifest.rs @@ -14,6 +14,9 @@ * 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) => { diff --git a/src/sdk_version_embedder.rs b/crates/main/src/sdk_version_embedder.rs similarity index 88% rename from src/sdk_version_embedder.rs rename to crates/main/src/sdk_version_embedder.rs index e3463cc..57c2071 100644 --- a/src/sdk_version_embedder.rs +++ b/crates/main/src/sdk_version_embedder.rs @@ -32,6 +32,9 @@ const fn sdk_version() -> [u8; VERSION_SIZE] { 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)] diff --git a/src/lib.rs b/src/lib.rs index c4e8c21..f1de40b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,8 +67,6 @@ )] #![warn(rust_2018_idioms)] -mod sdk_version_embedder; - pub use fluence_sdk_macro::fce; pub use fluence_sdk_main::CallParameters; From 42262b7e80603dcf52e31060b23321b3df43d3d2 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 19:46:43 +0300 Subject: [PATCH 11/41] delete excess dep --- Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e798e6e..44098b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,8 +21,6 @@ path = "src/lib.rs" fluence-sdk-macro = { path = "crates/macro", version = "=0.5.0" } fluence-sdk-main = { path = "crates/main", version = "=0.5.0" } -static_assertions = "1.1.0" - [features] # Print some internal logs by log_utf8_string debug = ["fluence-sdk-main/debug"] From 6c477059abc1730f36d838e370610ad621786285 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 11 Mar 2021 19:59:55 +0300 Subject: [PATCH 12/41] rename __FCE_SDK_WASM_MODULE_MANIFEST to __FCE_WASM_MODULE_MANIFEST --- crates/main/src/module_manifest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs index ac8a97b..ba99ee9 100644 --- a/crates/main/src/module_manifest.rs +++ b/crates/main/src/module_manifest.rs @@ -74,7 +74,7 @@ macro_rules! module_manifest { #[cfg(target_arch = "wasm32")] #[link_section = "__fluence_wasm_module_manifest"] #[doc(hidden)] - pub static __FCE_SDK_WASM_MODULE_MANIFEST: [u8; __FCE_MANIFEST_SIZE] = generate_manifest(); + pub static __FCE_WASM_MODULE_MANIFEST: [u8; __FCE_MANIFEST_SIZE] = generate_manifest(); }; () => { From d3e1b6d3b53509a45388c331c75dfd4b5b38cee6 Mon Sep 17 00:00:00 2001 From: vms Date: Fri, 12 Mar 2021 10:29:26 +0300 Subject: [PATCH 13/41] review fixes --- crates/main/src/module_manifest.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs index ba99ee9..95328eb 100644 --- a/crates/main/src/module_manifest.rs +++ b/crates/main/src/module_manifest.rs @@ -24,13 +24,13 @@ macro_rules! module_manifest { 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_FEILD_PREFIX_SIZE: usize = std::mem::size_of::(); + const __FCE_SDK_FIELD_PREFIX_SIZE: usize = std::mem::size_of::(); const __FCE_MANIFEST_SIZE: usize = __FCE_SDK_AUTHORS_SIZE + __FCE_SDK_VERSION_SIZE + __FCE_SDK_DESCRIPTION_SIZE + __FCE_SDK_REPOSITORY_SIZE - + __FCE_SDK_FEILD_PREFIX_SIZE * 4; + + __FCE_SDK_FIELD_PREFIX_SIZE * 4; const fn append_data( mut manifest: [u8; __FCE_MANIFEST_SIZE], @@ -43,20 +43,20 @@ macro_rules! module_manifest { // 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_id = 0; - while byte_id < __FCE_SDK_FEILD_PREFIX_SIZE { - manifest[offset + byte_id] = data_len_le_bytes[byte_id]; - byte_id += 1; + 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_id = 0; - while byte_id < data_len { - manifest[__FCE_SDK_FEILD_PREFIX_SIZE + offset + byte_id] = data_as_bytes[byte_id]; - byte_id += 1; + 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_FEILD_PREFIX_SIZE + data_len) + (manifest, offset + __FCE_SDK_FIELD_PREFIX_SIZE + data_len) } const fn generate_manifest() -> [u8; __FCE_MANIFEST_SIZE] { From fbd021e3e235d147f8139f8ae252e722ff8d09c6 Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 28 Mar 2021 17:05:35 +0300 Subject: [PATCH 14/41] intermediate --- crates/macro-test/Cargo.toml | 9 ++++- crates/macro-test/src/attributes.rs | 61 +++++++++++++++++++++++++++++ crates/macro-test/src/fce_test.rs | 54 +++++++++++++++++++++++++ crates/macro-test/src/lib.rs | 38 +++++++++++++----- crates/wit/Cargo.toml | 8 ++-- 5 files changed, 156 insertions(+), 14 deletions(-) create mode 100644 crates/macro-test/src/attributes.rs diff --git a/crates/macro-test/Cargo.toml b/crates/macro-test/Cargo.toml index fd30b9a..ef3c7ab 100644 --- a/crates/macro-test/Cargo.toml +++ b/crates/macro-test/Cargo.toml @@ -17,5 +17,12 @@ all-features = true proc-macro = true [dependencies] -fluence-app-service = "0.5.2" +fluence-faas = "0.5.2" +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.65', features = ['full'] } +uuid = { version = "0.8.2", features = ["v4"] } + #fluence-sdk-wit = { path = "../wit", version = "=0.4.2" } diff --git a/crates/macro-test/src/attributes.rs b/crates/macro-test/src/attributes.rs new file mode 100644 index 0000000..49f36c3 --- /dev/null +++ b/crates/macro-test/src/attributes.rs @@ -0,0 +1,61 @@ +/* + * 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 syn::parse::Parse; +use syn::parse::ParseStream; + +#[derive(Debug, Default, Clone)] +pub(crate) struct FCETestAttributes { + pub(crate) config_path: String, +} + +impl Parse for FCETestAttributes { + fn parse(input: ParseStream<'_>) -> syn::Result { + let config_file_path = parse_config_file_path(input)?; + let attributes = FCETestAttributes { + config_path: config_file_path, + }; + + Ok(attributes) + } +} + +pub(crate) fn parse_config_file_path(token_stream: ParseStream<'_>) -> syn::Result { + let attr_name = token_stream.step(|cursor| match cursor.ident() { + Some((ident, rem)) => Ok((ident, rem)), + None => Err(cursor.error("Expected a valid identifier")), + })?; + + match attr_name.to_string().as_str() { + "config" => { + // trying to parse `=` + token_stream.parse::()?; + + match token_stream.parse::() { + Ok(config_file_path) => Ok(config_file_path.to_string()), + Err(e) => Err(syn::Error::new( + attr_name.span(), + format!("failed to parse a config file path: {}", e), + )), + } + } + + attr => Err(syn::Error::new( + attr_name.span(), + format!("Expected 'config' identifier, but {} found", attr), + )), + } +} diff --git a/crates/macro-test/src/fce_test.rs b/crates/macro-test/src/fce_test.rs index 3c7d24b..143967e 100644 --- a/crates/macro-test/src/fce_test.rs +++ b/crates/macro-test/src/fce_test.rs @@ -14,3 +14,57 @@ * limitations under the License. */ +use proc_macro2::TokenStream; +use quote::quote; + +pub(super) fn fce_test_impl( + attr: TokenStream, + func_input: syn::ItemFn, +) -> Result { + use crate::attributes::FCETestAttributes; + + let attrs = syn::parse2::(attr).map_err(|e| e.into_compile_error())?; + let generated_test = generate_test_glue_code(func_input, &attrs.config_path); + + Ok(generated_test) +} + +fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TokenStream { + let fce_ctor = generate_fce_ctor(config_path); + let original_block = func.block; + let signature = func.sig; + + quote! { + #[test] + #signature { + #fce_ctor + + #original_block + } + } +} + +fn generate_fce_ctor(config_path: &str) -> TokenStream { + let config_path = new_ident(config_path); + + let tmp_file_path = std::env::temp_dir(); + let random_uuid = uuid::Uuid::new_v4().to_string(); + let service_id = new_ident(&random_uuid); + + let tmp_file_path = tmp_file_path.join(random_uuid); + let tmp_file_path = tmp_file_path.to_string_lossy().to_string(); + let tmp_file_path = new_ident(&tmp_file_path); + + quote! { + let mut __fce__generated_fce_config = fluence_faas::TomlAppServiceConfig::load(#config_path) + .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_file_path); + + let fce = fce_app_service::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)); + } +} + +fn new_ident(name: &str) -> syn::Ident { + syn::Ident::new(name, proc_macro2::Span::call_site()) +} diff --git a/crates/macro-test/src/lib.rs b/crates/macro-test/src/lib.rs index 9bf03aa..4080b56 100644 --- a/crates/macro-test/src/lib.rs +++ b/crates/macro-test/src/lib.rs @@ -15,6 +15,7 @@ */ #![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.2")] +/* #![deny( dead_code, nonstandard_style, @@ -23,21 +24,40 @@ unused_unsafe, unreachable_patterns )] + */ #![warn(rust_2018_idioms)] #![recursion_limit = "1024"] +mod attributes; mod fce_test; +use fce_test::fce_test_impl; use proc_macro::TokenStream; +/// This macro allows user to write tests for services in the following form: +///```rust +/// #[fce_test(config = "/path/to/Config.toml")] +/// fn test() { +/// let service_result = fce.call("greeting", "name"); +/// assert_eq!(&service_result, "Hi, name!"); +/// } +///``` +/// +/// This function is desugrated in the following way: +///```rust +/// #[test] +/// fn test() { +/// let fce = fluence_faas::FluenceFaaS::with_raw_config("/path/to/Config.toml") +/// .unwrap_or_else(|e| panic!("test instance can't be instantiated: {}", e)); +/// let service_result = fce.call("greeting", "name"); +/// assert_eq!(&service_result, "Hi, name!"); +/// } +///``` + #[proc_macro_attribute] -pub fn fce_test(attr: TokenStream, input: TokenStream) -> TokenStream { - // into converts proc_macro::TokenStream to proc_macro2::TokenStream - match fce_impl(input.into()) { - Ok(v) => v, - // converts syn:error to proc_macro2::TokenStream - Err(e) => e.to_compile_error(), - } - // converts proc_macro2::TokenStream to proc_macro::TokenStream - .into() +pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream { + let func_input = syn::parse_macro_input!(input as syn::ItemFn); + let result = fce_test_impl(attrs.into(), func_input).unwrap_or_else(std::convert::identity); + + result.into() } diff --git a/crates/wit/Cargo.toml b/crates/wit/Cargo.toml index 791c5d0..ba91fe6 100644 --- a/crates/wit/Cargo.toml +++ b/crates/wit/Cargo.toml @@ -14,9 +14,9 @@ license = "Apache-2.0" 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.65', features = ['full'] } +uuid = { version = "0.8.2", features = ["v4"] } From 0ed7b3e6b8ce1150543bec3ddd371f6da405274a Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 28 Mar 2021 18:02:36 +0300 Subject: [PATCH 15/41] misc improvements --- Cargo.toml | 12 +++++++++--- crates/{macro => fce-macro}/Cargo.toml | 0 crates/{macro => fce-macro}/src/lib.rs | 0 crates/{macro-test => fce-test-macro}/Cargo.toml | 10 +++------- .../{macro-test => fce-test-macro}/src/attributes.rs | 0 .../{macro-test => fce-test-macro}/src/fce_test.rs | 4 ++-- crates/{macro-test => fce-test-macro}/src/lib.rs | 1 - crates/main/Cargo.toml | 2 +- src/lib.rs | 8 ++++++++ 9 files changed, 23 insertions(+), 14 deletions(-) rename crates/{macro => fce-macro}/Cargo.toml (100%) rename crates/{macro => fce-macro}/src/lib.rs (100%) rename crates/{macro-test => fce-test-macro}/Cargo.toml (72%) rename crates/{macro-test => fce-test-macro}/src/attributes.rs (100%) rename crates/{macro-test => fce-test-macro}/src/fce_test.rs (89%) rename crates/{macro-test => fce-test-macro}/src/lib.rs (99%) diff --git a/Cargo.toml b/Cargo.toml index 374b260..2cd774f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,12 @@ all-features = true path = "src/lib.rs" [dependencies] -fluence-sdk-macro = { path = "crates/macro", version = "=0.5.0" } +fluence-sdk-macro = { path = "crates/fce-macro", version = "=0.5.0" } +fluence-sdk-test-macro = { path = "crates/fce-test-macro", version = "=0.5.0", optional = true } fluence-sdk-main = { path = "crates/main", version = "=0.5.0" } +fluence-app-service= { version = "0.5.2", features = ["raw-module-api"], optional = true } + [features] # Print some internal logs by log_utf8_string debug = ["fluence-sdk-main/debug"] @@ -28,10 +31,13 @@ debug = ["fluence-sdk-main/debug"] # Enable logger (this will cause log_utf8_string to appear in imports) logger = ["fluence-sdk-main/logger"] +# Enable the fce-test features (it'll bring fluence-app-service as a dependency) +fce-test = ["fluence-sdk-test-macro", "fluence-app-service"] + [workspace] members = [ - "crates/macro", - "crates/macro-test", + "crates/fce-macro", + "crates/fce-test-macro", "crates/main", "crates/wit", ] diff --git a/crates/macro/Cargo.toml b/crates/fce-macro/Cargo.toml similarity index 100% rename from crates/macro/Cargo.toml rename to crates/fce-macro/Cargo.toml diff --git a/crates/macro/src/lib.rs b/crates/fce-macro/src/lib.rs similarity index 100% rename from crates/macro/src/lib.rs rename to crates/fce-macro/src/lib.rs diff --git a/crates/macro-test/Cargo.toml b/crates/fce-test-macro/Cargo.toml similarity index 72% rename from crates/macro-test/Cargo.toml rename to crates/fce-test-macro/Cargo.toml index ef3c7ab..cde8466 100644 --- a/crates/macro-test/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -1,10 +1,9 @@ [package] -name = "fluence-sdk-macro-test" -version = "0.4.2" # remember to update html_root_url +name = "fluence-sdk-test-macro" +version = "0.5.0" # remember to update html_root_url edition = "2018" description = "Definition of the `#[fce_test]` macro" -documentation = "https://docs.rs/fluence/fluence-sdk-macro" -repository = "https://github.com/fluencelabs/rust-sdk/crates/macro" +repository = "https://github.com/fluencelabs/rust-sdk/crates/macro-test" authors = ["Fluence Labs"] keywords = ["fluence", "sdk", "webassembly", "procedural_macros"] categories = ["api-bindings", "wasm"] @@ -17,12 +16,9 @@ all-features = true proc-macro = true [dependencies] -fluence-faas = "0.5.2" 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.65', features = ['full'] } uuid = { version = "0.8.2", features = ["v4"] } - -#fluence-sdk-wit = { path = "../wit", version = "=0.4.2" } diff --git a/crates/macro-test/src/attributes.rs b/crates/fce-test-macro/src/attributes.rs similarity index 100% rename from crates/macro-test/src/attributes.rs rename to crates/fce-test-macro/src/attributes.rs diff --git a/crates/macro-test/src/fce_test.rs b/crates/fce-test-macro/src/fce_test.rs similarity index 89% rename from crates/macro-test/src/fce_test.rs rename to crates/fce-test-macro/src/fce_test.rs index 143967e..678432d 100644 --- a/crates/macro-test/src/fce_test.rs +++ b/crates/fce-test-macro/src/fce_test.rs @@ -56,11 +56,11 @@ fn generate_fce_ctor(config_path: &str) -> TokenStream { let tmp_file_path = new_ident(&tmp_file_path); quote! { - let mut __fce__generated_fce_config = fluence_faas::TomlAppServiceConfig::load(#config_path) + let mut __fce__generated_fce_config = fluence::internal::test::TomlAppServiceConfig::load(#config_path) .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_file_path); - let fce = fce_app_service::AppService::new_with_empty_facade(__fce__generated_fce_config, #service_id, std::collections::HashMap::new()) + let fce = fluence::internal::test::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)); } } diff --git a/crates/macro-test/src/lib.rs b/crates/fce-test-macro/src/lib.rs similarity index 99% rename from crates/macro-test/src/lib.rs rename to crates/fce-test-macro/src/lib.rs index 4080b56..7e693b1 100644 --- a/crates/macro-test/src/lib.rs +++ b/crates/fce-test-macro/src/lib.rs @@ -53,7 +53,6 @@ use proc_macro::TokenStream; /// assert_eq!(&service_result, "Hi, name!"); /// } ///``` - #[proc_macro_attribute] pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream { let func_input = syn::parse_macro_input!(input as syn::ItemFn); diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index 7d601b8..b2a3b65 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" crate-type = ["rlib"] [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" diff --git a/src/lib.rs b/src/lib.rs index f1de40b..87eab47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,6 +68,8 @@ #![warn(rust_2018_idioms)] pub use fluence_sdk_macro::fce; +#[cfg(feature = "fce-test")] +pub use fluence_sdk_test_macro::fce_test; pub use fluence_sdk_main::CallParameters; pub use fluence_sdk_main::SecurityTetraplet; @@ -92,4 +94,10 @@ pub mod internal { pub use fluence_sdk_main::get_result_size; pub use fluence_sdk_main::set_result_ptr; pub use fluence_sdk_main::set_result_size; + + #[cfg(feature = "fce-test")] + pub mod test { + pub use fluence_app_service::AppService; + pub use fluence_app_service::AppServiceConfig; + } } From 287090ae5a8ebc27f9a4d919fc196d3bb370bcef Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 28 Mar 2021 19:11:29 +0300 Subject: [PATCH 16/41] adjust crate versions --- crates/fce-test-macro/Cargo.toml | 2 +- crates/wit/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/fce-test-macro/Cargo.toml b/crates/fce-test-macro/Cargo.toml index cde8466..e95cb65 100644 --- a/crates/fce-test-macro/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -20,5 +20,5 @@ 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.65', features = ['full'] } +syn = { version = '1.0.64', features = ['full'] } uuid = { version = "0.8.2", features = ["v4"] } diff --git a/crates/wit/Cargo.toml b/crates/wit/Cargo.toml index ba91fe6..cbb511f 100644 --- a/crates/wit/Cargo.toml +++ b/crates/wit/Cargo.toml @@ -18,5 +18,5 @@ 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.65', features = ['full'] } +syn = { version = '1.0.64', features = ['full'] } uuid = { version = "0.8.2", features = ["v4"] } From e4c7ed319bd9200d85215ef5032a4fe7fe9742dd Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 28 Mar 2021 22:51:50 +0300 Subject: [PATCH 17/41] cleanup --- Cargo.toml | 38 ++-------------------- crates/fce-test-macro/Cargo.toml | 3 +- crates/fce-test-macro/src/attributes.rs | 43 ++----------------------- crates/fce-test-macro/src/fce_test.rs | 43 +++++++++++++------------ crates/fce-test-macro/src/lib.rs | 7 ++-- crates/main/src/module_manifest.rs | 10 +++--- fluence-test/Cargo.toml | 22 +++++++++++++ fluence-test/src/lib.rs | 36 +++++++++++++++++++++ fluence/Cargo.toml | 29 +++++++++++++++++ {src => fluence/src}/lib.rs | 6 ---- 10 files changed, 121 insertions(+), 116 deletions(-) create mode 100644 fluence-test/Cargo.toml create mode 100644 fluence-test/src/lib.rs create mode 100644 fluence/Cargo.toml rename {src => fluence/src}/lib.rs (94%) diff --git a/Cargo.toml b/Cargo.toml index 2cd774f..42176e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,43 +1,9 @@ -[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" - -[dependencies] -fluence-sdk-macro = { path = "crates/fce-macro", version = "=0.5.0" } -fluence-sdk-test-macro = { path = "crates/fce-test-macro", version = "=0.5.0", optional = true } -fluence-sdk-main = { path = "crates/main", version = "=0.5.0" } - -fluence-app-service= { version = "0.5.2", features = ["raw-module-api"], optional = true } - -[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"] - -# Enable the fce-test features (it'll bring fluence-app-service as a dependency) -fce-test = ["fluence-sdk-test-macro", "fluence-app-service"] - [workspace] members = [ "crates/fce-macro", "crates/fce-test-macro", "crates/main", "crates/wit", + "fluence", + "fluence-test" ] diff --git a/crates/fce-test-macro/Cargo.toml b/crates/fce-test-macro/Cargo.toml index e95cb65..e0b9cd5 100644 --- a/crates/fce-test-macro/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -18,7 +18,6 @@ proc-macro = true [dependencies] 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.64', features = ['full'] } uuid = { version = "0.8.2", features = ["v4"] } +darling = "0.12.2" diff --git a/crates/fce-test-macro/src/attributes.rs b/crates/fce-test-macro/src/attributes.rs index 49f36c3..1393ff8 100644 --- a/crates/fce-test-macro/src/attributes.rs +++ b/crates/fce-test-macro/src/attributes.rs @@ -14,48 +14,9 @@ * limitations under the License. */ -use syn::parse::Parse; -use syn::parse::ParseStream; +use darling::FromMeta; -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, FromMeta)] pub(crate) struct FCETestAttributes { pub(crate) config_path: String, } - -impl Parse for FCETestAttributes { - fn parse(input: ParseStream<'_>) -> syn::Result { - let config_file_path = parse_config_file_path(input)?; - let attributes = FCETestAttributes { - config_path: config_file_path, - }; - - Ok(attributes) - } -} - -pub(crate) fn parse_config_file_path(token_stream: ParseStream<'_>) -> syn::Result { - let attr_name = token_stream.step(|cursor| match cursor.ident() { - Some((ident, rem)) => Ok((ident, rem)), - None => Err(cursor.error("Expected a valid identifier")), - })?; - - match attr_name.to_string().as_str() { - "config" => { - // trying to parse `=` - token_stream.parse::()?; - - match token_stream.parse::() { - Ok(config_file_path) => Ok(config_file_path.to_string()), - Err(e) => Err(syn::Error::new( - attr_name.span(), - format!("failed to parse a config file path: {}", e), - )), - } - } - - attr => Err(syn::Error::new( - attr_name.span(), - format!("Expected 'config' identifier, but {} found", attr), - )), - } -} diff --git a/crates/fce-test-macro/src/fce_test.rs b/crates/fce-test-macro/src/fce_test.rs index 678432d..2d63100 100644 --- a/crates/fce-test-macro/src/fce_test.rs +++ b/crates/fce-test-macro/src/fce_test.rs @@ -14,22 +14,27 @@ * limitations under the License. */ -use proc_macro2::TokenStream; +use crate::attributes::FCETestAttributes; + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; use quote::quote; -pub(super) fn fce_test_impl( - attr: TokenStream, - func_input: syn::ItemFn, -) -> Result { - use crate::attributes::FCETestAttributes; +pub(super) fn fce_test_impl(attrs: TokenStream, func_input: syn::ItemFn) -> TokenStream { + use darling::FromMeta; - let attrs = syn::parse2::(attr).map_err(|e| e.into_compile_error())?; - let generated_test = generate_test_glue_code(func_input, &attrs.config_path); + let attrs = syn::parse_macro_input!(attrs as syn::AttributeArgs); + let attrs = match FCETestAttributes::from_list(&attrs) { + Ok(v) => v, + Err(e) => { + return TokenStream::from(e.write_errors()); + } + }; - Ok(generated_test) + generate_test_glue_code(func_input, &attrs.config_path).into() } -fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TokenStream { +fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TokenStream2 { let fce_ctor = generate_fce_ctor(config_path); let original_block = func.block; let signature = func.sig; @@ -44,27 +49,23 @@ fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TokenStream } } -fn generate_fce_ctor(config_path: &str) -> TokenStream { - let config_path = new_ident(config_path); +fn generate_fce_ctor(config_path: &str) -> TokenStream2 { + let config_path = quote! { #config_path }; let tmp_file_path = std::env::temp_dir(); let random_uuid = uuid::Uuid::new_v4().to_string(); - let service_id = new_ident(&random_uuid); + let service_id = quote! { #random_uuid }; let tmp_file_path = tmp_file_path.join(random_uuid); let tmp_file_path = tmp_file_path.to_string_lossy().to_string(); - let tmp_file_path = new_ident(&tmp_file_path); + let tmp_file_path = quote! { #tmp_file_path }; quote! { - let mut __fce__generated_fce_config = fluence::internal::test::TomlAppServiceConfig::load(#config_path) + 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_file_path); + __fce__generated_fce_config.service_base_dir = Some(#tmp_file_path.to_string()); - let fce = fluence::internal::test::AppService::new_with_empty_facade(__fce__generated_fce_config, #service_id, std::collections::HashMap::new()) + let mut 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)); } } - -fn new_ident(name: &str) -> syn::Ident { - syn::Ident::new(name, proc_macro2::Span::call_site()) -} diff --git a/crates/fce-test-macro/src/lib.rs b/crates/fce-test-macro/src/lib.rs index 7e693b1..8b3b49d 100644 --- a/crates/fce-test-macro/src/lib.rs +++ b/crates/fce-test-macro/src/lib.rs @@ -15,16 +15,15 @@ */ #![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.2")] -/* #![deny( dead_code, nonstandard_style, unused_imports, unused_mut, + unused_variables, unused_unsafe, unreachable_patterns )] - */ #![warn(rust_2018_idioms)] #![recursion_limit = "1024"] @@ -56,7 +55,5 @@ use proc_macro::TokenStream; #[proc_macro_attribute] pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream { let func_input = syn::parse_macro_input!(input as syn::ItemFn); - let result = fce_test_impl(attrs.into(), func_input).unwrap_or_else(std::convert::identity); - - result.into() + fce_test_impl(attrs.into(), func_input) } diff --git a/crates/main/src/module_manifest.rs b/crates/main/src/module_manifest.rs index 95328eb..003864e 100644 --- a/crates/main/src/module_manifest.rs +++ b/crates/main/src/module_manifest.rs @@ -32,7 +32,7 @@ macro_rules! module_manifest { + __FCE_SDK_REPOSITORY_SIZE + __FCE_SDK_FIELD_PREFIX_SIZE * 4; - const fn append_data( + const fn __fce_sdk_append_data( mut manifest: [u8; __FCE_MANIFEST_SIZE], data: &'static str, offset: usize, @@ -63,10 +63,10 @@ macro_rules! module_manifest { let manifest: [u8; __FCE_MANIFEST_SIZE] = [0; __FCE_MANIFEST_SIZE]; let offset = 0; - let (manifest, offset) = append_data(manifest, $authors, offset); - let (manifest, offset) = append_data(manifest, $version, offset); - let (manifest, offset) = append_data(manifest, $description, offset); - let (manifest, _) = append_data(manifest, $repository, offset); + 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 } diff --git a/fluence-test/Cargo.toml b/fluence-test/Cargo.toml new file mode 100644 index 0000000..bf7fcef --- /dev/null +++ b/fluence-test/Cargo.toml @@ -0,0 +1,22 @@ +[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] # https://docs.rs/about +all-features = true + +[lib] +path = "src/lib.rs" + +[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"] } diff --git a/fluence-test/src/lib.rs b/fluence-test/src/lib.rs new file mode 100644 index 0000000..a3a4c6d --- /dev/null +++ b/fluence-test/src/lib.rs @@ -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. + */ + +#![doc(html_root_url = "https://docs.rs/fluence/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; +} diff --git a/fluence/Cargo.toml b/fluence/Cargo.toml new file mode 100644 index 0000000..e093b47 --- /dev/null +++ b/fluence/Cargo.toml @@ -0,0 +1,29 @@ +[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" + +[dependencies] +fluence-sdk-macro = { path = "../crates/fce-macro", version = "=0.5.0" } +fluence-sdk-main = { path = "../crates/main", version = "=0.5.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"] diff --git a/src/lib.rs b/fluence/src/lib.rs similarity index 94% rename from src/lib.rs rename to fluence/src/lib.rs index 87eab47..24d6e59 100644 --- a/src/lib.rs +++ b/fluence/src/lib.rs @@ -94,10 +94,4 @@ pub mod internal { pub use fluence_sdk_main::get_result_size; pub use fluence_sdk_main::set_result_ptr; pub use fluence_sdk_main::set_result_size; - - #[cfg(feature = "fce-test")] - pub mod test { - pub use fluence_app_service::AppService; - pub use fluence_app_service::AppServiceConfig; - } } From 04c2fb51d7e1903ffdac5bdae0911dfcdb621e8b Mon Sep 17 00:00:00 2001 From: vms Date: Sun, 28 Mar 2021 23:22:12 +0300 Subject: [PATCH 18/41] fix CI --- .circleci/config.yml | 10 +++++++--- crates/fce-macro/src/lib.rs | 4 ++-- crates/fce-test-macro/src/lib.rs | 4 ++-- crates/wit/src/parsed_type/fn_epilog.rs | 2 +- crates/wit/src/parsed_type/fn_prolog.rs | 2 +- crates/wit/src/parsed_type/foreign_mod_prolog.rs | 4 ++-- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 927365e..e6ccab9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,13 +15,17 @@ jobs: rustup toolchain install nightly-2021-02-27 rustup default nightly-2021-02-27 rustup override set nightly-2021-02-27 - rustup target add wasm32-unknown-unknown + 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 diff --git a/crates/fce-macro/src/lib.rs b/crates/fce-macro/src/lib.rs index 26442ed..658b1a5 100644 --- a/crates/fce-macro/src/lib.rs +++ b/crates/fce-macro/src/lib.rs @@ -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,7 +33,7 @@ //! This more complex example shows how a function could be imported from another Wasm module //! and how a struct could be passed: //! -//! ``` +//! ```ignore //! use fluence::MountedBinaryResult; //! //! #[fce] diff --git a/crates/fce-test-macro/src/lib.rs b/crates/fce-test-macro/src/lib.rs index 8b3b49d..5e0a373 100644 --- a/crates/fce-test-macro/src/lib.rs +++ b/crates/fce-test-macro/src/lib.rs @@ -34,7 +34,7 @@ use fce_test::fce_test_impl; use proc_macro::TokenStream; /// This macro allows user to write tests for services in the following form: -///```rust +///```ignore /// #[fce_test(config = "/path/to/Config.toml")] /// fn test() { /// let service_result = fce.call("greeting", "name"); @@ -43,7 +43,7 @@ use proc_macro::TokenStream; ///``` /// /// This function is desugrated in the following way: -///```rust +///```ignore /// #[test] /// fn test() { /// let fce = fluence_faas::FluenceFaaS::with_raw_config("/path/to/Config.toml") diff --git a/crates/wit/src/parsed_type/fn_epilog.rs b/crates/wit/src/parsed_type/fn_epilog.rs index a79a6fd..f332369 100644 --- a/crates/wit/src/parsed_type/fn_epilog.rs +++ b/crates/wit/src/parsed_type/fn_epilog.rs @@ -28,7 +28,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 { /// ... diff --git a/crates/wit/src/parsed_type/fn_prolog.rs b/crates/wit/src/parsed_type/fn_prolog.rs index c5b2c8b..3135a05 100644 --- a/crates/wit/src/parsed_type/fn_prolog.rs +++ b/crates/wit/src/parsed_type/fn_prolog.rs @@ -31,7 +31,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 diff --git a/crates/wit/src/parsed_type/foreign_mod_prolog.rs b/crates/wit/src/parsed_type/foreign_mod_prolog.rs index 6de6947..0ccc5ff 100644 --- a/crates/wit/src/parsed_type/foreign_mod_prolog.rs +++ b/crates/wit/src/parsed_type/foreign_mod_prolog.rs @@ -33,7 +33,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); @@ -44,7 +44,7 @@ pub(crate) struct ExternDescriptor { /// } /// ``` /// -/// ``` +/// ```ignore /// quote! { /// extern "C" { /// #[link_name = "foo_link_name"] From 3ffe392e146bc268b9bc0bb27805c65d3aa57785 Mon Sep 17 00:00:00 2001 From: vms Date: Wed, 31 Mar 2021 11:36:54 +0300 Subject: [PATCH 19/41] progress --- crates/fce-test-macro/Cargo.toml | 6 +- crates/fce-test-macro/src/errors.rs | 38 +++++ crates/fce-test-macro/src/fce_test.rs | 220 ++++++++++++++++++++++++++ crates/fce-test-macro/src/lib.rs | 5 +- fluence-test/Cargo.toml | 2 +- 5 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 crates/fce-test-macro/src/errors.rs diff --git a/crates/fce-test-macro/Cargo.toml b/crates/fce-test-macro/Cargo.toml index e0b9cd5..80a16b1 100644 --- a/crates/fce-test-macro/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -16,8 +16,12 @@ all-features = true proc-macro = 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" syn = { version = '1.0.64', features = ['full'] } +thiserror = "1.0.24" uuid = { version = "0.8.2", features = ["v4"] } -darling = "0.12.2" diff --git a/crates/fce-test-macro/src/errors.rs b/crates/fce-test-macro/src/errors.rs new file mode 100644 index 0000000..188dde9 --- /dev/null +++ b/crates/fce-test-macro/src/errors.rs @@ -0,0 +1,38 @@ +/* + * 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 syn::Error as SynError; +use thiserror::Error as ThisError; + +#[derive(Debug, ThisError)] +pub(crate) enum TestGeneratorError { + #[error("{0}")] + WITParserError(#[from] WITParserError), + + #[error("{0}")] + CorruptedITSection(#[from] CorruptedITSection), + + #[error("{0}")] + SynError(#[from] SynError), +} + +#[derive(Debug, ThisError)] +pub(crate) enum CorruptedITSection { + #[error("record with {0} is absent in embedded IT section")] + AbsentRecord(u64), +} diff --git a/crates/fce-test-macro/src/fce_test.rs b/crates/fce-test-macro/src/fce_test.rs index 2d63100..3ea6f93 100644 --- a/crates/fce-test-macro/src/fce_test.rs +++ b/crates/fce-test-macro/src/fce_test.rs @@ -15,7 +15,9 @@ */ use crate::attributes::FCETestAttributes; +use crate::TResult; +use fluence_app_service::TomlAppServiceConfig; use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; @@ -69,3 +71,221 @@ fn generate_fce_ctor(config_path: &str) -> TokenStream2 { .unwrap_or_else(|e| panic!("app service can't be created: {}", e)); } } + +use fce_wit_parser::module_raw_interface; +use fce_wit_parser::interface::FCEModuleInterface; +use fce_wit_parser::interface::FCERecordTypes; +use fce_wit_parser::interface::FCEFunctionSignature; +use fce_wit_parser::interface::it::IFunctionArg; +use fce_wit_parser::interface::it::IRecordFieldType; +use fce_wit_parser::interface::it::IType; + +use std::path::PathBuf; + +fn generate_module_definition( + module_name: &str, + module_interface: &FCEModuleInterface, +) -> TResult { + let module_name = new_ident(module_name)?; + let module_records = generate_records(&module_interface.record_types)?; + let module_functions = generate_module_methods( + module_interface.function_signatures.iter(), + &module_interface.record_types, + )?; + + let module_definition = quote! { + pub mod #module_name { + #module_records + + struct #module_name { + pub fce: fluence_test::internal::AppService, + } + + impl #module_name { + #(#module_functions)* + } + } + }; + + Ok(module_definition) +} + +fn generate_module_methods<'m, 'r>( + method_signatures: impl ExactSizeIterator, + records: &'r FCERecordTypes, +) -> TResult> { + let mut result = Vec::with_capacity(method_signatures.len()); + + for signature in method_signatures { + let func_name = new_ident(&signature.name)?; + let arguments = generate_arguments(signature.arguments.iter(), records)?; + let output_type = generate_output_type(&signature.outputs, records)?; + + let module_method = quote! { + pub fn #func_name(&self, #(#arguments),*) #output_type { + let result + } + }; + + result.push(module_method); + } + + Ok(result) +} + +fn generate_fce_call(method_signature: &FCEFunctionSignature) -> TokenStream2 { + let output_type = get_output_type(&method_signature.outputs); + + quote! { + #convert_arguments + + #set_result #function_call + + #convert_result_to_output_type + + #ret + } +} + +fn generate_arguments<'a, 'r>( + arguments: impl ExactSizeIterator, + records: &'r FCERecordTypes, +) -> TResult> { + let mut result = Vec::with_capacity(arguments.len()); + for argument in arguments { + let arg_name = new_ident(&argument.name)?; + let arg_type = itype_to_tokens(&argument.ty, records)?; + + let arg = quote! { #arg_name: #arg_type }; + result.push(arg); + } + + Ok(result) +} + +fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TResult { + let output_type = get_output_type(output_types); + match output_type { + None => Ok(TokenStream2::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]) -> Option<&IType> { + match output_types.len() { + 0 => None, + 1 => Some(&output_types[0]), + _ => unimplemented!("function with more than 1 arguments aren't supported now"), + } +} + +fn generate_records(records: &FCERecordTypes) -> TResult { + use std::ops::Deref; + + let mut result = TokenStream2::new(); + + for (_, record) in records.iter() { + let name = new_ident(&record.name)?; + let fields = prepare_field(record.fields.deref(), records)?; + + let record = quote! { + struct #name { + #fields + } + }; + result.extend(record); + } + + Ok(result) +} + +fn prepare_field(fields: &[IRecordFieldType], records: &FCERecordTypes) -> TResult { + let mut result = TokenStream2::new(); + + for field in fields { + let field_name = new_ident(&field.name)?; + let field_type = itype_to_tokens(&field.ty, records)?; + + let field = quote! { #field_name: #field_type }; + result.extend(field); + } + + Ok(result) +} + +fn new_ident(ident_str: &str) -> TResult { + syn::parse_str::(ident_str).map_err(Into::into) +} + +fn itype_to_tokens(itype: &IType, records: &FCERecordTypes) -> TResult { + 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!("anyref isn't supported and will be delete from IType"), + }; + + Ok(token_stream) +} + +fn collect_module_interfaces( + config: &TomlAppServiceConfig, +) -> TResult> { + let module_paths = collect_module_paths(config); + + module_paths + .into_iter() + .map(|(name, path)| module_raw_interface(path).map(|interface| (name, interface))) + .collect::, _>>() + .map_err(Into::into) +} + +fn collect_module_paths(config: &TomlAppServiceConfig) -> Vec<(&str, PathBuf)> { + let base_dir = config + .toml_faas_config + .modules_dir + .as_ref() + .map(|p| PathBuf::from(p)) + .unwrap_or_default(); + + 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); + let module_path = base_dir.join(module_file_name); + + (m.name.as_str(), module_path) + }) + .collect::>() +} diff --git a/crates/fce-test-macro/src/lib.rs b/crates/fce-test-macro/src/lib.rs index 5e0a373..58e7749 100644 --- a/crates/fce-test-macro/src/lib.rs +++ b/crates/fce-test-macro/src/lib.rs @@ -16,7 +16,7 @@ #![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.2")] #![deny( - dead_code, + // dead_code, nonstandard_style, unused_imports, unused_mut, @@ -28,11 +28,14 @@ #![recursion_limit = "1024"] mod attributes; +mod errors; mod fce_test; use fce_test::fce_test_impl; use proc_macro::TokenStream; +pub(crate) type TResult = std::result::Result; + /// This macro allows user to write tests for services in the following form: ///```ignore /// #[fce_test(config = "/path/to/Config.toml")] diff --git a/fluence-test/Cargo.toml b/fluence-test/Cargo.toml index bf7fcef..5562f61 100644 --- a/fluence-test/Cargo.toml +++ b/fluence-test/Cargo.toml @@ -19,4 +19,4 @@ path = "src/lib.rs" [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"] } +fluence-app-service = { version = "0.5.2", features = ["raw-module-api"] } From c571cc1628aceaef947610d75ac5ff4db14dfd54 Mon Sep 17 00:00:00 2001 From: vms Date: Wed, 31 Mar 2021 12:38:10 +0300 Subject: [PATCH 20/41] implement module glue code generation --- crates/fce-test-macro/src/fce_test.rs | 87 ++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 10 deletions(-) diff --git a/crates/fce-test-macro/src/fce_test.rs b/crates/fce-test-macro/src/fce_test.rs index 3ea6f93..0c08d94 100644 --- a/crates/fce-test-macro/src/fce_test.rs +++ b/crates/fce-test-macro/src/fce_test.rs @@ -86,22 +86,23 @@ fn generate_module_definition( module_name: &str, module_interface: &FCEModuleInterface, ) -> TResult { - let module_name = new_ident(module_name)?; + let module_name_ident = new_ident(module_name)?; let module_records = generate_records(&module_interface.record_types)?; let module_functions = generate_module_methods( + module_name, module_interface.function_signatures.iter(), &module_interface.record_types, )?; let module_definition = quote! { - pub mod #module_name { + pub mod #module_name_ident { #module_records - struct #module_name { + struct #module_name_ident { pub fce: fluence_test::internal::AppService, } - impl #module_name { + impl #module_name_ident { #(#module_functions)* } } @@ -111,6 +112,7 @@ fn generate_module_definition( } fn generate_module_methods<'m, 'r>( + module_name: &str, method_signatures: impl ExactSizeIterator, records: &'r FCERecordTypes, ) -> TResult> { @@ -120,10 +122,11 @@ fn generate_module_methods<'m, 'r>( let func_name = 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(&self, #(#arguments),*) #output_type { - let result + pub fn #func_name(&mut self, #(#arguments),*) #output_type { + #fce_call } }; @@ -133,10 +136,21 @@ fn generate_module_methods<'m, 'r>( Ok(result) } -fn generate_fce_call(method_signature: &FCEFunctionSignature) -> TokenStream2 { - let output_type = get_output_type(&method_signature.outputs); +fn generate_fce_call( + module_name: &str, + method_signature: &FCEFunctionSignature, + records: &FCERecordTypes, +) -> TResult { + let args = method_signature.arguments.iter().map(|a| a.name.as_str()); + let convert_arguments = generate_arguments_converter(args)?; - quote! { + 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! { #convert_arguments #set_result #function_call @@ -144,6 +158,58 @@ fn generate_fce_call(method_signature: &FCEFunctionSignature) -> TokenStream2 { #convert_result_to_output_type #ret + }; + + Ok(function_call) +} + +fn generate_arguments_converter<'a>( + args: impl ExactSizeIterator, +) -> TResult { + let mut arguments = Vec::with_capacity(args.len()); + + for arg in args { + let arg_ident = new_ident(arg)?; + arguments.push(arg_ident); + } + + let arguments_serializer = + quote! { let arguments = fluence_test::internal::json!([#(#arguments)*,]) }; + Ok(arguments_serializer) +} + +fn generate_function_call(module_name: &str, method_name: &str) -> TokenStream2 { + quote! { self.call_module(#module_name, #method_name, arguments, <_>::default()).expect("call to FCE failed"); } +} + +fn generate_set_result(output_type: &Option<&IType>) -> TokenStream2 { + match output_type { + Some(_) => quote! { let result = }, + None => TokenStream2::new(), + } +} + +fn generate_convert_to_output( + output_type: &Option<&IType>, + records: &FCERecordTypes, +) -> TResult { + let result_stream = match output_type { + Some(ty) => { + let ty = itype_to_tokens(ty, records)?; + quote! { + let result: #ty = serde_json::from_value(result).expect("default deserializer shouldn't fail"); + } + } + None => TokenStream2::new(), + }; + + Ok(result_stream) +} + +fn generate_ret(output_type: &Option<&IType>) -> TokenStream2 { + match output_type { + Some(_) => quote! { result }, + None => TokenStream2::new(), } } @@ -194,6 +260,7 @@ fn generate_records(records: &FCERecordTypes) -> TResult { let fields = prepare_field(record.fields.deref(), records)?; let record = quote! { + #[derive(Clone, fluence_test::internal::Serialize, fluence_test::internal::Deserialize)] struct #name { #fields } @@ -250,7 +317,7 @@ fn itype_to_tokens(itype: &IType, records: &FCERecordTypes) -> TResult quote! { i64 }, IType::F32 => quote! { f32 }, IType::F64 => quote! { f64 }, - IType::Anyref => unimplemented!("anyref isn't supported and will be delete from IType"), + IType::Anyref => unimplemented!("anyref isn't supported and will be deleted from IType"), }; Ok(token_stream) From ca75ef5eadea4fed639c1f842983beb00113c577 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 02:15:24 +0300 Subject: [PATCH 21/41] progress --- crates/fce-test-macro/Cargo.toml | 1 + crates/fce-test-macro/src/errors.rs | 17 ++++ crates/fce-test-macro/src/fce_test.rs | 110 ++++++++++++++++++++------ crates/fce-test-macro/src/lib.rs | 7 +- 4 files changed, 112 insertions(+), 23 deletions(-) diff --git a/crates/fce-test-macro/Cargo.toml b/crates/fce-test-macro/Cargo.toml index 80a16b1..f053007 100644 --- a/crates/fce-test-macro/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -22,6 +22,7 @@ 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" uuid = { version = "0.8.2", features = ["v4"] } diff --git a/crates/fce-test-macro/src/errors.rs b/crates/fce-test-macro/src/errors.rs index 188dde9..bf96758 100644 --- a/crates/fce-test-macro/src/errors.rs +++ b/crates/fce-test-macro/src/errors.rs @@ -15,7 +15,9 @@ */ 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; @@ -29,6 +31,12 @@ pub(crate) enum TestGeneratorError { #[error("{0}")] SynError(#[from] SynError), + + #[error("{0}")] + ConfigLoadError(#[from] AppServiceError), + + #[error("{0}")] + AttributesError(#[from] DarlingError), } #[derive(Debug, ThisError)] @@ -36,3 +44,12 @@ pub(crate) enum CorruptedITSection { #[error("record with {0} is absent in embedded IT section")] AbsentRecord(u64), } + +use proc_macro2::TokenStream; + +impl quote::ToTokens for TestGeneratorError { + fn to_tokens(&self, tokens: &mut TokenStream) { + let error_as_text = format!("Error was encountered inside fce_test: {}", self); + error_as_text.to_tokens(tokens); + } +} diff --git a/crates/fce-test-macro/src/fce_test.rs b/crates/fce-test-macro/src/fce_test.rs index 0c08d94..a6bb616 100644 --- a/crates/fce-test-macro/src/fce_test.rs +++ b/crates/fce-test-macro/src/fce_test.rs @@ -18,37 +18,48 @@ use crate::attributes::FCETestAttributes; use crate::TResult; use fluence_app_service::TomlAppServiceConfig; -use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; use quote::quote; -pub(super) fn fce_test_impl(attrs: TokenStream, func_input: syn::ItemFn) -> TokenStream { +pub(super) fn fce_test_impl(attrs: TokenStream2, func_input: syn::ItemFn) -> TResult { use darling::FromMeta; - let attrs = syn::parse_macro_input!(attrs as syn::AttributeArgs); - let attrs = match FCETestAttributes::from_list(&attrs) { - Ok(v) => v, - Err(e) => { - return TokenStream::from(e.write_errors()); - } - }; + // from https://github.com/dtolnay/syn/issues/788 + let parser = syn::punctuated::Punctuated::::parse_terminated; + let attrs = parser.parse2(attrs)?; + let attrs: Vec = attrs.into_iter().collect(); + let attrs = FCETestAttributes::from_list(&attrs)?; - generate_test_glue_code(func_input, &attrs.config_path).into() + generate_test_glue_code(func_input, &attrs.config_path) } -fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TokenStream2 { +fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TResult { + let fce_config = TomlAppServiceConfig::load(config_path)?; + let module_interfaces = collect_module_interfaces(&fce_config)?; + + let module_definitions = generate_module_definitions(module_interfaces.iter())?; let fce_ctor = generate_fce_ctor(config_path); + let module_iter = module_interfaces + .iter() + .map(|(module_name, _)| *module_name); + let module_ctors = generate_module_ctors(module_iter)?; let original_block = func.block; let signature = func.sig; - quote! { + let glue_code = quote! { #[test] #signature { + #module_definitions + #fce_ctor + #module_ctors + #original_block } - } + }; + + Ok(glue_code) } fn generate_fce_ctor(config_path: &str) -> TokenStream2 { @@ -67,11 +78,32 @@ fn generate_fce_ctor(config_path: &str) -> TokenStream2 { .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_file_path.to_string()); - let mut fce = fluence_test::internal::AppService::new_with_empty_facade(__fce__generated_fce_config, #service_id, std::collections::HashMap::new()) + 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, +) -> TResult { + let mut module_ctors = Vec::with_capacity(module_names.len()); + for name in module_names { + // TODO: optimize these two call because they are called twice for each module name + // and internally allocate memory in format + let module_name = generate_module_name(&name)?; + let struct_name = generate_struct_name(&name)?; + + let module_ctor = quote! { #module_name::#struct_name { fce: fce.clone() }}; + module_ctors.push(module_ctor); + } + + let module_ctors = quote! { #(#module_ctors)*, }; + + Ok(module_ctors) +} + use fce_wit_parser::module_raw_interface; use fce_wit_parser::interface::FCEModuleInterface; use fce_wit_parser::interface::FCERecordTypes; @@ -81,12 +113,29 @@ use fce_wit_parser::interface::it::IRecordFieldType; use fce_wit_parser::interface::it::IType; use std::path::PathBuf; +use syn::parse::Parser; + +fn generate_module_definitions<'i>( + module_interfaces: impl ExactSizeIterator, +) -> TResult { + let mut module_definitions = Vec::with_capacity(module_interfaces.len()); + + for interface in module_interfaces { + let module_definition = generate_module_definition(&interface.0, &interface.1)?; + module_definitions.push(module_definition); + } + + let module_definitions = quote! { #(#module_definitions)*,}; + + Ok(module_definitions) +} fn generate_module_definition( module_name: &str, module_interface: &FCEModuleInterface, ) -> TResult { - let module_name_ident = new_ident(module_name)?; + let module_name_ident = generate_module_name(module_name)?; + let struct_name_ident = generate_struct_name(module_name)?; let module_records = generate_records(&module_interface.record_types)?; let module_functions = generate_module_methods( module_name, @@ -98,11 +147,11 @@ fn generate_module_definition( pub mod #module_name_ident { #module_records - struct #module_name_ident { - pub fce: fluence_test::internal::AppService, + struct #struct_name_ident { + pub fce: std::rc::Rc>, } - impl #module_name_ident { + impl #struct_name_ident { #(#module_functions)* } } @@ -151,6 +200,8 @@ fn generate_fce_call( let ret = generate_ret(&output_type); let function_call = quote! { + use std::ops::DerefMut; + #convert_arguments #set_result #function_call @@ -179,7 +230,7 @@ fn generate_arguments_converter<'a>( } fn generate_function_call(module_name: &str, method_name: &str) -> TokenStream2 { - quote! { self.call_module(#module_name, #method_name, arguments, <_>::default()).expect("call to FCE failed"); } + 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>) -> TokenStream2 { @@ -197,7 +248,7 @@ fn generate_convert_to_output( Some(ty) => { let ty = itype_to_tokens(ty, records)?; quote! { - let result: #ty = serde_json::from_value(result).expect("default deserializer shouldn't fail"); + let result: #ty = serde_json::from_value(result).expect("the default deserializer shouldn't fail"); } } None => TokenStream2::new(), @@ -256,12 +307,12 @@ fn generate_records(records: &FCERecordTypes) -> TResult { let mut result = TokenStream2::new(); for (_, record) in records.iter() { - let name = new_ident(&record.name)?; + let record_name_ident = generate_record_name(&record.name)?; let fields = prepare_field(record.fields.deref(), records)?; let record = quote! { #[derive(Clone, fluence_test::internal::Serialize, fluence_test::internal::Deserialize)] - struct #name { + struct #record_name_ident { #fields } }; @@ -285,6 +336,21 @@ fn prepare_field(fields: &[IRecordFieldType], records: &FCERecordTypes) -> TResu Ok(result) } +fn generate_module_name(module_name: &str) -> TResult { + let extended_module_name = format!("__fce_generated_{}", module_name); + new_ident(&extended_module_name) +} + +fn generate_record_name(record_name: &str) -> TResult { + let extended_record_name = format!("FCEGeneratedRecord{}", record_name); + new_ident(&extended_record_name) +} + +fn generate_struct_name(struct_name: &str) -> TResult { + let extended_struct_name = format!("FCEGeneratedStruct{}", struct_name); + new_ident(&extended_struct_name) +} + fn new_ident(ident_str: &str) -> TResult { syn::parse_str::(ident_str).map_err(Into::into) } diff --git a/crates/fce-test-macro/src/lib.rs b/crates/fce-test-macro/src/lib.rs index 58e7749..b6c1652 100644 --- a/crates/fce-test-macro/src/lib.rs +++ b/crates/fce-test-macro/src/lib.rs @@ -33,6 +33,7 @@ mod fce_test; use fce_test::fce_test_impl; use proc_macro::TokenStream; +use proc_macro_error::proc_macro_error; pub(crate) type TResult = std::result::Result; @@ -55,8 +56,12 @@ pub(crate) type TResult = std::result::Result; /// assert_eq!(&service_result, "Hi, name!"); /// } ///``` +#[proc_macro_error] #[proc_macro_attribute] pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream { let func_input = syn::parse_macro_input!(input as syn::ItemFn); - fce_test_impl(attrs.into(), func_input) + match fce_test_impl(attrs.into(), func_input) { + Ok(stream) => stream.into(), + Err(e) => proc_macro_error::abort_call_site!(format!("{}", e)), + } } From 0574adb39a38ebc29a8f16c0387541002bc75c6d Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 03:49:44 +0300 Subject: [PATCH 22/41] it works --- Cargo.toml | 1 + crates/fce-test-macro-impl/Cargo.toml | 24 ++++ .../src/attributes.rs | 2 + .../src/errors.rs | 9 +- .../src/fce_test.rs | 111 +++++++++++------- crates/fce-test-macro-impl/src/lib.rs | 37 ++++++ crates/fce-test-macro/Cargo.toml | 6 +- crates/fce-test-macro/src/lib.rs | 21 ++-- fluence-test/Cargo.toml | 5 + fluence-test/src/lib.rs | 7 ++ 10 files changed, 162 insertions(+), 61 deletions(-) create mode 100644 crates/fce-test-macro-impl/Cargo.toml rename crates/{fce-test-macro => fce-test-macro-impl}/src/attributes.rs (91%) rename crates/{fce-test-macro => fce-test-macro-impl}/src/errors.rs (88%) rename crates/{fce-test-macro => fce-test-macro-impl}/src/fce_test.rs (78%) create mode 100644 crates/fce-test-macro-impl/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 42176e5..c36734b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "crates/fce-macro", "crates/fce-test-macro", + "crates/fce-test-macro-impl", "crates/main", "crates/wit", "fluence", diff --git a/crates/fce-test-macro-impl/Cargo.toml b/crates/fce-test-macro-impl/Cargo.toml new file mode 100644 index 0000000..f828a43 --- /dev/null +++ b/crates/fce-test-macro-impl/Cargo.toml @@ -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] # https://docs.rs/about +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" diff --git a/crates/fce-test-macro/src/attributes.rs b/crates/fce-test-macro-impl/src/attributes.rs similarity index 91% rename from crates/fce-test-macro/src/attributes.rs rename to crates/fce-test-macro-impl/src/attributes.rs index 1393ff8..8590400 100644 --- a/crates/fce-test-macro/src/attributes.rs +++ b/crates/fce-test-macro-impl/src/attributes.rs @@ -19,4 +19,6 @@ use darling::FromMeta; #[derive(Debug, Default, Clone, FromMeta)] pub(crate) struct FCETestAttributes { pub(crate) config_path: String, + #[darling(default)] + pub(crate) modules_dir: Option, } diff --git a/crates/fce-test-macro/src/errors.rs b/crates/fce-test-macro-impl/src/errors.rs similarity index 88% rename from crates/fce-test-macro/src/errors.rs rename to crates/fce-test-macro-impl/src/errors.rs index bf96758..d1f4b9f 100644 --- a/crates/fce-test-macro/src/errors.rs +++ b/crates/fce-test-macro-impl/src/errors.rs @@ -22,7 +22,7 @@ use syn::Error as SynError; use thiserror::Error as ThisError; #[derive(Debug, ThisError)] -pub(crate) enum TestGeneratorError { +pub enum TestGeneratorError { #[error("{0}")] WITParserError(#[from] WITParserError), @@ -37,10 +37,15 @@ pub(crate) enum TestGeneratorError { #[error("{0}")] AttributesError(#[from] DarlingError), + + #[error( + "neither attribute specified nor service config contains modules_dir, please specify it" + )] + ModulesDirUnspecified, } #[derive(Debug, ThisError)] -pub(crate) enum CorruptedITSection { +pub enum CorruptedITSection { #[error("record with {0} is absent in embedded IT section")] AbsentRecord(u64), } diff --git a/crates/fce-test-macro/src/fce_test.rs b/crates/fce-test-macro-impl/src/fce_test.rs similarity index 78% rename from crates/fce-test-macro/src/fce_test.rs rename to crates/fce-test-macro-impl/src/fce_test.rs index a6bb616..8319fb6 100644 --- a/crates/fce-test-macro/src/fce_test.rs +++ b/crates/fce-test-macro-impl/src/fce_test.rs @@ -15,13 +15,14 @@ */ use crate::attributes::FCETestAttributes; -use crate::TResult; +use crate::{TResult, TestGeneratorError}; use fluence_app_service::TomlAppServiceConfig; use proc_macro2::TokenStream as TokenStream2; use quote::quote; +use quote::ToTokens; -pub(super) fn fce_test_impl(attrs: TokenStream2, func_input: syn::ItemFn) -> TResult { +pub fn fce_test_impl(attrs: TokenStream2, input: TokenStream2) -> TResult { use darling::FromMeta; // from https://github.com/dtolnay/syn/issues/788 @@ -30,21 +31,31 @@ pub(super) fn fce_test_impl(attrs: TokenStream2, func_input: syn::ItemFn) -> TRe let attrs: Vec = attrs.into_iter().collect(); let attrs = FCETestAttributes::from_list(&attrs)?; - generate_test_glue_code(func_input, &attrs.config_path) + let func_item = syn::parse2::(input)?; + + generate_test_glue_code(func_item, attrs) } -fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TResult { - let fce_config = TomlAppServiceConfig::load(config_path)?; - let module_interfaces = collect_module_interfaces(&fce_config)?; +fn generate_test_glue_code( + func_item: syn::ItemFn, + attrs: FCETestAttributes, +) -> TResult { + let fce_config = TomlAppServiceConfig::load(&attrs.config_path)?; + let modules_dir = match determine_modules_dir(&fce_config, attrs.modules_dir) { + Some(modules_dir) => modules_dir, + None => return Err(TestGeneratorError::ModulesDirUnspecified), + }; + + let fce_ctor = generate_fce_ctor(&attrs.config_path, &modules_dir); + let module_interfaces = collect_module_interfaces(&fce_config, modules_dir)?; let module_definitions = generate_module_definitions(module_interfaces.iter())?; - let fce_ctor = generate_fce_ctor(config_path); let module_iter = module_interfaces .iter() .map(|(module_name, _)| *module_name); let module_ctors = generate_module_ctors(module_iter)?; - let original_block = func.block; - let signature = func.sig; + let original_block = func_item.block; + let signature = func_item.sig; let glue_code = quote! { #[test] @@ -62,23 +73,24 @@ fn generate_test_glue_code(func: syn::ItemFn, config_path: &str) -> TResult TokenStream2 { - let config_path = quote! { #config_path }; - - let tmp_file_path = std::env::temp_dir(); - let random_uuid = uuid::Uuid::new_v4().to_string(); - let service_id = quote! { #random_uuid }; - - let tmp_file_path = tmp_file_path.join(random_uuid); - let tmp_file_path = tmp_file_path.to_string_lossy().to_string(); - let tmp_file_path = quote! { #tmp_file_path }; +fn generate_fce_ctor(config_path: &str, modules_dir: &PathBuf) -> TokenStream2 { + let config_path = config_path.to_token_stream(); + let modules_dir = modules_dir.to_string_lossy().to_string(); quote! { - 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_file_path.to_string()); + let tmp_dir = std::env::temp_dir(); + let service_id = fluence_test::internal::Uuid::new_v4().to_string(); - let fce = fluence_test::internal::AppService::new_with_empty_facade(__fce__generated_fce_config, #service_id, std::collections::HashMap::new()) + 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)); @@ -94,12 +106,14 @@ fn generate_module_ctors<'n>( // and internally allocate memory in format let module_name = generate_module_name(&name)?; let struct_name = generate_struct_name(&name)?; + let name_for_user = new_ident(&name)?; - let module_ctor = quote! { #module_name::#struct_name { fce: fce.clone() }}; + let module_ctor = + quote! { let mut #name_for_user = #module_name::#struct_name { fce: fce.clone() }; }; module_ctors.push(module_ctor); } - let module_ctors = quote! { #(#module_ctors)*, }; + let module_ctors = quote! { #(#module_ctors),* }; Ok(module_ctors) } @@ -125,7 +139,7 @@ fn generate_module_definitions<'i>( module_definitions.push(module_definition); } - let module_definitions = quote! { #(#module_definitions)*,}; + let module_definitions = quote! { #(#module_definitions),*}; Ok(module_definitions) } @@ -147,7 +161,7 @@ fn generate_module_definition( pub mod #module_name_ident { #module_records - struct #struct_name_ident { + pub struct #struct_name_ident { pub fce: std::rc::Rc>, } @@ -225,12 +239,12 @@ fn generate_arguments_converter<'a>( } let arguments_serializer = - quote! { let arguments = fluence_test::internal::json!([#(#arguments)*,]) }; + quote! { let arguments = fluence_test::internal::json!([#(#arguments),*]); }; Ok(arguments_serializer) } fn generate_function_call(module_name: &str, method_name: &str) -> TokenStream2 { - quote! { self.fce.as_ref.borrow_mut().call_with_module_name(#module_name, #method_name, arguments, <_>::default()).expect("call to FCE failed"); } + 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>) -> TokenStream2 { @@ -312,7 +326,7 @@ fn generate_records(records: &FCERecordTypes) -> TResult { let record = quote! { #[derive(Clone, fluence_test::internal::Serialize, fluence_test::internal::Deserialize)] - struct #record_name_ident { + pub struct #record_name_ident { #fields } }; @@ -329,7 +343,7 @@ fn prepare_field(fields: &[IRecordFieldType], records: &FCERecordTypes) -> TResu let field_name = new_ident(&field.name)?; let field_type = itype_to_tokens(&field.ty, records)?; - let field = quote! { #field_name: #field_type }; + let field = quote! { #field_name: #field_type, }; result.extend(field); } @@ -342,7 +356,7 @@ fn generate_module_name(module_name: &str) -> TResult { } fn generate_record_name(record_name: &str) -> TResult { - let extended_record_name = format!("FCEGeneratedRecord{}", record_name); + let extended_record_name = format!("{}", record_name); new_ident(&extended_record_name) } @@ -391,8 +405,10 @@ fn itype_to_tokens(itype: &IType, records: &FCERecordTypes) -> TResult TResult> { - let module_paths = collect_module_paths(config); + let module_paths = collect_module_paths(config, modules_dir); + println!("module paths: {:?}", module_paths); module_paths .into_iter() @@ -401,14 +417,10 @@ fn collect_module_interfaces( .map_err(Into::into) } -fn collect_module_paths(config: &TomlAppServiceConfig) -> Vec<(&str, PathBuf)> { - let base_dir = config - .toml_faas_config - .modules_dir - .as_ref() - .map(|p| PathBuf::from(p)) - .unwrap_or_default(); - +fn collect_module_paths( + config: &TomlAppServiceConfig, + modules_dir: PathBuf, +) -> Vec<(&str, PathBuf)> { config .toml_faas_config .module @@ -416,9 +428,24 @@ fn collect_module_paths(config: &TomlAppServiceConfig) -> Vec<(&str, PathBuf)> { .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); - let module_path = base_dir.join(module_file_name); + // TODO: is it right to always have .wasm extension? + let module_path = modules_dir.join(module_file_name).with_extension("wasm"); (m.name.as_str(), module_path) }) .collect::>() } + +fn determine_modules_dir( + config: &TomlAppServiceConfig, + modules_dir: Option, +) -> Option { + 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)), + } +} diff --git a/crates/fce-test-macro-impl/src/lib.rs b/crates/fce-test-macro-impl/src/lib.rs new file mode 100644 index 0000000..9a16b6d --- /dev/null +++ b/crates/fce-test-macro-impl/src/lib.rs @@ -0,0 +1,37 @@ +/* + * 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"] + +mod attributes; +mod errors; +mod fce_test; + +pub use fce_test::fce_test_impl; +pub use errors::TestGeneratorError; + +pub(crate) type TResult = std::result::Result; diff --git a/crates/fce-test-macro/Cargo.toml b/crates/fce-test-macro/Cargo.toml index f053007..5830e1f 100644 --- a/crates/fce-test-macro/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -16,13 +16,9 @@ all-features = true proc-macro = true [dependencies] -fluence-app-service = { version = "0.5.2", features = ["raw-module-api"] } -fce-wit-parser = "0.4.0" +fluence-sdk-test-macro-impl = { path = "../fce-test-macro-impl", version = "=0.5.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" -uuid = { version = "0.8.2", features = ["v4"] } diff --git a/crates/fce-test-macro/src/lib.rs b/crates/fce-test-macro/src/lib.rs index b6c1652..4d3e172 100644 --- a/crates/fce-test-macro/src/lib.rs +++ b/crates/fce-test-macro/src/lib.rs @@ -14,9 +14,9 @@ * limitations under the License. */ -#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.2")] +#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.5.0")] #![deny( - // dead_code, + dead_code, nonstandard_style, unused_imports, unused_mut, @@ -27,15 +27,10 @@ #![warn(rust_2018_idioms)] #![recursion_limit = "1024"] -mod attributes; -mod errors; -mod fce_test; - -use fce_test::fce_test_impl; +use fluence_sdk_test_macro_impl::fce_test_impl; use proc_macro::TokenStream; use proc_macro_error::proc_macro_error; - -pub(crate) type TResult = std::result::Result; +use syn::spanned::Spanned; /// This macro allows user to write tests for services in the following form: ///```ignore @@ -59,9 +54,11 @@ pub(crate) type TResult = std::result::Result; #[proc_macro_error] #[proc_macro_attribute] pub fn fce_test(attrs: TokenStream, input: TokenStream) -> TokenStream { - let func_input = syn::parse_macro_input!(input as syn::ItemFn); - match fce_test_impl(attrs.into(), func_input) { + 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_call_site!(format!("{}", e)), + Err(e) => proc_macro_error::abort!(attrs_span, format!("{}", e)), } } diff --git a/fluence-test/Cargo.toml b/fluence-test/Cargo.toml index 5562f61..d92d49c 100644 --- a/fluence-test/Cargo.toml +++ b/fluence-test/Cargo.toml @@ -19,4 +19,9 @@ path = "src/lib.rs" [dependencies] fluence-sdk-test-macro = { path = "../crates/fce-test-macro", version = "=0.5.0" } +fluence-sdk-test-macro-impl = { path = "../crates/fce-test-macro-impl", 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"] } diff --git a/fluence-test/src/lib.rs b/fluence-test/src/lib.rs index a3a4c6d..dd21149 100644 --- a/fluence-test/src/lib.rs +++ b/fluence-test/src/lib.rs @@ -27,10 +27,17 @@ #![warn(rust_2018_idioms)] pub use fluence_sdk_test_macro::fce_test; +pub use fluence_sdk_test_macro_impl::fce_test_impl; /// 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; } From de2e61e60b3fcee0d44903a68af81da7165cd43e Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 04:26:36 +0300 Subject: [PATCH 23/41] houskeeping --- crates/fce-test-macro-impl/src/errors.rs | 4 +- crates/fce-test-macro-impl/src/fce_test.rs | 451 ------------------ .../src/fce_test/config_worker.rs | 82 ++++ .../src/fce_test/fce_test_impl.rs | 35 ++ .../src/fce_test/glue_code_generator.rs | 109 +++++ .../fce-test-macro-impl/src/fce_test/mod.rs | 23 + .../src/fce_test/module_generator.rs | 72 +++ .../module_generator/methods_generator.rs | 168 +++++++ .../module_generator/record_type_generator.rs | 62 +++ .../fce-test-macro-impl/src/fce_test/utils.rs | 77 +++ crates/fce-test-macro-impl/src/fce_test_.rs | 41 ++ crates/fce-test-macro-impl/src/lib.rs | 2 +- fluence-test/Cargo.toml | 1 - fluence-test/src/lib.rs | 1 - 14 files changed, 672 insertions(+), 456 deletions(-) delete mode 100644 crates/fce-test-macro-impl/src/fce_test.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/config_worker.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/fce_test_impl.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/mod.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/module_generator.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test/utils.rs create mode 100644 crates/fce-test-macro-impl/src/fce_test_.rs diff --git a/crates/fce-test-macro-impl/src/errors.rs b/crates/fce-test-macro-impl/src/errors.rs index d1f4b9f..12655a6 100644 --- a/crates/fce-test-macro-impl/src/errors.rs +++ b/crates/fce-test-macro-impl/src/errors.rs @@ -23,7 +23,7 @@ use thiserror::Error as ThisError; #[derive(Debug, ThisError)] pub enum TestGeneratorError { - #[error("{0}")] + #[error("Can't load Wasm modules into FCE: {0}")] WITParserError(#[from] WITParserError), #[error("{0}")] @@ -32,7 +32,7 @@ pub enum TestGeneratorError { #[error("{0}")] SynError(#[from] SynError), - #[error("{0}")] + #[error("Can't load Wasm modules from the provided config: {0}")] ConfigLoadError(#[from] AppServiceError), #[error("{0}")] diff --git a/crates/fce-test-macro-impl/src/fce_test.rs b/crates/fce-test-macro-impl/src/fce_test.rs deleted file mode 100644 index 8319fb6..0000000 --- a/crates/fce-test-macro-impl/src/fce_test.rs +++ /dev/null @@ -1,451 +0,0 @@ -/* - * 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 crate::attributes::FCETestAttributes; -use crate::{TResult, TestGeneratorError}; - -use fluence_app_service::TomlAppServiceConfig; -use proc_macro2::TokenStream as TokenStream2; -use quote::quote; -use quote::ToTokens; - -pub fn fce_test_impl(attrs: TokenStream2, input: TokenStream2) -> TResult { - use darling::FromMeta; - - // from https://github.com/dtolnay/syn/issues/788 - let parser = syn::punctuated::Punctuated::::parse_terminated; - let attrs = parser.parse2(attrs)?; - let attrs: Vec = attrs.into_iter().collect(); - let attrs = FCETestAttributes::from_list(&attrs)?; - - let func_item = syn::parse2::(input)?; - - generate_test_glue_code(func_item, attrs) -} - -fn generate_test_glue_code( - func_item: syn::ItemFn, - attrs: FCETestAttributes, -) -> TResult { - let fce_config = TomlAppServiceConfig::load(&attrs.config_path)?; - let modules_dir = match determine_modules_dir(&fce_config, attrs.modules_dir) { - Some(modules_dir) => modules_dir, - None => return Err(TestGeneratorError::ModulesDirUnspecified), - }; - - let fce_ctor = generate_fce_ctor(&attrs.config_path, &modules_dir); - let module_interfaces = collect_module_interfaces(&fce_config, modules_dir)?; - - let module_definitions = generate_module_definitions(module_interfaces.iter())?; - let module_iter = module_interfaces - .iter() - .map(|(module_name, _)| *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 { - #module_definitions - - #fce_ctor - - #module_ctors - - #original_block - } - }; - - Ok(glue_code) -} - -fn generate_fce_ctor(config_path: &str, modules_dir: &PathBuf) -> TokenStream2 { - 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, -) -> TResult { - let mut module_ctors = Vec::with_capacity(module_names.len()); - for name in module_names { - // TODO: optimize these two call because they are called twice for each module name - // and internally allocate memory in format - let module_name = generate_module_name(&name)?; - let struct_name = generate_struct_name(&name)?; - let name_for_user = new_ident(&name)?; - - let module_ctor = - quote! { let mut #name_for_user = #module_name::#struct_name { fce: fce.clone() }; }; - module_ctors.push(module_ctor); - } - - let module_ctors = quote! { #(#module_ctors),* }; - - Ok(module_ctors) -} - -use fce_wit_parser::module_raw_interface; -use fce_wit_parser::interface::FCEModuleInterface; -use fce_wit_parser::interface::FCERecordTypes; -use fce_wit_parser::interface::FCEFunctionSignature; -use fce_wit_parser::interface::it::IFunctionArg; -use fce_wit_parser::interface::it::IRecordFieldType; -use fce_wit_parser::interface::it::IType; - -use std::path::PathBuf; -use syn::parse::Parser; - -fn generate_module_definitions<'i>( - module_interfaces: impl ExactSizeIterator, -) -> TResult { - let mut module_definitions = Vec::with_capacity(module_interfaces.len()); - - for interface in module_interfaces { - let module_definition = generate_module_definition(&interface.0, &interface.1)?; - module_definitions.push(module_definition); - } - - let module_definitions = quote! { #(#module_definitions),*}; - - Ok(module_definitions) -} - -fn generate_module_definition( - module_name: &str, - module_interface: &FCEModuleInterface, -) -> TResult { - let module_name_ident = generate_module_name(module_name)?; - let struct_name_ident = generate_struct_name(module_name)?; - let module_records = generate_records(&module_interface.record_types)?; - let module_functions = 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 { - pub fce: std::rc::Rc>, - } - - impl #struct_name_ident { - #(#module_functions)* - } - } - }; - - Ok(module_definition) -} - -fn generate_module_methods<'m, 'r>( - module_name: &str, - method_signatures: impl ExactSizeIterator, - records: &'r FCERecordTypes, -) -> TResult> { - let mut result = Vec::with_capacity(method_signatures.len()); - - for signature in method_signatures { - let func_name = 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 - } - }; - - result.push(module_method); - } - - Ok(result) -} - -fn generate_fce_call( - module_name: &str, - method_signature: &FCEFunctionSignature, - records: &FCERecordTypes, -) -> TResult { - 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) -} - -fn generate_arguments_converter<'a>( - args: impl ExactSizeIterator, -) -> TResult { - let mut arguments = Vec::with_capacity(args.len()); - - for arg in args { - let arg_ident = new_ident(arg)?; - arguments.push(arg_ident); - } - - let arguments_serializer = - quote! { let arguments = fluence_test::internal::json!([#(#arguments),*]); }; - Ok(arguments_serializer) -} - -fn generate_function_call(module_name: &str, method_name: &str) -> TokenStream2 { - 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>) -> TokenStream2 { - match output_type { - Some(_) => quote! { let result = }, - None => TokenStream2::new(), - } -} - -fn generate_convert_to_output( - output_type: &Option<&IType>, - records: &FCERecordTypes, -) -> TResult { - let result_stream = match output_type { - Some(ty) => { - let ty = itype_to_tokens(ty, records)?; - quote! { - let result: #ty = serde_json::from_value(result).expect("the default deserializer shouldn't fail"); - } - } - None => TokenStream2::new(), - }; - - Ok(result_stream) -} - -fn generate_ret(output_type: &Option<&IType>) -> TokenStream2 { - match output_type { - Some(_) => quote! { result }, - None => TokenStream2::new(), - } -} - -fn generate_arguments<'a, 'r>( - arguments: impl ExactSizeIterator, - records: &'r FCERecordTypes, -) -> TResult> { - let mut result = Vec::with_capacity(arguments.len()); - for argument in arguments { - let arg_name = new_ident(&argument.name)?; - let arg_type = itype_to_tokens(&argument.ty, records)?; - - let arg = quote! { #arg_name: #arg_type }; - result.push(arg); - } - - Ok(result) -} - -fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TResult { - let output_type = get_output_type(output_types); - match output_type { - None => Ok(TokenStream2::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]) -> Option<&IType> { - match output_types.len() { - 0 => None, - 1 => Some(&output_types[0]), - _ => unimplemented!("function with more than 1 arguments aren't supported now"), - } -} - -fn generate_records(records: &FCERecordTypes) -> TResult { - use std::ops::Deref; - - let mut result = TokenStream2::new(); - - for (_, record) in records.iter() { - let record_name_ident = generate_record_name(&record.name)?; - let fields = prepare_field(record.fields.deref(), records)?; - - let record = quote! { - #[derive(Clone, fluence_test::internal::Serialize, fluence_test::internal::Deserialize)] - pub struct #record_name_ident { - #fields - } - }; - result.extend(record); - } - - Ok(result) -} - -fn prepare_field(fields: &[IRecordFieldType], records: &FCERecordTypes) -> TResult { - let mut result = TokenStream2::new(); - - for field in fields { - let field_name = new_ident(&field.name)?; - let field_type = itype_to_tokens(&field.ty, records)?; - - let field = quote! { #field_name: #field_type, }; - result.extend(field); - } - - Ok(result) -} - -fn generate_module_name(module_name: &str) -> TResult { - let extended_module_name = format!("__fce_generated_{}", module_name); - new_ident(&extended_module_name) -} - -fn generate_record_name(record_name: &str) -> TResult { - let extended_record_name = format!("{}", record_name); - new_ident(&extended_record_name) -} - -fn generate_struct_name(struct_name: &str) -> TResult { - let extended_struct_name = format!("FCEGeneratedStruct{}", struct_name); - new_ident(&extended_struct_name) -} - -fn new_ident(ident_str: &str) -> TResult { - syn::parse_str::(ident_str).map_err(Into::into) -} - -fn itype_to_tokens(itype: &IType, records: &FCERecordTypes) -> TResult { - 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!("anyref isn't supported and will be deleted from IType"), - }; - - Ok(token_stream) -} - -fn collect_module_interfaces( - config: &TomlAppServiceConfig, - modules_dir: PathBuf, -) -> TResult> { - let module_paths = collect_module_paths(config, modules_dir); - println!("module paths: {:?}", module_paths); - - module_paths - .into_iter() - .map(|(name, path)| module_raw_interface(path).map(|interface| (name, interface))) - .collect::, _>>() - .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 right to always have .wasm extension? - let module_path = modules_dir.join(module_file_name).with_extension("wasm"); - - (m.name.as_str(), module_path) - }) - .collect::>() -} - -fn determine_modules_dir( - config: &TomlAppServiceConfig, - modules_dir: Option, -) -> Option { - 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)), - } -} diff --git a/crates/fce-test-macro-impl/src/fce_test/config_worker.rs b/crates/fce-test-macro-impl/src/fce_test/config_worker.rs new file mode 100644 index 0000000..6d3ffbc --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/config_worker.rs @@ -0,0 +1,82 @@ +/* + * 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; + +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 } + } +} + +pub(super) fn collect_modules( + config: &TomlAppServiceConfig, + modules_dir: PathBuf, +) -> TResult>> { + 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::, _>>() + .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::>() +} + +pub(super) fn determine_modules_dir( + config: &TomlAppServiceConfig, + modules_dir: Option, +) -> Option { + 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)), + } +} diff --git a/crates/fce-test-macro-impl/src/fce_test/fce_test_impl.rs b/crates/fce-test-macro-impl/src/fce_test/fce_test_impl.rs new file mode 100644 index 0000000..b739529 --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/fce_test_impl.rs @@ -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 { + // from https://github.com/dtolnay/syn/issues/788 + let parser = syn::punctuated::Punctuated::::parse_terminated; + let attrs = parser.parse2(attrs)?; + let attrs: Vec = attrs.into_iter().collect(); + let attrs = FCETestAttributes::from_list(&attrs)?; + + let func_item = syn::parse2::(input)?; + + generate_test_glue_code(func_item, attrs) +} diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs new file mode 100644 index 0000000..b84cea4 --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -0,0 +1,109 @@ +/* + * 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 fluence_app_service::TomlAppServiceConfig; +use proc_macro2::TokenStream; +use quote::quote; +use quote::ToTokens; + +use std::path::PathBuf; + +pub(super) fn generate_test_glue_code( + func_item: syn::ItemFn, + attrs: FCETestAttributes, +) -> TResult { + let fce_config = TomlAppServiceConfig::load(&attrs.config_path)?; + let modules_dir = + match fce_test::config_worker::determine_modules_dir(&fce_config, attrs.modules_dir) { + Some(modules_dir) => modules_dir, + None => return Err(TestGeneratorError::ModulesDirUnspecified), + }; + + let fce_ctor = generate_fce_ctor(&attrs.config_path, &modules_dir); + let module_interfaces = fce_test::config_worker::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 { + #module_definitions + + #fce_ctor + + #module_ctors + + #original_block + } + }; + + Ok(glue_code) +} + +fn generate_fce_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, +) -> TResult { + let mut module_ctors = Vec::with_capacity(module_names.len()); + for name in module_names { + // 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 { fce: fce.clone() }; }; + module_ctors.push(module_ctor); + } + + let module_ctors = quote! { #(#module_ctors),* }; + + Ok(module_ctors) +} diff --git a/crates/fce-test-macro-impl/src/fce_test/mod.rs b/crates/fce-test-macro-impl/src/fce_test/mod.rs new file mode 100644 index 0000000..ed7a3a5 --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/mod.rs @@ -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_worker; +mod fce_test_impl; +mod glue_code_generator; +mod module_generator; +mod utils; + +pub use fce_test_impl::fce_test_impl; diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs new file mode 100644 index 0000000..492115a --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs @@ -0,0 +1,72 @@ +/* + * 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_worker::Module; +use crate::TResult; + +use fce_wit_parser::interface::FCEModuleInterface; + +use proc_macro2::TokenStream; +use quote::quote; + +pub(super) fn generate_module_definitions<'i>( + modules: impl ExactSizeIterator>, +) -> TResult { + let mut module_definitions = Vec::with_capacity(modules.len()); + + for module in modules { + let module_definition = generate_module_definition(&module.name, &module.interface)?; + module_definitions.push(module_definition); + } + + let module_definitions = quote! { #(#module_definitions),*}; + + Ok(module_definitions) +} + +fn generate_module_definition( + module_name: &str, + module_interface: &FCEModuleInterface, +) -> TResult { + let module_name_ident = utils::generate_module_name(module_name)?; + let struct_name_ident = utils::generate_struct_name(module_name)?; + 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 { + pub fce: std::rc::Rc>, + } + + impl #struct_name_ident { + #(#module_functions)* + } + } + }; + + Ok(module_definition) +} diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs new file mode 100644 index 0000000..9facb9d --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs @@ -0,0 +1,168 @@ +/* + * 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::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, + records: &'r FCERecordTypes, +) -> TResult> { + let mut result = Vec::with_capacity(method_signatures.len()); + + for signature in method_signatures { + 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 + } + }; + + result.push(module_method); + } + + Ok(result) +} + +fn generate_fce_call( + module_name: &str, + method_signature: &FCEFunctionSignature, + records: &FCERecordTypes, +) -> TResult { + 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) +} + +fn generate_arguments_converter<'a>( + args: impl ExactSizeIterator, +) -> TResult { + let mut arguments = Vec::with_capacity(args.len()); + + for arg in args { + let arg_ident = utils::new_ident(arg)?; + arguments.push(arg_ident); + } + + let arguments_serializer = + quote! { let arguments = fluence_test::internal::json!([#(#arguments),*]); }; + + Ok(arguments_serializer) +} + +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 { + 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, + records: &'r FCERecordTypes, +) -> TResult> { + let mut result = Vec::with_capacity(arguments.len()); + for argument in arguments { + 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 }; + result.push(arg); + } + + Ok(result) +} + +fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TResult { + 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]) -> Option<&IType> { + match output_types.len() { + 0 => None, + 1 => Some(&output_types[0]), + _ => unimplemented!("function with more than 1 arguments aren't supported now"), + } +} diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs new file mode 100644 index 0000000..9fb81dc --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs @@ -0,0 +1,62 @@ +/* + * 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 { + use std::ops::Deref; + + let mut result = TokenStream::new(); + + for (_, record) in records.iter() { + let record_name_ident = utils::generate_record_name(&record.name)?; + let fields = prepare_field(record.fields.deref().iter(), records)?; + + let record = quote! { + #[derive(Clone, fluence_test::internal::Serialize, fluence_test::internal::Deserialize)] + pub struct #record_name_ident { + #(#fields),* + } + }; + result.extend(record); + } + + Ok(result) +} + +fn prepare_field<'f>( + fields: impl ExactSizeIterator, + records: &FCERecordTypes, +) -> TResult> { + let mut result = Vec::with_capacity(fields.len()); + + for field in fields { + let field_name = utils::new_ident(&field.name)?; + let field_type = utils::itype_to_tokens(&field.ty, records)?; + + let field = quote! { #field_name: #field_type }; + result.push(field); + } + + Ok(result) +} diff --git a/crates/fce-test-macro-impl/src/fce_test/utils.rs b/crates/fce-test-macro-impl/src/fce_test/utils.rs new file mode 100644 index 0000000..a39f823 --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test/utils.rs @@ -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 { + let extended_module_name = format!("__fce_generated_{}", module_name); + new_ident(&extended_module_name) +} + +pub(super) fn generate_record_name(record_name: &str) -> TResult { + let extended_record_name = format!("{}", record_name); + new_ident(&extended_record_name) +} + +pub(super) fn generate_struct_name(struct_name: &str) -> TResult { + let extended_struct_name = format!("FCEGeneratedStruct{}", struct_name); + new_ident(&extended_struct_name) +} + +pub(super) fn new_ident(ident_str: &str) -> TResult { + syn::parse_str::(ident_str).map_err(Into::into) +} + +pub(super) fn itype_to_tokens(itype: &IType, records: &FCERecordTypes) -> TResult { + 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) +} diff --git a/crates/fce-test-macro-impl/src/fce_test_.rs b/crates/fce-test-macro-impl/src/fce_test_.rs new file mode 100644 index 0000000..fccd95c --- /dev/null +++ b/crates/fce-test-macro-impl/src/fce_test_.rs @@ -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. + */ + +use crate::attributes::FCETestAttributes; +use crate::TResult; +use crate::TestGeneratorError; + +use fluence_app_service::TomlAppServiceConfig; +use proc_macro2::TokenStream; +use quote::quote; +use quote::ToTokens; + + + +use fce_wit_parser::module_raw_interface; +use fce_wit_parser::interface::FCEModuleInterface; +use fce_wit_parser::interface::FCERecordTypes; +use fce_wit_parser::interface::FCEFunctionSignature; +use fce_wit_parser::interface::it::IFunctionArg; +use fce_wit_parser::interface::it::IRecordFieldType; +use fce_wit_parser::interface::it::IType; + +use std::path::PathBuf; +use syn::parse::Parser; + + + + diff --git a/crates/fce-test-macro-impl/src/lib.rs b/crates/fce-test-macro-impl/src/lib.rs index 9a16b6d..51f196e 100644 --- a/crates/fce-test-macro-impl/src/lib.rs +++ b/crates/fce-test-macro-impl/src/lib.rs @@ -16,7 +16,7 @@ #![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.5.0")] #![deny( - // dead_code, + dead_code, nonstandard_style, unused_imports, unused_mut, diff --git a/fluence-test/Cargo.toml b/fluence-test/Cargo.toml index d92d49c..d75e52e 100644 --- a/fluence-test/Cargo.toml +++ b/fluence-test/Cargo.toml @@ -19,7 +19,6 @@ path = "src/lib.rs" [dependencies] fluence-sdk-test-macro = { path = "../crates/fce-test-macro", version = "=0.5.0" } -fluence-sdk-test-macro-impl = { path = "../crates/fce-test-macro-impl", version = "=0.5.0" } fluence-app-service = { version = "0.5.2", features = ["raw-module-api"] } serde = { version = "1.0.118", features = ["derive"] } diff --git a/fluence-test/src/lib.rs b/fluence-test/src/lib.rs index dd21149..278355f 100644 --- a/fluence-test/src/lib.rs +++ b/fluence-test/src/lib.rs @@ -27,7 +27,6 @@ #![warn(rust_2018_idioms)] pub use fluence_sdk_test_macro::fce_test; -pub use fluence_sdk_test_macro_impl::fce_test_impl; /// These API functions are intended for internal usage in generated code. /// Normally, you shouldn't use them. From 6911e72ecc1dddbdb2fd84f813b4a0540993ed5f Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 05:08:41 +0300 Subject: [PATCH 24/41] more houskeeping --- .../src/fce_test/glue_code_generator.rs | 3 +- .../src/fce_test/module_generator.rs | 8 +++- crates/fce-test-macro-impl/src/fce_test_.rs | 41 ------------------- 3 files changed, 9 insertions(+), 43 deletions(-) delete mode 100644 crates/fce-test-macro-impl/src/fce_test_.rs diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index b84cea4..7c6cef9 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -99,7 +99,8 @@ fn generate_module_ctors<'n>( let name_for_user = fce_test::utils::new_ident(&name)?; let module_ctor = - quote! { let mut #name_for_user = #module_name::#struct_name { fce: fce.clone() }; }; + quote! { let mut #name_for_user = #module_name::#struct_name::new(fce.clone()); }; + module_ctors.push(module_ctor); } diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs index 492115a..74318f4 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs @@ -59,7 +59,13 @@ fn generate_module_definition( #module_records pub struct #struct_name_ident { - pub fce: std::rc::Rc>, + fce: std::rc::Rc>, + } + + impl #struct_name_ident { + pub fn new(fce: std::rc::Rc>) -> Self { + Self { fce } + } } impl #struct_name_ident { diff --git a/crates/fce-test-macro-impl/src/fce_test_.rs b/crates/fce-test-macro-impl/src/fce_test_.rs deleted file mode 100644 index fccd95c..0000000 --- a/crates/fce-test-macro-impl/src/fce_test_.rs +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 crate::attributes::FCETestAttributes; -use crate::TResult; -use crate::TestGeneratorError; - -use fluence_app_service::TomlAppServiceConfig; -use proc_macro2::TokenStream; -use quote::quote; -use quote::ToTokens; - - - -use fce_wit_parser::module_raw_interface; -use fce_wit_parser::interface::FCEModuleInterface; -use fce_wit_parser::interface::FCERecordTypes; -use fce_wit_parser::interface::FCEFunctionSignature; -use fce_wit_parser::interface::it::IFunctionArg; -use fce_wit_parser::interface::it::IRecordFieldType; -use fce_wit_parser::interface::it::IType; - -use std::path::PathBuf; -use syn::parse::Parser; - - - - From e03476316c0c8b0ed2985a554d3a2f0edebaaa22 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 05:10:49 +0300 Subject: [PATCH 25/41] remove ToTokens impl --- crates/fce-test-macro-impl/src/errors.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/crates/fce-test-macro-impl/src/errors.rs b/crates/fce-test-macro-impl/src/errors.rs index 12655a6..af368c1 100644 --- a/crates/fce-test-macro-impl/src/errors.rs +++ b/crates/fce-test-macro-impl/src/errors.rs @@ -39,7 +39,7 @@ pub enum TestGeneratorError { AttributesError(#[from] DarlingError), #[error( - "neither attribute specified nor service config contains modules_dir, please specify it" + "neither modules_dir attribute specified nor service config contains modules_dir, please specify one of them" )] ModulesDirUnspecified, } @@ -49,12 +49,3 @@ pub enum CorruptedITSection { #[error("record with {0} is absent in embedded IT section")] AbsentRecord(u64), } - -use proc_macro2::TokenStream; - -impl quote::ToTokens for TestGeneratorError { - fn to_tokens(&self, tokens: &mut TokenStream) { - let error_as_text = format!("Error was encountered inside fce_test: {}", self); - error_as_text.to_tokens(tokens); - } -} From 305ca68c102b137063af297d042bdd3b19592111 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 05:29:54 +0300 Subject: [PATCH 26/41] add comments --- crates/fce-test-macro-impl/src/attributes.rs | 4 ++ .../src/fce_test/glue_code_generator.rs | 59 +++++++++++++++++++ .../src/fce_test/module_generator.rs | 29 +++++++++ crates/fce-test-macro/src/lib.rs | 15 +---- 4 files changed, 94 insertions(+), 13 deletions(-) diff --git a/crates/fce-test-macro-impl/src/attributes.rs b/crates/fce-test-macro-impl/src/attributes.rs index 8590400..bd5e482 100644 --- a/crates/fce-test-macro-impl/src/attributes.rs +++ b/crates/fce-test-macro-impl/src/attributes.rs @@ -16,9 +16,13 @@ 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, } diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index 7c6cef9..81a0c09 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -26,6 +26,65 @@ use quote::ToTokens; use std::path::PathBuf; +/// Generates glue code for tests. +/// F.e. for the greeting service the following glue code would be generated: +///```ignore +/// // (0) +/// pub mod __fce_generated_greeting { +/// struct FCEGeneratedStructgreeting { +/// fce: std::rc::Rc>, +/// } +/// +/// impl FCEGeneratedStructgreeting { +/// pub fn new(fce: std::rc::Rc>) -> 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 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: {}", +/// "/Users/mike/dev/work/fluence/wasm/fce/examples/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) +///``` +/// +/// Here [(0), (1)] - module_definitions +/// [(1), (2)] - fce ctor +/// [(2), (3)] - ctors of all modules of the tested service +/// [(3), (4)] - original test function pub(super) fn generate_test_glue_code( func_item: syn::ItemFn, attrs: FCETestAttributes, diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs index 74318f4..40b2f18 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs @@ -26,6 +26,35 @@ use fce_wit_parser::interface::FCEModuleInterface; 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>, +/// } +/// +/// impl FCEGeneratedStructgreeting { +/// pub fn new(fce: std::rc::Rc>) -> 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>, ) -> TResult { diff --git a/crates/fce-test-macro/src/lib.rs b/crates/fce-test-macro/src/lib.rs index 4d3e172..0e6c594 100644 --- a/crates/fce-test-macro/src/lib.rs +++ b/crates/fce-test-macro/src/lib.rs @@ -34,20 +34,9 @@ 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")] +/// #[fce_test(config = "/path/to/Config.toml", modules_dir = "path/to/service/modules")] /// fn test() { -/// let service_result = fce.call("greeting", "name"); -/// assert_eq!(&service_result, "Hi, name!"); -/// } -///``` -/// -/// This function is desugrated in the following way: -///```ignore -/// #[test] -/// fn test() { -/// let fce = fluence_faas::FluenceFaaS::with_raw_config("/path/to/Config.toml") -/// .unwrap_or_else(|e| panic!("test instance can't be instantiated: {}", e)); -/// let service_result = fce.call("greeting", "name"); +/// let service_result = greeting.greeting("John".to_string()); /// assert_eq!(&service_result, "Hi, name!"); /// } ///``` From 6fca2485ebec418d61325f5042cef9653d919a90 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 05:34:16 +0300 Subject: [PATCH 27/41] improcve comment --- .../src/fce_test/glue_code_generator.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index 81a0c09..3dfef57 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -56,6 +56,13 @@ use std::path::PathBuf; /// } ///} /// // (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!( From 8e2318dc779ef45d00fd13765327498cd84ea13b Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 12:11:31 +0300 Subject: [PATCH 28/41] housekeeping --- .../{config_worker.rs => config_utils.rs} | 8 +++- .../src/fce_test/glue_code_generator.rs | 24 +++++----- .../fce-test-macro-impl/src/fce_test/mod.rs | 2 +- .../src/fce_test/module_generator.rs | 30 +++++-------- .../module_generator/methods_generator.rs | 44 ++++++++----------- .../module_generator/record_type_generator.rs | 31 ++++++------- 6 files changed, 65 insertions(+), 74 deletions(-) rename crates/fce-test-macro-impl/src/fce_test/{config_worker.rs => config_utils.rs} (85%) diff --git a/crates/fce-test-macro-impl/src/fce_test/config_worker.rs b/crates/fce-test-macro-impl/src/fce_test/config_utils.rs similarity index 85% rename from crates/fce-test-macro-impl/src/fce_test/config_worker.rs rename to crates/fce-test-macro-impl/src/fce_test/config_utils.rs index 6d3ffbc..a8d2fea 100644 --- a/crates/fce-test-macro-impl/src/fce_test/config_worker.rs +++ b/crates/fce-test-macro-impl/src/fce_test/config_utils.rs @@ -22,6 +22,7 @@ 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, @@ -33,6 +34,7 @@ impl<'m> Module<'m> { } } +/// Returns all modules the provided config consist of. pub(super) fn collect_modules( config: &TomlAppServiceConfig, modules_dir: PathBuf, @@ -67,7 +69,11 @@ fn collect_module_paths( .collect::>() } -pub(super) fn determine_modules_dir( +/// Tries to determine a dir with compiled Wasm modules according to the following +/// - 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, ) -> Option { diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index 3dfef57..3ec6b52 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -18,6 +18,7 @@ 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; @@ -89,7 +90,7 @@ use std::path::PathBuf; ///``` /// /// Here [(0), (1)] - module_definitions -/// [(1), (2)] - fce ctor +/// [(1), (2)] - AppService ctor /// [(2), (3)] - ctors of all modules of the tested service /// [(3), (4)] - original test function pub(super) fn generate_test_glue_code( @@ -97,28 +98,29 @@ pub(super) fn generate_test_glue_code( attrs: FCETestAttributes, ) -> TResult { let fce_config = TomlAppServiceConfig::load(&attrs.config_path)?; - let modules_dir = - match fce_test::config_worker::determine_modules_dir(&fce_config, attrs.modules_dir) { - Some(modules_dir) => modules_dir, - None => return Err(TestGeneratorError::ModulesDirUnspecified), - }; + 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 fce_ctor = generate_fce_ctor(&attrs.config_path, &modules_dir); - let module_interfaces = fce_test::config_worker::collect_modules(&fce_config, modules_dir)?; + 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 { - #module_definitions + #(#module_definitions)* - #fce_ctor + #app_service_ctor #module_ctors @@ -129,7 +131,7 @@ pub(super) fn generate_test_glue_code( Ok(glue_code) } -fn generate_fce_ctor(config_path: &str, modules_dir: &PathBuf) -> TokenStream { +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(); diff --git a/crates/fce-test-macro-impl/src/fce_test/mod.rs b/crates/fce-test-macro-impl/src/fce_test/mod.rs index ed7a3a5..492c7af 100644 --- a/crates/fce-test-macro-impl/src/fce_test/mod.rs +++ b/crates/fce-test-macro-impl/src/fce_test/mod.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -mod config_worker; +mod config_utils; mod fce_test_impl; mod glue_code_generator; mod module_generator; diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs index 40b2f18..45aeee3 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs @@ -18,11 +18,9 @@ mod methods_generator; mod record_type_generator; use crate::fce_test::utils; -use crate::fce_test::config_worker::Module; +use crate::fce_test::config_utils::Module; use crate::TResult; -use fce_wit_parser::interface::FCEModuleInterface; - use proc_macro2::TokenStream; use quote::quote; @@ -57,25 +55,19 @@ use quote::quote; ///``` pub(super) fn generate_module_definitions<'i>( modules: impl ExactSizeIterator>, -) -> TResult { - let mut module_definitions = Vec::with_capacity(modules.len()); - - for module in modules { - let module_definition = generate_module_definition(&module.name, &module.interface)?; - module_definitions.push(module_definition); - } - - let module_definitions = quote! { #(#module_definitions),*}; - - Ok(module_definitions) +) -> TResult> { + modules + .into_iter() + .map(generate_module_definition) + .collect::, _>>() } -fn generate_module_definition( - module_name: &str, - module_interface: &FCEModuleInterface, -) -> TResult { +fn generate_module_definition(module: &Module<'_>) -> TResult { + 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, @@ -85,7 +77,7 @@ fn generate_module_definition( let module_definition = quote! { pub mod #module_name_ident { - #module_records + #(#module_records)* pub struct #struct_name_ident { fce: std::rc::Rc>, diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs index 9facb9d..58a4288 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs @@ -30,24 +30,22 @@ pub(super) fn generate_module_methods<'m, 'r>( method_signatures: impl ExactSizeIterator, records: &'r FCERecordTypes, ) -> TResult> { - let mut result = Vec::with_capacity(method_signatures.len()); + 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)?; - for signature in method_signatures { - 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 + } + }; - let module_method = quote! { - pub fn #func_name(&mut self, #(#arguments),*) #output_type { - #fce_call - } - }; - - result.push(module_method); - } - - Ok(result) + Ok(module_method) + }) + .collect::, _>>() } fn generate_fce_call( @@ -79,20 +77,16 @@ fn generate_fce_call( Ok(function_call) } +/// Generates type convertor to json because of AppService receives them in json. fn generate_arguments_converter<'a>( args: impl ExactSizeIterator, ) -> TResult { - let mut arguments = Vec::with_capacity(args.len()); + let arg_idents: Vec = args.map(utils::new_ident).collect::>()?; - for arg in args { - let arg_ident = utils::new_ident(arg)?; - arguments.push(arg_ident); - } + let args_converter = + quote! { let arguments = fluence_test::internal::json!([#(#arg_idents),*]); }; - let arguments_serializer = - quote! { let arguments = fluence_test::internal::json!([#(#arguments),*]); }; - - Ok(arguments_serializer) + Ok(args_converter) } fn generate_function_call(module_name: &str, method_name: &str) -> TokenStream { diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs index 9fb81dc..32bd833 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs @@ -23,40 +23,37 @@ use fce_wit_parser::interface::FCERecordTypes; use proc_macro2::TokenStream; use quote::quote; -pub(super) fn generate_records(records: &FCERecordTypes) -> TResult { +pub(super) fn generate_records(records: &FCERecordTypes) -> TResult> { use std::ops::Deref; - let mut result = TokenStream::new(); - - for (_, record) in records.iter() { + 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 record = quote! { + let generated_record = quote! { #[derive(Clone, fluence_test::internal::Serialize, fluence_test::internal::Deserialize)] pub struct #record_name_ident { #(#fields),* } }; - result.extend(record); - } - Ok(result) + Ok(generated_record) + } + ).collect::, _>>() } fn prepare_field<'f>( fields: impl ExactSizeIterator, records: &FCERecordTypes, ) -> TResult> { - let mut result = Vec::with_capacity(fields.len()); + fields + .map(|field| -> TResult { + let field_name = utils::new_ident(&field.name)?; + let field_type = utils::itype_to_tokens(&field.ty, records)?; - for field in fields { - 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 }; - let field = quote! { #field_name: #field_type }; - result.push(field); - } - - Ok(result) + Ok(generated_field) + }) + .collect::, _>>() } From b34a9fc90b9e4acd1c17a9813fcb60da8687d618 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 12:20:52 +0300 Subject: [PATCH 29/41] code cleaning --- .../src/fce_test/glue_code_generator.rs | 31 +++++++++---------- .../module_generator/methods_generator.rs | 21 ++++++------- .../module_generator/record_type_generator.rs | 8 ++--- crates/fce-test-macro-impl/src/lib.rs | 1 - fluence-test/src/lib.rs | 2 +- 5 files changed, 29 insertions(+), 34 deletions(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index 3ec6b52..0f32669 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -122,7 +122,7 @@ pub(super) fn generate_test_glue_code( #app_service_ctor - #module_ctors + #(#module_ctors)* #original_block } @@ -157,22 +157,19 @@ fn generate_app_service_ctor(config_path: &str, modules_dir: &PathBuf) -> TokenS fn generate_module_ctors<'n>( module_names: impl ExactSizeIterator, -) -> TResult { - let mut module_ctors = Vec::with_capacity(module_names.len()); - for name in module_names { - // 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)?; +) -> TResult> { + 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()); }; + let module_ctor = + quote! { let mut #name_for_user = #module_name::#struct_name::new(fce.clone()); }; - module_ctors.push(module_ctor); - } - - let module_ctors = quote! { #(#module_ctors),* }; - - Ok(module_ctors) + Ok(module_ctor) + }) + .collect::>() } diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs index 58a4288..7d6ac63 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs @@ -31,7 +31,7 @@ pub(super) fn generate_module_methods<'m, 'r>( records: &'r FCERecordTypes, ) -> TResult> { method_signatures - .map(|signature| -> TResult { + .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)?; @@ -45,7 +45,7 @@ pub(super) fn generate_module_methods<'m, 'r>( Ok(module_method) }) - .collect::, _>>() + .collect::>>() } fn generate_fce_call( @@ -128,16 +128,15 @@ fn generate_arguments<'a, 'r>( arguments: impl ExactSizeIterator, records: &'r FCERecordTypes, ) -> TResult> { - let mut result = Vec::with_capacity(arguments.len()); - for argument in arguments { - let arg_name = utils::new_ident(&argument.name)?; - let arg_type = utils::itype_to_tokens(&argument.ty, records)?; + 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 }; - result.push(arg); - } - - Ok(result) + let arg = quote! { #arg_name: #arg_type }; + Ok(arg) + }) + .collect::>>() } fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TResult { diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs index 32bd833..2e20dfd 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator/record_type_generator.rs @@ -26,7 +26,7 @@ use quote::quote; pub(super) fn generate_records(records: &FCERecordTypes) -> TResult> { use std::ops::Deref; - records.iter().map(|(_, record)| -> TResult { + records.iter().map(|(_, record)| -> TResult<_> { let record_name_ident = utils::generate_record_name(&record.name)?; let fields = prepare_field(record.fields.deref().iter(), records)?; @@ -39,7 +39,7 @@ pub(super) fn generate_records(records: &FCERecordTypes) -> TResult, _>>() + ).collect::>>() } fn prepare_field<'f>( @@ -47,7 +47,7 @@ fn prepare_field<'f>( records: &FCERecordTypes, ) -> TResult> { fields - .map(|field| -> TResult { + .map(|field| -> TResult<_> { let field_name = utils::new_ident(&field.name)?; let field_type = utils::itype_to_tokens(&field.ty, records)?; @@ -55,5 +55,5 @@ fn prepare_field<'f>( Ok(generated_field) }) - .collect::, _>>() + .collect::>>() } diff --git a/crates/fce-test-macro-impl/src/lib.rs b/crates/fce-test-macro-impl/src/lib.rs index 51f196e..432d957 100644 --- a/crates/fce-test-macro-impl/src/lib.rs +++ b/crates/fce-test-macro-impl/src/lib.rs @@ -14,7 +14,6 @@ * limitations under the License. */ -#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.5.0")] #![deny( dead_code, nonstandard_style, diff --git a/fluence-test/src/lib.rs b/fluence-test/src/lib.rs index 278355f..c60b3fc 100644 --- a/fluence-test/src/lib.rs +++ b/fluence-test/src/lib.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -#![doc(html_root_url = "https://docs.rs/fluence/0.5.0")] +#![doc(html_root_url = "https://docs.rs/fluence-test/0.5.0")] #![deny( dead_code, nonstandard_style, From c2a7cc874abf5186db3dae54586239d0c6c319f2 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 12:48:32 +0300 Subject: [PATCH 30/41] fix a typo --- crates/fce-test-macro-impl/src/fce_test/config_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/config_utils.rs b/crates/fce-test-macro-impl/src/fce_test/config_utils.rs index a8d2fea..1c91cc6 100644 --- a/crates/fce-test-macro-impl/src/fce_test/config_utils.rs +++ b/crates/fce-test-macro-impl/src/fce_test/config_utils.rs @@ -34,7 +34,7 @@ impl<'m> Module<'m> { } } -/// Returns all modules the provided config consist of. +/// Returns all modules the provided config consists of. pub(super) fn collect_modules( config: &TomlAppServiceConfig, modules_dir: PathBuf, From b57c3687a232eb286f0f5834593bf103be62b469 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 12:49:34 +0300 Subject: [PATCH 31/41] one more fix --- crates/fce-test-macro-impl/src/fce_test/config_utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/config_utils.rs b/crates/fce-test-macro-impl/src/fce_test/config_utils.rs index 1c91cc6..77450da 100644 --- a/crates/fce-test-macro-impl/src/fce_test/config_utils.rs +++ b/crates/fce-test-macro-impl/src/fce_test/config_utils.rs @@ -69,7 +69,7 @@ fn collect_module_paths( .collect::>() } -/// Tries to determine a dir with compiled Wasm modules according to the following +/// 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. From 773dedcd792ad35133d67b82dba0c149a33a0ad3 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 12:56:23 +0300 Subject: [PATCH 32/41] improve result converting --- crates/fce-test-macro-impl/src/fce_test/module_generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs index 45aeee3..c29ea00 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator.rs @@ -59,7 +59,7 @@ pub(super) fn generate_module_definitions<'i>( modules .into_iter() .map(generate_module_definition) - .collect::, _>>() + .collect::>>() } fn generate_module_definition(module: &Module<'_>) -> TResult { From bff0b7b5d3424be5383eba1a1937b634fd5f79d0 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 13:55:16 +0300 Subject: [PATCH 33/41] add initial tests version --- tests/test_files/arrays_passing.rs | 175 +++++++++++++++++++++ tests/test_files/basic_argument_passing.rs | 153 ++++++++++++++++++ tests/test_files/records.rs | 0 3 files changed, 328 insertions(+) create mode 100644 tests/test_files/arrays_passing.rs create mode 100644 tests/test_files/basic_argument_passing.rs create mode 100644 tests/test_files/records.rs diff --git a/tests/test_files/arrays_passing.rs b/tests/test_files/arrays_passing.rs new file mode 100644 index 0000000..b60b122 --- /dev/null +++ b/tests/test_files/arrays_passing.rs @@ -0,0 +1,175 @@ +use fluence::fce; + +pub fn main() {} + +#[fce] +pub fn byte_type(mut arg: Vec) -> Vec { + arg.push(0); + + let mut arg = unsafe { effector::byte_type(arg) }; + + arg.push(2); + arg +} + +#[fce] +pub fn inner_arrays_1(mut arg: Vec>>>) -> Vec>>> { + arg.push(vec![vec![vec![0]]]); + + let mut arg = unsafe { effector::inner_arrays_1(arg) }; + + arg.push(vec![vec![vec![2]]]); + arg +} + +#[fce] +#[derive(Default)] +pub struct TestRecord { + pub field_0: i32, + pub field_1: Vec>, +} + +#[fce] +pub fn inner_arrays_2(mut arg: Vec>>>) -> Vec>>> { + arg.push(vec![vec![vec![ + TestRecord { + field_0: 0, + field_1: vec![vec![1]], + }, + TestRecord::default(), + ]]]); + + let mut arg = unsafe { effector::inner_arrays_2(arg) }; + + arg.push(vec![vec![vec![ + TestRecord { + field_0: 1, + field_1: vec![vec![2]], + }, + TestRecord::default(), + ]]]); + + arg +} + +#[fce] +pub fn string_type(mut arg: Vec) -> Vec { + arg.push(String::from("fce")); + + let mut arg = unsafe { effector::string_type(arg) }; + + arg.push(String::from("test")); + arg +} + +/* +#[fce] +pub fn bool_type(arg: Vec) -> Vec { + let mut arg = unsafe { effector::bool_type(arg) }; + + arg.push(false); + arg +} + */ + +#[fce] +pub fn f32_type(mut arg: Vec) -> Vec { + arg.push(0.0); + + let mut arg = unsafe { effector::f32_type(arg) }; + + arg.push(1.0); + arg +} + +#[fce] +pub fn f64_type(mut arg: Vec) -> Vec { + arg.push(0.0); + + let mut arg = unsafe { effector::f64_type(arg) }; + + arg.push(1.0); + arg +} + +#[fce] +pub fn u32_type(mut arg: Vec) -> Vec { + arg.push(0); + + let mut arg = unsafe { effector::u32_type(arg) }; + + arg.push(2); + arg +} + +#[fce] +pub fn u64_type(mut arg: Vec) -> Vec { + arg.push(0); + + let mut arg = unsafe { effector::u64_type(arg) }; + + arg.push(2); + arg +} + +#[fce] +pub fn i32_type(mut arg: Vec) -> Vec { + arg.push(0); + + let mut arg = unsafe { effector::i32_type(arg) }; + + arg.push(2); + arg +} + +#[fce] +pub fn i64_type(mut arg: Vec) -> Vec { + arg.push(0); + + let mut arg = unsafe { effector::i64_type(arg) }; + + arg.push(1); + arg +} + +#[fce] +pub fn empty_type() -> Vec { + unsafe { effector::empty_type() } +} + +mod effector { + use fluence::fce; + use super::TestRecord; + + #[fce] + #[link(wasm_import_module = "arrays_passing_effector")] + extern "C" { + pub fn inner_arrays_1(arg: Vec>>>) -> Vec>>>; + + pub fn inner_arrays_2( + arg: Vec>>>, + ) -> Vec>>>; + + pub fn string_type(arg: Vec) -> Vec; + + pub fn byte_type(arg: Vec) -> Vec; + + /* + pub fn bool_type(arg: Vec) -> Vec; + */ + + pub fn f32_type(arg: Vec) -> Vec; + + pub fn f64_type(arg: Vec) -> Vec; + + pub fn u32_type(arg: Vec) -> Vec; + + pub fn u64_type(arg: Vec) -> Vec; + + pub fn i32_type(arg: Vec) -> Vec; + + pub fn i64_type(arg: Vec) -> Vec; + + pub fn empty_type() -> Vec; + } +} diff --git a/tests/test_files/basic_argument_passing.rs b/tests/test_files/basic_argument_passing.rs new file mode 100644 index 0000000..beed225 --- /dev/null +++ b/tests/test_files/basic_argument_passing.rs @@ -0,0 +1,153 @@ +#![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, +) -> Vec { + let mut result = unsafe { + effector::all_types( + arg_0, + arg_1, + arg_2, + arg_3, + arg_4, + arg_5, + arg_6, + arg_7, + arg_8, + arg_9, + arg_10.clone(), + arg_11.clone(), + ) + }; + + result.push(arg_0 as u8); + result.extend(safe_transmute::transmute_one_to_bytes(&arg_1)); + result.extend(safe_transmute::transmute_one_to_bytes(&arg_2)); + result.extend(safe_transmute::transmute_one_to_bytes(&arg_3)); + result.extend(safe_transmute::transmute_one_to_bytes(&arg_4)); + result.extend(safe_transmute::transmute_one_to_bytes(&arg_5)); + result.extend(safe_transmute::transmute_one_to_bytes(&arg_6)); + result.extend(safe_transmute::transmute_one_to_bytes(&arg_7)); + result.extend(&arg_8.to_be_bytes()); + result.extend(&arg_9.to_be_bytes()); + result.extend(arg_10.into_bytes()); + result.extend(arg_11); + + result +} + +#[fce] +pub fn string_type(arg: String) -> String { + let arg = unsafe { effector::string_type(arg) }; + + format!("{}_{}", arg, arg) +} + +#[fce] +pub fn bytearray_type(arg: Vec) -> Vec { + let mut arg = unsafe { effector::bytearray_type(arg) }; + + arg.push(1); + arg +} + +#[fce] +pub fn bool_type(arg: bool) -> bool { + unsafe { effector::bool_type(arg) } +} + +#[fce] +pub fn f32_type(arg: f32) -> f32 { + let arg = unsafe { effector::f32_type(arg) }; + arg + 1.0 +} + +#[fce] +pub fn f64_type(arg: f64) -> f64 { + let arg = unsafe { effector::f64_type(arg) }; + arg + 1.0 +} + +#[fce] +pub fn u32_type(arg: u32) -> u32 { + let arg = unsafe { effector::u32_type(arg) }; + arg + 1 +} + +#[fce] +pub fn u64_type(arg: u64) -> u64 { + let arg = unsafe { effector::u64_type(arg) }; + arg + 1 +} + +#[fce] +pub fn i32_type(arg: i32) -> i32 { + let arg = unsafe { effector::i32_type(arg) }; + arg + 1 +} + +#[fce] +pub fn i64_type(arg: i64) -> i64 { + let arg = unsafe { effector::i64_type(arg) }; + arg + 1 +} + +#[fce] +pub fn empty_type() -> String { + unsafe { effector::empty_type() } +} + +mod effector { + use fluence::fce; + + #[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, + ) -> Vec; + + pub fn string_type(arg: String) -> String; + pub fn bytearray_type(arg: Vec) -> Vec; + + 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; + } +} diff --git a/tests/test_files/records.rs b/tests/test_files/records.rs new file mode 100644 index 0000000..e69de29 From b010fe93df8d867d01557cdda00b20e69462d235 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 14:29:01 +0300 Subject: [PATCH 34/41] Update crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs Co-authored-by: folex <0xdxdy@gmail.com> --- crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index 0f32669..e9c36e1 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -68,7 +68,7 @@ use std::path::PathBuf; /// .unwrap_or_else(|e| { /// panic!( /// "app service located at `{}` config can't be loaded: {}", -/// "/Users/mike/dev/work/fluence/wasm/fce/examples/greeting/Config.toml", e +/// "/path/to/greeting/Config.toml", e /// ) /// }); /// From 26c93581610c1d122427a6c8dcabcdf430bb466c Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 14:29:34 +0300 Subject: [PATCH 35/41] Update crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs Co-authored-by: folex <0xdxdy@gmail.com> --- .../src/fce_test/glue_code_generator.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index e9c36e1..bb1c331 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -118,12 +118,13 @@ pub(super) fn generate_test_glue_code( 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 } }; From e040a172535aea63fe85ecf96fd2a9c3ef4cb23a Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 14:29:40 +0300 Subject: [PATCH 36/41] Update crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs Co-authored-by: folex <0xdxdy@gmail.com> --- .../src/fce_test/glue_code_generator.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index bb1c331..850bd26 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -89,10 +89,11 @@ use std::path::PathBuf; /// // (3) ///``` /// -/// Here [(0), (1)] - module_definitions -/// [(1), (2)] - AppService ctor -/// [(2), (3)] - ctors of all modules of the tested service -/// [(3), (4)] - original test function +/// 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, From a4908f37cd604dcde705c1555d12c46bb444ab67 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 14:37:32 +0300 Subject: [PATCH 37/41] pr fixes --- .../src/fce_test/glue_code_generator.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs index 850bd26..bdc7dc5 100644 --- a/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/glue_code_generator.rs @@ -28,7 +28,19 @@ use quote::ToTokens; use std::path::PathBuf; /// Generates glue code for tests. -/// F.e. for the greeting service the following glue code would be generated: +/// 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 { @@ -87,6 +99,11 @@ use std::path::PathBuf; /// 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: @@ -121,10 +138,13 @@ pub(super) fn generate_test_glue_code( #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 } From a0fd5b2bc63aa1866b2a56a0c7477fa58471f222 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 14:42:23 +0300 Subject: [PATCH 38/41] fix get_output_type --- crates/fce-test-macro-impl/src/errors.rs | 3 +++ .../fce_test/module_generator/methods_generator.rs | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/fce-test-macro-impl/src/errors.rs b/crates/fce-test-macro-impl/src/errors.rs index af368c1..2497763 100644 --- a/crates/fce-test-macro-impl/src/errors.rs +++ b/crates/fce-test-macro-impl/src/errors.rs @@ -42,6 +42,9 @@ pub enum TestGeneratorError { "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)] diff --git a/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs index 7d6ac63..bdc2a47 100644 --- a/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs +++ b/crates/fce-test-macro-impl/src/fce_test/module_generator/methods_generator.rs @@ -16,6 +16,7 @@ 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; @@ -56,7 +57,7 @@ fn generate_fce_call( 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 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)?; @@ -140,7 +141,7 @@ fn generate_arguments<'a, 'r>( } fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TResult { - let output_type = get_output_type(output_types); + let output_type = get_output_type(output_types)?; match output_type { None => Ok(TokenStream::new()), Some(ty) => { @@ -152,10 +153,10 @@ fn generate_output_type(output_types: &[IType], records: &FCERecordTypes) -> TRe } } -fn get_output_type(output_types: &[IType]) -> Option<&IType> { +fn get_output_type(output_types: &[IType]) -> TResult> { match output_types.len() { - 0 => None, - 1 => Some(&output_types[0]), - _ => unimplemented!("function with more than 1 arguments aren't supported now"), + 0 => Ok(None), + 1 => Ok(Some(&output_types[0])), + _ => Err(TestGeneratorError::ManyFnOutputsUnsupported), } } From 6abd3e0907152362e83f5339723a6a15fa4d8828 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 14:46:33 +0300 Subject: [PATCH 39/41] delete # https://docs.rs/about --- crates/fce-macro/Cargo.toml | 2 +- crates/fce-test-macro-impl/Cargo.toml | 2 +- crates/fce-test-macro/Cargo.toml | 2 +- crates/main/Cargo.toml | 2 +- crates/wit/Cargo.toml | 2 +- fluence-test/Cargo.toml | 2 +- fluence/Cargo.toml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/fce-macro/Cargo.toml b/crates/fce-macro/Cargo.toml index c860d93..d0997e3 100644 --- a/crates/fce-macro/Cargo.toml +++ b/crates/fce-macro/Cargo.toml @@ -10,7 +10,7 @@ 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] diff --git a/crates/fce-test-macro-impl/Cargo.toml b/crates/fce-test-macro-impl/Cargo.toml index f828a43..436cb5b 100644 --- a/crates/fce-test-macro-impl/Cargo.toml +++ b/crates/fce-test-macro-impl/Cargo.toml @@ -9,7 +9,7 @@ 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 [dependencies] diff --git a/crates/fce-test-macro/Cargo.toml b/crates/fce-test-macro/Cargo.toml index 5830e1f..eb15b83 100644 --- a/crates/fce-test-macro/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -9,7 +9,7 @@ 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] diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index b2a3b65..abfdbcf 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -10,7 +10,7 @@ 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] diff --git a/crates/wit/Cargo.toml b/crates/wit/Cargo.toml index cbb511f..cd47583 100644 --- a/crates/wit/Cargo.toml +++ b/crates/wit/Cargo.toml @@ -10,7 +10,7 @@ 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] diff --git a/fluence-test/Cargo.toml b/fluence-test/Cargo.toml index d75e52e..6359737 100644 --- a/fluence-test/Cargo.toml +++ b/fluence-test/Cargo.toml @@ -11,7 +11,7 @@ categories = ["api-bindings", "wasm"] license = "Apache-2.0" edition = "2018" -[package.metadata.docs.rs] # https://docs.rs/about +[package.metadata.docs.rs] all-features = true [lib] diff --git a/fluence/Cargo.toml b/fluence/Cargo.toml index e093b47..6c45896 100644 --- a/fluence/Cargo.toml +++ b/fluence/Cargo.toml @@ -11,7 +11,7 @@ categories = ["api-bindings", "wasm"] license = "Apache-2.0" edition = "2018" -[package.metadata.docs.rs] # https://docs.rs/about +[package.metadata.docs.rs] all-features = true [lib] From fc320fe50d291c17b7a26d97bbef14ce87a6bf3b Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 18:36:25 +0300 Subject: [PATCH 40/41] add trybuild tests --- crates/fce-macro/Cargo.toml | 1 + crates/fce-test-macro/Cargo.toml | 1 + crates/main/Cargo.toml | 1 + fluence-test/Cargo.toml | 1 + fluence/Cargo.toml | 4 + fluence/tests/export_functions/arrays.rs | 67 +++++++ fluence/tests/export_functions/basic_types.rs | 73 ++++++++ .../tests/export_functions/improper_types.rs | 24 +++ .../export_functions/improper_types.stderr | 29 +++ fluence/tests/import_functions/arrays.rs | 40 ++++ fluence/tests/import_functions/basic_types.rs | 40 ++++ .../tests/import_functions/improper_types.rs | 24 +++ .../import_functions/improper_types.stderr | 5 + fluence/tests/records/basic_structs.rs | 82 ++++++++ fluence/tests/records/empty_struct.rs | 8 + .../records/struct_with_improper_types.rs | 20 ++ .../records/struct_with_improper_types.stderr | 17 ++ .../records/struct_with_private_fields.rs | 11 ++ .../records/struct_with_private_fields.stderr | 5 + fluence/tests/test_runner.rs | 16 ++ tests/test_files/arrays_passing.rs | 175 ------------------ tests/test_files/basic_argument_passing.rs | 153 --------------- tests/test_files/records.rs | 0 23 files changed, 469 insertions(+), 328 deletions(-) create mode 100644 fluence/tests/export_functions/arrays.rs create mode 100644 fluence/tests/export_functions/basic_types.rs create mode 100644 fluence/tests/export_functions/improper_types.rs create mode 100644 fluence/tests/export_functions/improper_types.stderr create mode 100644 fluence/tests/import_functions/arrays.rs create mode 100644 fluence/tests/import_functions/basic_types.rs create mode 100644 fluence/tests/import_functions/improper_types.rs create mode 100644 fluence/tests/import_functions/improper_types.stderr create mode 100644 fluence/tests/records/basic_structs.rs create mode 100644 fluence/tests/records/empty_struct.rs create mode 100644 fluence/tests/records/struct_with_improper_types.rs create mode 100644 fluence/tests/records/struct_with_improper_types.stderr create mode 100644 fluence/tests/records/struct_with_private_fields.rs create mode 100644 fluence/tests/records/struct_with_private_fields.stderr create mode 100644 fluence/tests/test_runner.rs delete mode 100644 tests/test_files/arrays_passing.rs delete mode 100644 tests/test_files/basic_argument_passing.rs delete mode 100644 tests/test_files/records.rs diff --git a/crates/fce-macro/Cargo.toml b/crates/fce-macro/Cargo.toml index d0997e3..9c78807 100644 --- a/crates/fce-macro/Cargo.toml +++ b/crates/fce-macro/Cargo.toml @@ -15,6 +15,7 @@ all-features = true [lib] proc-macro = true +doctest = false [dependencies] fluence-sdk-wit = { path = "../wit", version = "=0.5.0" } diff --git a/crates/fce-test-macro/Cargo.toml b/crates/fce-test-macro/Cargo.toml index eb15b83..c8578ca 100644 --- a/crates/fce-test-macro/Cargo.toml +++ b/crates/fce-test-macro/Cargo.toml @@ -14,6 +14,7 @@ all-features = true [lib] proc-macro = true +doctest = false [dependencies] fluence-sdk-test-macro-impl = { path = "../fce-test-macro-impl", version = "=0.5.0" } diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index abfdbcf..0ad43c8 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -16,6 +16,7 @@ all-features = true [lib] path = "src/lib.rs" crate-type = ["rlib"] +doctest = false [dependencies] fluence-sdk-macro = { path = "../fce-macro", version = "=0.5.0" } diff --git a/fluence-test/Cargo.toml b/fluence-test/Cargo.toml index 6359737..76c4596 100644 --- a/fluence-test/Cargo.toml +++ b/fluence-test/Cargo.toml @@ -16,6 +16,7 @@ all-features = true [lib] path = "src/lib.rs" +doctest = false [dependencies] fluence-sdk-test-macro = { path = "../crates/fce-test-macro", version = "=0.5.0" } diff --git a/fluence/Cargo.toml b/fluence/Cargo.toml index 6c45896..a8803f1 100644 --- a/fluence/Cargo.toml +++ b/fluence/Cargo.toml @@ -16,11 +16,15 @@ 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" } +[dev-dependencies] +trybuild = "1.0" + [features] # Print some internal logs by log_utf8_string debug = ["fluence-sdk-main/debug"] diff --git a/fluence/tests/export_functions/arrays.rs b/fluence/tests/export_functions/arrays.rs new file mode 100644 index 0000000..2b9c7f4 --- /dev/null +++ b/fluence/tests/export_functions/arrays.rs @@ -0,0 +1,67 @@ +#![allow(improper_ctypes)] + +use fluence::fce; + +pub fn main() {} + +#[fce] +pub fn byte_type( __arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn inner_arrays_1(_arg: Vec>>>) -> Vec>>> { + unimplemented!() +} + +#[fce] +#[derive(Default)] +pub struct TestRecord { + pub field_0: i32, + pub field_1: Vec>, +} + +#[fce] +pub fn inner_arrays_2(_arg: Vec>>>) -> Vec>>> { + unimplemented!() +} + +#[fce] +pub fn string_type(_arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn f32_type(_arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn f64_type(_arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn u32_type(_arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn u64_type(_arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn i32_type(_arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn i64_type(_arg: Vec) -> Vec { + unimplemented!() +} + +#[fce] +pub fn empty_type() -> Vec { + unimplemented!() +} diff --git a/fluence/tests/export_functions/basic_types.rs b/fluence/tests/export_functions/basic_types.rs new file mode 100644 index 0000000..b0cd5fb --- /dev/null +++ b/fluence/tests/export_functions/basic_types.rs @@ -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, +) -> Vec { + unimplemented!() +} + +#[fce] +pub fn string_type(_arg: String) -> String { + unimplemented!() +} + +#[fce] +pub fn bytearray_type(_arg: Vec) -> Vec { + 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!() +} diff --git a/fluence/tests/export_functions/improper_types.rs b/fluence/tests/export_functions/improper_types.rs new file mode 100644 index 0000000..d2caa86 --- /dev/null +++ b/fluence/tests/export_functions/improper_types.rs @@ -0,0 +1,24 @@ +#![allow(improper_ctypes)] + +use fluence::fce; + +pub fn main() {} + +#[fce] +fn test(_arg_1: Box) {} + +#[fce] +fn test2(_arg_1: std::rc::Rc) {} + +#[fce] +fn test3(_arg_1: std::collections::HashMap) {} + +#[fce] +fn test4(_arg_1: i32) -> (i32, i32) { + unimplemented!() +} + +#[fce] +fn test5(_arg_1: i32) -> Box { + unimplemented!() +} diff --git a/fluence/tests/export_functions/improper_types.stderr b/fluence/tests/export_functions/improper_types.stderr new file mode 100644 index 0000000..a77fcc0 --- /dev/null +++ b/fluence/tests/export_functions/improper_types.stderr @@ -0,0 +1,29 @@ +error: type with lifetimes or generics aren't allowed + --> $DIR/improper_types.rs:8:17 + | +8 | fn test(_arg_1: Box) {} + | ^^^^^^^^ + +error: type with lifetimes or generics aren't allowed + --> $DIR/improper_types.rs:11:27 + | +11 | fn test2(_arg_1: std::rc::Rc) {} + | ^^^^^^^ + +error: type with lifetimes or generics aren't allowed + --> $DIR/improper_types.rs:14:36 + | +14 | fn test3(_arg_1: std::collections::HashMap) {} + | ^^^^^^^^^^^^^^^^^^^^ + +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: type with lifetimes or generics aren't allowed + --> $DIR/improper_types.rs:22:26 + | +22 | fn test5(_arg_1: i32) -> Box { + | ^^^^^^^^ diff --git a/fluence/tests/import_functions/arrays.rs b/fluence/tests/import_functions/arrays.rs new file mode 100644 index 0000000..052a884 --- /dev/null +++ b/fluence/tests/import_functions/arrays.rs @@ -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>, +} + +#[fce] +#[link(wasm_import_module = "arrays_passing_effector")] +extern "C" { + pub fn inner_arrays_1(arg: Vec>>>) -> Vec>>>; + + pub fn inner_arrays_2( + arg: Vec>>>, + ) -> Vec>>>; + + pub fn string_type(arg: Vec) -> Vec; + + pub fn byte_type(arg: Vec) -> Vec; + + pub fn f32_type(arg: Vec) -> Vec; + + pub fn f64_type(arg: Vec) -> Vec; + + pub fn u32_type(arg: Vec) -> Vec; + + pub fn u64_type(arg: Vec) -> Vec; + + pub fn i32_type(arg: Vec) -> Vec; + + pub fn i64_type(arg: Vec) -> Vec; + + pub fn empty_type() -> Vec; +} diff --git a/fluence/tests/import_functions/basic_types.rs b/fluence/tests/import_functions/basic_types.rs new file mode 100644 index 0000000..340a5d2 --- /dev/null +++ b/fluence/tests/import_functions/basic_types.rs @@ -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, + ) -> Vec; + + pub fn string_type(arg: String) -> String; + pub fn bytearray_type(arg: Vec) -> Vec; + + 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; +} diff --git a/fluence/tests/import_functions/improper_types.rs b/fluence/tests/import_functions/improper_types.rs new file mode 100644 index 0000000..5888828 --- /dev/null +++ b/fluence/tests/import_functions/improper_types.rs @@ -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); + + #[fce] + fn test2(_arg_1: std::rc::Rc); + + #[fce] + fn test3(_arg_1: std::collections::HashMap); + + #[fce] + fn test4(_arg_1: i32) -> (i32, i32); + + #[fce] + fn test5(_arg_1: i32) -> Box; +} diff --git a/fluence/tests/import_functions/improper_types.stderr b/fluence/tests/import_functions/improper_types.stderr new file mode 100644 index 0000000..6879314 --- /dev/null +++ b/fluence/tests/import_functions/improper_types.stderr @@ -0,0 +1,5 @@ +error: type with lifetimes or generics aren't allowed + --> $DIR/improper_types.rs:11:21 + | +11 | fn test(_arg_1: Box); + | ^^^^^^^^ diff --git a/fluence/tests/records/basic_structs.rs b/fluence/tests/records/basic_structs.rs new file mode 100644 index 0000000..34d8b79 --- /dev/null +++ b/fluence/tests/records/basic_structs.rs @@ -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, +} + +#[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, +} + +#[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, +} diff --git a/fluence/tests/records/empty_struct.rs b/fluence/tests/records/empty_struct.rs new file mode 100644 index 0000000..7a8bce1 --- /dev/null +++ b/fluence/tests/records/empty_struct.rs @@ -0,0 +1,8 @@ +#![allow(improper_ctypes)] + +use fluence::fce; + +fn main() {} + +#[fce] +struct A {} diff --git a/fluence/tests/records/struct_with_improper_types.rs b/fluence/tests/records/struct_with_improper_types.rs new file mode 100644 index 0000000..40889a4 --- /dev/null +++ b/fluence/tests/records/struct_with_improper_types.rs @@ -0,0 +1,20 @@ +#![allow(improper_ctypes)] + +use fluence::fce; + +fn main() {} + +#[fce] +struct StructWithBox { + pub a: Box, +} + +#[fce] +struct StructWithRc { + pub a: std::rc::Rc, +} + +#[fce] +struct StructWithHashMap { + pub a: std::collections::HashMap, +} diff --git a/fluence/tests/records/struct_with_improper_types.stderr b/fluence/tests/records/struct_with_improper_types.stderr new file mode 100644 index 0000000..8275e88 --- /dev/null +++ b/fluence/tests/records/struct_with_improper_types.stderr @@ -0,0 +1,17 @@ +error: type with lifetimes or generics aren't allowed + --> $DIR/struct_with_improper_types.rs:9:12 + | +9 | pub a: Box, + | ^^^^^^^^ + +error: type with lifetimes or generics aren't allowed + --> $DIR/struct_with_improper_types.rs:14:21 + | +14 | pub a: std::rc::Rc, + | ^^^^^^^ + +error: type with lifetimes or generics aren't allowed + --> $DIR/struct_with_improper_types.rs:19:30 + | +19 | pub a: std::collections::HashMap, + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/fluence/tests/records/struct_with_private_fields.rs b/fluence/tests/records/struct_with_private_fields.rs new file mode 100644 index 0000000..ca4f2aa --- /dev/null +++ b/fluence/tests/records/struct_with_private_fields.rs @@ -0,0 +1,11 @@ +#![allow(improper_ctypes)] + +use fluence::fce; + +fn main() {} + +#[fce] +struct StructWithPrivateFields { + a: i32, + b: usize, +} diff --git a/fluence/tests/records/struct_with_private_fields.stderr b/fluence/tests/records/struct_with_private_fields.stderr new file mode 100644 index 0000000..22b2d15 --- /dev/null +++ b/fluence/tests/records/struct_with_private_fields.stderr @@ -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, + | ^^^^^^ diff --git a/fluence/tests/test_runner.rs b/fluence/tests/test_runner.rs new file mode 100644 index 0000000..ff32c6d --- /dev/null +++ b/fluence/tests/test_runner.rs @@ -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"); +} diff --git a/tests/test_files/arrays_passing.rs b/tests/test_files/arrays_passing.rs deleted file mode 100644 index b60b122..0000000 --- a/tests/test_files/arrays_passing.rs +++ /dev/null @@ -1,175 +0,0 @@ -use fluence::fce; - -pub fn main() {} - -#[fce] -pub fn byte_type(mut arg: Vec) -> Vec { - arg.push(0); - - let mut arg = unsafe { effector::byte_type(arg) }; - - arg.push(2); - arg -} - -#[fce] -pub fn inner_arrays_1(mut arg: Vec>>>) -> Vec>>> { - arg.push(vec![vec![vec![0]]]); - - let mut arg = unsafe { effector::inner_arrays_1(arg) }; - - arg.push(vec![vec![vec![2]]]); - arg -} - -#[fce] -#[derive(Default)] -pub struct TestRecord { - pub field_0: i32, - pub field_1: Vec>, -} - -#[fce] -pub fn inner_arrays_2(mut arg: Vec>>>) -> Vec>>> { - arg.push(vec![vec![vec![ - TestRecord { - field_0: 0, - field_1: vec![vec![1]], - }, - TestRecord::default(), - ]]]); - - let mut arg = unsafe { effector::inner_arrays_2(arg) }; - - arg.push(vec![vec![vec![ - TestRecord { - field_0: 1, - field_1: vec![vec![2]], - }, - TestRecord::default(), - ]]]); - - arg -} - -#[fce] -pub fn string_type(mut arg: Vec) -> Vec { - arg.push(String::from("fce")); - - let mut arg = unsafe { effector::string_type(arg) }; - - arg.push(String::from("test")); - arg -} - -/* -#[fce] -pub fn bool_type(arg: Vec) -> Vec { - let mut arg = unsafe { effector::bool_type(arg) }; - - arg.push(false); - arg -} - */ - -#[fce] -pub fn f32_type(mut arg: Vec) -> Vec { - arg.push(0.0); - - let mut arg = unsafe { effector::f32_type(arg) }; - - arg.push(1.0); - arg -} - -#[fce] -pub fn f64_type(mut arg: Vec) -> Vec { - arg.push(0.0); - - let mut arg = unsafe { effector::f64_type(arg) }; - - arg.push(1.0); - arg -} - -#[fce] -pub fn u32_type(mut arg: Vec) -> Vec { - arg.push(0); - - let mut arg = unsafe { effector::u32_type(arg) }; - - arg.push(2); - arg -} - -#[fce] -pub fn u64_type(mut arg: Vec) -> Vec { - arg.push(0); - - let mut arg = unsafe { effector::u64_type(arg) }; - - arg.push(2); - arg -} - -#[fce] -pub fn i32_type(mut arg: Vec) -> Vec { - arg.push(0); - - let mut arg = unsafe { effector::i32_type(arg) }; - - arg.push(2); - arg -} - -#[fce] -pub fn i64_type(mut arg: Vec) -> Vec { - arg.push(0); - - let mut arg = unsafe { effector::i64_type(arg) }; - - arg.push(1); - arg -} - -#[fce] -pub fn empty_type() -> Vec { - unsafe { effector::empty_type() } -} - -mod effector { - use fluence::fce; - use super::TestRecord; - - #[fce] - #[link(wasm_import_module = "arrays_passing_effector")] - extern "C" { - pub fn inner_arrays_1(arg: Vec>>>) -> Vec>>>; - - pub fn inner_arrays_2( - arg: Vec>>>, - ) -> Vec>>>; - - pub fn string_type(arg: Vec) -> Vec; - - pub fn byte_type(arg: Vec) -> Vec; - - /* - pub fn bool_type(arg: Vec) -> Vec; - */ - - pub fn f32_type(arg: Vec) -> Vec; - - pub fn f64_type(arg: Vec) -> Vec; - - pub fn u32_type(arg: Vec) -> Vec; - - pub fn u64_type(arg: Vec) -> Vec; - - pub fn i32_type(arg: Vec) -> Vec; - - pub fn i64_type(arg: Vec) -> Vec; - - pub fn empty_type() -> Vec; - } -} diff --git a/tests/test_files/basic_argument_passing.rs b/tests/test_files/basic_argument_passing.rs deleted file mode 100644 index beed225..0000000 --- a/tests/test_files/basic_argument_passing.rs +++ /dev/null @@ -1,153 +0,0 @@ -#![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, -) -> Vec { - let mut result = unsafe { - effector::all_types( - arg_0, - arg_1, - arg_2, - arg_3, - arg_4, - arg_5, - arg_6, - arg_7, - arg_8, - arg_9, - arg_10.clone(), - arg_11.clone(), - ) - }; - - result.push(arg_0 as u8); - result.extend(safe_transmute::transmute_one_to_bytes(&arg_1)); - result.extend(safe_transmute::transmute_one_to_bytes(&arg_2)); - result.extend(safe_transmute::transmute_one_to_bytes(&arg_3)); - result.extend(safe_transmute::transmute_one_to_bytes(&arg_4)); - result.extend(safe_transmute::transmute_one_to_bytes(&arg_5)); - result.extend(safe_transmute::transmute_one_to_bytes(&arg_6)); - result.extend(safe_transmute::transmute_one_to_bytes(&arg_7)); - result.extend(&arg_8.to_be_bytes()); - result.extend(&arg_9.to_be_bytes()); - result.extend(arg_10.into_bytes()); - result.extend(arg_11); - - result -} - -#[fce] -pub fn string_type(arg: String) -> String { - let arg = unsafe { effector::string_type(arg) }; - - format!("{}_{}", arg, arg) -} - -#[fce] -pub fn bytearray_type(arg: Vec) -> Vec { - let mut arg = unsafe { effector::bytearray_type(arg) }; - - arg.push(1); - arg -} - -#[fce] -pub fn bool_type(arg: bool) -> bool { - unsafe { effector::bool_type(arg) } -} - -#[fce] -pub fn f32_type(arg: f32) -> f32 { - let arg = unsafe { effector::f32_type(arg) }; - arg + 1.0 -} - -#[fce] -pub fn f64_type(arg: f64) -> f64 { - let arg = unsafe { effector::f64_type(arg) }; - arg + 1.0 -} - -#[fce] -pub fn u32_type(arg: u32) -> u32 { - let arg = unsafe { effector::u32_type(arg) }; - arg + 1 -} - -#[fce] -pub fn u64_type(arg: u64) -> u64 { - let arg = unsafe { effector::u64_type(arg) }; - arg + 1 -} - -#[fce] -pub fn i32_type(arg: i32) -> i32 { - let arg = unsafe { effector::i32_type(arg) }; - arg + 1 -} - -#[fce] -pub fn i64_type(arg: i64) -> i64 { - let arg = unsafe { effector::i64_type(arg) }; - arg + 1 -} - -#[fce] -pub fn empty_type() -> String { - unsafe { effector::empty_type() } -} - -mod effector { - use fluence::fce; - - #[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, - ) -> Vec; - - pub fn string_type(arg: String) -> String; - pub fn bytearray_type(arg: Vec) -> Vec; - - 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; - } -} diff --git a/tests/test_files/records.rs b/tests/test_files/records.rs deleted file mode 100644 index e69de29..0000000 From a44e9aa7006262c8c01defc0eeef67f51ffb8374 Mon Sep 17 00:00:00 2001 From: vms Date: Thu, 1 Apr 2021 18:38:16 +0300 Subject: [PATCH 41/41] fix error message --- crates/wit/src/parsed_type.rs | 2 +- fluence/tests/export_functions/improper_types.stderr | 8 ++++---- fluence/tests/import_functions/improper_types.stderr | 2 +- fluence/tests/records/struct_with_improper_types.stderr | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/wit/src/parsed_type.rs b/crates/wit/src/parsed_type.rs index 955bf4d..ea82523 100644 --- a/crates/wit/src/parsed_type.rs +++ b/crates/wit/src/parsed_type.rs @@ -123,7 +123,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(), diff --git a/fluence/tests/export_functions/improper_types.stderr b/fluence/tests/export_functions/improper_types.stderr index a77fcc0..484a611 100644 --- a/fluence/tests/export_functions/improper_types.stderr +++ b/fluence/tests/export_functions/improper_types.stderr @@ -1,16 +1,16 @@ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/improper_types.rs:8:17 | 8 | fn test(_arg_1: Box) {} | ^^^^^^^^ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/improper_types.rs:11:27 | 11 | fn test2(_arg_1: std::rc::Rc) {} | ^^^^^^^ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/improper_types.rs:14:36 | 14 | fn test3(_arg_1: std::collections::HashMap) {} @@ -22,7 +22,7 @@ error: Incorrect argument type - passing only by value is supported now 17 | fn test4(_arg_1: i32) -> (i32, i32) { | ^^^^^^^^^^ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/improper_types.rs:22:26 | 22 | fn test5(_arg_1: i32) -> Box { diff --git a/fluence/tests/import_functions/improper_types.stderr b/fluence/tests/import_functions/improper_types.stderr index 6879314..af4f71d 100644 --- a/fluence/tests/import_functions/improper_types.stderr +++ b/fluence/tests/import_functions/improper_types.stderr @@ -1,4 +1,4 @@ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/improper_types.rs:11:21 | 11 | fn test(_arg_1: Box); diff --git a/fluence/tests/records/struct_with_improper_types.stderr b/fluence/tests/records/struct_with_improper_types.stderr index 8275e88..c6584d4 100644 --- a/fluence/tests/records/struct_with_improper_types.stderr +++ b/fluence/tests/records/struct_with_improper_types.stderr @@ -1,16 +1,16 @@ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/struct_with_improper_types.rs:9:12 | 9 | pub a: Box, | ^^^^^^^^ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/struct_with_improper_types.rs:14:21 | 14 | pub a: std::rc::Rc, | ^^^^^^^ -error: type with lifetimes or generics aren't allowed +error: types with lifetimes or generics aren't allowed --> $DIR/struct_with_improper_types.rs:19:30 | 19 | pub a: std::collections::HashMap,