Record refactoring (#19)

This commit is contained in:
vms
2020-09-16 01:14:15 +03:00
committed by GitHub
parent 5259036913
commit dd52743024
66 changed files with 2382 additions and 386 deletions

View File

@ -10,7 +10,7 @@ jobs:
- checkout - checkout
- restore_cache: - restore_cache:
keys: keys:
- fce01-{{ checksum "Cargo.lock" }} - fce02-{{ checksum "Cargo.lock" }}
- run: | - run: |
rustup toolchain install nightly rustup toolchain install nightly
rustup component add rustfmt rustup component add rustfmt
@ -25,7 +25,7 @@ jobs:
paths: paths:
- ~/.cargo - ~/.cargo
- ~/.rustup - ~/.rustup
key: fce01-{{ checksum "Cargo.lock" }} key: fce02-{{ checksum "Cargo.lock" }}
examples: examples:
docker: docker:

5
.gitignore vendored
View File

@ -16,3 +16,8 @@ target/
!/examples/greeting/artifacts/*.wasm !/examples/greeting/artifacts/*.wasm
!/examples/ipfs_node/artifacts/*.wasm !/examples/ipfs_node/artifacts/*.wasm
!/examples/records/artifacts/*.wasm !/examples/records/artifacts/*.wasm
# Allowed Wasm files for test
!/fluence-faas/tests/json_wasm_tests/arguments_passing/artifacts/effector.wasm
!/fluence-faas/tests/json_wasm_tests/arguments_passing/artifacts/pure.wasm
!/fluence-faas/tests/json_wasm_tests/inner_records/artifacts/inner_records_pure.wasm

138
Cargo.lock generated
View File

@ -39,6 +39,14 @@ version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b"
[[package]]
name = "arguments-passing-test"
version = "0.1.0"
dependencies = [
"fluence 0.2.3",
"safe-transmute",
]
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.6" version = "0.3.6"
@ -158,7 +166,7 @@ checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
name = "call_parameters" name = "call_parameters"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
] ]
[[package]] [[package]]
@ -367,7 +375,7 @@ dependencies = [
name = "curl" name = "curl"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
"log", "log",
] ]
@ -598,12 +606,12 @@ dependencies = [
"fce-wit-interfaces", "fce-wit-interfaces",
"fce-wit-parser", "fce-wit-parser",
"log", "log",
"multi-map",
"multimap", "multimap",
"once_cell", "once_cell",
"parity-wasm", "parity-wasm",
"pwasm-utils", "pwasm-utils",
"reqwest", "reqwest",
"serde",
"tokio", "tokio",
"wasmer-interface-types-fl", "wasmer-interface-types-fl",
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
@ -616,7 +624,7 @@ name = "fce-wit-generator"
version = "0.1.4" version = "0.1.4"
dependencies = [ dependencies = [
"fce-wit-parser", "fce-wit-parser",
"fluence-sdk-wit 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "fluence-sdk-wit 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"once_cell", "once_cell",
"serde", "serde",
"serde_json", "serde_json",
@ -659,10 +667,19 @@ dependencies = [
[[package]] [[package]]
name = "fluence" name = "fluence"
version = "0.2.2" version = "0.2.2"
source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" source = "git+https://github.com/fluencelabs/rust-sdk?branch=record_support#9201a824f2ecc4f2668449ea956d9b10a39091e5"
dependencies = [ dependencies = [
"fluence-sdk-macro 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", "fluence-sdk-macro 0.2.2",
"fluence-sdk-main 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", "fluence-sdk-main 0.2.2",
]
[[package]]
name = "fluence"
version = "0.2.3"
source = "git+https://github.com/fluencelabs/rust-sdk#04e2538661bab57110a288a3c7d21a2905c377e4"
dependencies = [
"fluence-sdk-macro 0.2.3 (git+https://github.com/fluencelabs/rust-sdk)",
"fluence-sdk-main 0.2.3 (git+https://github.com/fluencelabs/rust-sdk)",
] ]
[[package]] [[package]]
@ -681,9 +698,12 @@ name = "fluence-faas"
version = "0.1.2" version = "0.1.2"
dependencies = [ dependencies = [
"cmd_lib", "cmd_lib",
"env_logger 0.7.1",
"fce", "fce",
"fluence-sdk-main 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "fluence-sdk-main 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools",
"log", "log",
"once_cell",
"safe-transmute", "safe-transmute",
"serde", "serde",
"serde_derive", "serde_derive",
@ -698,37 +718,55 @@ dependencies = [
[[package]] [[package]]
name = "fluence-sdk-macro" name = "fluence-sdk-macro"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/fluencelabs/rust-sdk?branch=record_support#9201a824f2ecc4f2668449ea956d9b10a39091e5"
checksum = "21ca1fdcc78a17bc84798cdc2b13c36a07555b1a3dfe9db9a6ec3a3079aaebe6"
dependencies = [ dependencies = [
"fluence-sdk-wit 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "fluence-sdk-wit 0.2.2",
] ]
[[package]] [[package]]
name = "fluence-sdk-macro" name = "fluence-sdk-macro"
version = "0.2.2" version = "0.2.3"
source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" source = "git+https://github.com/fluencelabs/rust-sdk#04e2538661bab57110a288a3c7d21a2905c377e4"
dependencies = [ dependencies = [
"fluence-sdk-wit 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", "fluence-sdk-wit 0.2.3 (git+https://github.com/fluencelabs/rust-sdk)",
]
[[package]]
name = "fluence-sdk-macro"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c326f99a17dccf48e9cceadb7f19df184142d023f74ccb76634b8f99ac2dac1b"
dependencies = [
"fluence-sdk-wit 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "fluence-sdk-main" name = "fluence-sdk-main"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/fluencelabs/rust-sdk?branch=record_support#9201a824f2ecc4f2668449ea956d9b10a39091e5"
checksum = "26474b00df6b7ec38cfcaf96c8636bca84f3e504c3e192c3341dc2372e23b30e"
dependencies = [ dependencies = [
"fluence-sdk-macro 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "fluence-sdk-macro 0.2.2",
"log", "log",
"serde", "serde",
] ]
[[package]] [[package]]
name = "fluence-sdk-main" name = "fluence-sdk-main"
version = "0.2.2" version = "0.2.3"
source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" source = "git+https://github.com/fluencelabs/rust-sdk#04e2538661bab57110a288a3c7d21a2905c377e4"
dependencies = [ dependencies = [
"fluence-sdk-macro 0.2.2 (git+https://github.com/fluencelabs/rust-sdk)", "fluence-sdk-macro 0.2.3 (git+https://github.com/fluencelabs/rust-sdk)",
"log",
"serde",
]
[[package]]
name = "fluence-sdk-main"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8377076746dede55b132c745c5058630f164d9977d7f7dc4e414a837300cd9cc"
dependencies = [
"fluence-sdk-macro 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log", "log",
"serde", "serde",
] ]
@ -736,8 +774,7 @@ dependencies = [
[[package]] [[package]]
name = "fluence-sdk-wit" name = "fluence-sdk-wit"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/fluencelabs/rust-sdk?branch=record_support#9201a824f2ecc4f2668449ea956d9b10a39091e5"
checksum = "93c94643121eb234778b7f8f0e12fd29ec7c70ac71d84329ae25daf5d263074d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -749,8 +786,22 @@ dependencies = [
[[package]] [[package]]
name = "fluence-sdk-wit" name = "fluence-sdk-wit"
version = "0.2.2" version = "0.2.3"
source = "git+https://github.com/fluencelabs/rust-sdk#dcb6cfddf95978e777a8a53710bda88aec7d4baf" source = "git+https://github.com/fluencelabs/rust-sdk#04e2538661bab57110a288a3c7d21a2905c377e4"
dependencies = [
"proc-macro2",
"quote",
"serde",
"serde_json",
"syn",
"uuid",
]
[[package]]
name = "fluence-sdk-wit"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cb9034a9a196c94b12d650d07398c7e63ff83e98c120397f411da44156ab93a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1091,6 +1142,14 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "inner-records-test"
version = "0.1.0"
dependencies = [
"fluence 0.2.3",
"safe-transmute",
]
[[package]] [[package]]
name = "inventory" name = "inventory"
version = "0.1.9" version = "0.1.9"
@ -1126,7 +1185,7 @@ dependencies = [
name = "ipfs-effector" name = "ipfs-effector"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
"log", "log",
] ]
@ -1134,7 +1193,7 @@ dependencies = [
name = "ipfs-pure" name = "ipfs-pure"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
"log", "log",
] ]
@ -1213,7 +1272,7 @@ checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
name = "local_storage" name = "local_storage"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
"log", "log",
] ]
@ -1329,6 +1388,12 @@ dependencies = [
"ws2_32-sys", "ws2_32-sys",
] ]
[[package]]
name = "multi-map"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bba551d6d795f74a01767577ea8339560bf0a65354e0417b7e915ed608443d46"
[[package]] [[package]]
name = "multimap" name = "multimap"
version = "0.8.2" version = "0.8.2"
@ -1696,7 +1761,7 @@ dependencies = [
name = "record-effector" name = "record-effector"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
"test-record", "test-record",
] ]
@ -1704,7 +1769,7 @@ dependencies = [
name = "record-pure" name = "record-pure"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
"test-record", "test-record",
] ]
@ -1989,7 +2054,7 @@ name = "site-storage"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"fluence", "fluence 0.2.2",
"log", "log",
] ]
@ -2068,9 +2133,9 @@ checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.40" version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963f7d3cc59b59b9325165add223142bbf1df27655d07789f109896d353d8350" checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2133,7 +2198,7 @@ dependencies = [
name = "test-record" name = "test-record"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.2",
] ]
[[package]] [[package]]
@ -2568,7 +2633,7 @@ checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
name = "wasm-greeting" name = "wasm-greeting"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fluence", "fluence 0.2.3",
] ]
[[package]] [[package]]
@ -2625,10 +2690,11 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-interface-types-fl" name = "wasmer-interface-types-fl"
version = "0.17.0" version = "0.17.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b12519a2a53ea1b2166ff47e56c6b57a3f7d714a2d34d26a6b04bdf22c37a41" checksum = "486603d8267c5ade7a8c62b4fe4e15a6349e64857f40c7a9ac2a2a28d81569b8"
dependencies = [ dependencies = [
"log",
"nom", "nom",
"safe-transmute", "safe-transmute",
"serde", "serde",

View File

@ -16,6 +16,8 @@ members = [
"examples/call_parameters", "examples/call_parameters",
"fluence-app-service", "fluence-app-service",
"fluence-faas", "fluence-faas",
"fluence-faas/tests/json_wasm_tests/arguments_passing",
"fluence-faas/tests/json_wasm_tests/inner_records",
"tools/cli", "tools/cli",
"tools/repl", "tools/repl",
] ]

View File

@ -12,9 +12,10 @@ path = "src/lib.rs"
[dependencies] [dependencies]
fce-wit-parser = { path = "../wit-parser", version = "0.1.3"} fce-wit-parser = { path = "../wit-parser", version = "0.1.3"}
fluence-sdk-wit = "0.2.3"
walrus = "0.17.0" walrus = "0.17.0"
fluence-sdk-wit = "0.2.0" wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.5" }
once_cell = "1.4.0" once_cell = "1.4.0"
wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.0", features = ["serde"] }
serde = { version = "1.0.110", features = ["derive"] } serde = { version = "1.0.110", features = ["derive"] }
serde_json = "1.0.56" serde_json = "1.0.56"

View File

@ -16,20 +16,21 @@
use wasmer_wit::ast::Interfaces; use wasmer_wit::ast::Interfaces;
use wasmer_wit::types::InterfaceType as IType; use wasmer_wit::types::InterfaceType as IType;
use wasmer_wit::ast::FunctionArg as IFunctionArg;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
pub(crate) struct ApiExportFuncDescriptor { pub(crate) struct ApiExportFuncDescriptor {
pub(crate) name: &'static str, pub(crate) name: &'static str,
pub(crate) id: u32, pub(crate) id: u32,
pub(crate) input_types: Vec<IType>, pub(crate) arguments: Vec<IFunctionArg>,
pub(crate) output_types: Vec<IType>, pub(crate) output_types: Vec<IType>,
} }
impl ApiExportFuncDescriptor { impl ApiExportFuncDescriptor {
pub fn update_interfaces(&self, interfaces: &mut Interfaces<'_>) { pub fn update_interfaces(&self, interfaces: &mut Interfaces<'_>) {
let func_type = wasmer_wit::ast::Type::Function { let func_type = wasmer_wit::ast::Type::Function {
inputs: self.input_types.clone(), arguments: self.arguments.clone(),
outputs: self.output_types.clone(), output_types: self.output_types.clone(),
}; };
interfaces.types.push(func_type); interfaces.types.push(func_type);
@ -45,7 +46,10 @@ pub(crate) static ALLOCATE_FUNC: Lazy<ApiExportFuncDescriptor> =
Lazy::new(|| ApiExportFuncDescriptor { Lazy::new(|| ApiExportFuncDescriptor {
name: "allocate", name: "allocate",
id: 0, id: 0,
input_types: vec![IType::I32], arguments: vec![IFunctionArg {
name: String::from("size"),
ty: IType::I32,
}],
output_types: vec![IType::I32], output_types: vec![IType::I32],
}); });
@ -53,7 +57,16 @@ pub(crate) static DEALLOCATE_FUNC: Lazy<ApiExportFuncDescriptor> =
Lazy::new(|| ApiExportFuncDescriptor { Lazy::new(|| ApiExportFuncDescriptor {
name: "deallocate", name: "deallocate",
id: 1, id: 1,
input_types: vec![IType::I32, IType::I32], arguments: vec![
IFunctionArg {
name: String::from("pointer"),
ty: IType::I32,
},
IFunctionArg {
name: String::from("size"),
ty: IType::I32,
},
],
output_types: vec![], output_types: vec![],
}); });
@ -61,7 +74,7 @@ pub(crate) static GET_RESULT_SIZE_FUNC: Lazy<ApiExportFuncDescriptor> =
Lazy::new(|| ApiExportFuncDescriptor { Lazy::new(|| ApiExportFuncDescriptor {
name: "get_result_size", name: "get_result_size",
id: 2, id: 2,
input_types: vec![], arguments: vec![],
output_types: vec![IType::I32], output_types: vec![IType::I32],
}); });
@ -69,7 +82,7 @@ pub(crate) static GET_RESULT_PTR_FUNC: Lazy<ApiExportFuncDescriptor> =
Lazy::new(|| ApiExportFuncDescriptor { Lazy::new(|| ApiExportFuncDescriptor {
name: "get_result_ptr", name: "get_result_ptr",
id: 3, id: 3,
input_types: vec![], arguments: vec![],
output_types: vec![IType::I32], output_types: vec![IType::I32],
}); });
@ -77,7 +90,10 @@ pub(crate) static SET_RESULT_SIZE_FUNC: Lazy<ApiExportFuncDescriptor> =
Lazy::new(|| ApiExportFuncDescriptor { Lazy::new(|| ApiExportFuncDescriptor {
name: "set_result_size", name: "set_result_size",
id: 4, id: 4,
input_types: vec![IType::I32], arguments: vec![IFunctionArg {
name: String::from("result_size"),
ty: IType::I32,
}],
output_types: vec![], output_types: vec![],
}); });
@ -85,6 +101,9 @@ pub(crate) static SET_RESULT_PTR_FUNC: Lazy<ApiExportFuncDescriptor> =
Lazy::new(|| ApiExportFuncDescriptor { Lazy::new(|| ApiExportFuncDescriptor {
name: "set_result_ptr", name: "set_result_ptr",
id: 5, id: 5,
input_types: vec![IType::I32], arguments: vec![IFunctionArg {
name: String::from("result_ptr"),
ty: IType::I32,
}],
output_types: vec![], output_types: vec![],
}); });

View File

@ -23,15 +23,17 @@ use crate::Result;
use wasmer_wit::types::InterfaceType as IType; use wasmer_wit::types::InterfaceType as IType;
use wasmer_wit::ast::Interfaces; use wasmer_wit::ast::Interfaces;
use wasmer_wit::types::RecordType;
#[derive(PartialEq, Debug, Default)] #[derive(PartialEq, Debug, Default)]
pub(crate) struct WITResolver<'a> { pub(crate) struct WITResolver<'a> {
pub(crate) types: std::collections::HashMap<String, u32>, types: std::collections::HashMap<String, usize>,
pub(crate) interfaces: Interfaces<'a>, pub(crate) interfaces: Interfaces<'a>,
not_resolved_types_count: usize,
} }
impl<'a> WITResolver<'a> { impl<'a> WITResolver<'a> {
pub(crate) fn get_record_type_id(&self, record_name: &str) -> Result<u32> { pub(crate) fn get_record_type_id(&self, record_name: &str) -> Result<usize> {
match self.types.get(record_name) { match self.types.get(record_name) {
Some(type_index) => Ok(*type_index), Some(type_index) => Ok(*type_index),
None => Err(crate::errors::WITGeneratorError::CorruptedRecord(format!( None => Err(crate::errors::WITGeneratorError::CorruptedRecord(format!(
@ -41,22 +43,63 @@ impl<'a> WITResolver<'a> {
} }
} }
// adds a stub for type with such a name if it wasn't found
pub(crate) fn get_record_type_id_unchecked(&mut self, record_name: &str) -> usize {
use wasmer_wit::ast::Type;
match self.types.get(record_name) {
Some(type_index) => *type_index,
None => {
self.types
.insert(record_name.to_string(), self.interfaces.types.len());
self.interfaces
.types
.push(Type::Record(RecordType::default()));
self.not_resolved_types_count += 1;
self.interfaces.types.len()
}
}
}
pub(crate) fn get_record_type( pub(crate) fn get_record_type(
&self, &self,
record_name: &str, record_type_id: u64,
) -> Result<wasmer_wit::types::RecordType> { ) -> Result<&wasmer_wit::types::RecordType> {
match self.types.get(record_name) { if record_type_id >= self.interfaces.types.len() as u64 {
Some(type_index) => match &self.interfaces.types[*type_index as usize] { return Err(crate::errors::WITGeneratorError::CorruptedRecord(format!(
wasmer_wit::ast::Type::Function { .. } => { "Can't find record with id {}, don't you forget to wrap it with #[fce]",
panic!("internal error inside WITResolver") record_type_id
} )));
wasmer_wit::ast::Type::Record(record_type) => Ok(record_type.clone()),
},
None => Err(crate::errors::WITGeneratorError::CorruptedRecord(format!(
"Can't find record with name='{}', don't you forget to wrap it with #[fce]",
record_name
))),
} }
match &self.interfaces.types[record_type_id as usize] {
wasmer_wit::ast::Type::Function { .. } => {
panic!("internal error inside WITResolver: interfaces AST type should be record not record")
}
wasmer_wit::ast::Type::Record(record_type) => Ok(record_type),
}
}
pub(crate) fn insert_record_type(&mut self, record: RecordType) {
use wasmer_wit::ast::Type;
match self.types.get(&record.name) {
Some(pos) => {
self.interfaces.types[*pos] = Type::Record(record);
self.not_resolved_types_count -= 1;
}
None => {
self.types
.insert(record.name.clone(), self.interfaces.types.len());
self.interfaces.types.push(Type::Record(record));
}
}
}
pub(crate) fn unresolved_types_count(&self) -> usize {
self.not_resolved_types_count
} }
} }

View File

@ -16,39 +16,48 @@
use super::WITGenerator; use super::WITGenerator;
use super::WITResolver; use super::WITResolver;
use super::utils::ptype_to_itype; use super::utils::ptype_to_itype_checked;
use crate::default_export_api_config::*; use crate::default_export_api_config::*;
use crate::Result; use crate::Result;
use fluence_sdk_wit::AstFunctionItem; use fluence_sdk_wit::AstFunctionItem;
use fluence_sdk_wit::ParsedType; use fluence_sdk_wit::ParsedType;
use wasmer_wit::interpreter::Instruction; use wasmer_wit::interpreter::Instruction;
use wasmer_wit::ast::FunctionArg as IFunctionArg;
impl WITGenerator for AstFunctionItem { impl WITGenerator for AstFunctionItem {
fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> { fn generate_wit<'a>(&'a self, wit_resolver: &mut WITResolver<'a>) -> Result<()> {
use wasmer_wit::ast::Type; use wasmer_wit::ast::Type;
use wasmer_wit::ast::Adapter; use wasmer_wit::ast::Adapter;
let inputs = self let arguments = self
.signature .signature
.input_types .arguments
.iter() .iter()
.map(|input_type| ptype_to_itype(input_type, wit_resolver)) .map(|(arg_name, arg_type)| -> Result<IFunctionArg> {
Ok(IFunctionArg {
name: arg_name.clone(),
ty: ptype_to_itype_checked(arg_type, wit_resolver)?,
})
})
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
let outputs = match self.signature.output_type { let output_types = match self.signature.output_type {
Some(ref output_type) => vec![ptype_to_itype(output_type, wit_resolver)?], Some(ref output_type) => vec![ptype_to_itype_checked(output_type, wit_resolver)?],
None => vec![], None => vec![],
}; };
let interfaces = &mut wit_resolver.interfaces; let interfaces = &mut wit_resolver.interfaces;
interfaces.types.push(Type::Function { interfaces.types.push(Type::Function {
inputs: inputs.clone(), arguments: arguments.clone(),
outputs: outputs.clone(), output_types: output_types.clone(),
}); });
// TODO: replace with Wasm types // TODO: replace with Wasm types
interfaces.types.push(Type::Function { inputs, outputs }); interfaces.types.push(Type::Function {
arguments,
output_types,
});
let adapter_idx = (interfaces.types.len() - 2) as u32; let adapter_idx = (interfaces.types.len() - 2) as u32;
let export_idx = (interfaces.types.len() - 1) as u32; let export_idx = (interfaces.types.len() - 1) as u32;
@ -60,16 +69,19 @@ impl WITGenerator for AstFunctionItem {
let mut instructions = self let mut instructions = self
.signature .signature
.input_types .arguments
.iter() .iter()
.enumerate() .enumerate()
.try_fold::<_, _, Result<_>>(Vec::new(), |mut instructions, (arg_id, input_type)| { .try_fold::<_, _, Result<_>>(
let mut new_instructions = Vec::new(),
input_type.generate_instructions_for_input_type(arg_id as _, wit_resolver)?; |mut instructions, (arg_id, (_, input_type))| {
let mut new_instructions = input_type
.generate_instructions_for_input_type(arg_id as _, wit_resolver)?;
instructions.append(&mut new_instructions); instructions.append(&mut new_instructions);
Ok(instructions) Ok(instructions)
})?; },
)?;
let export_function_index = (wit_resolver.interfaces.exports.len() - 1) as u32; let export_function_index = (wit_resolver.interfaces.exports.len() - 1) as u32;
instructions.push(Instruction::CallCore { instructions.push(Instruction::CallCore {
@ -119,8 +131,8 @@ impl FnInstructionGenerator for ParsedType {
ParsedType::Boolean => vec![Instruction::ArgumentGet { index }], ParsedType::Boolean => vec![Instruction::ArgumentGet { index }],
ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS8], ParsedType::I8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS8],
ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16], ParsedType::I16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS16],
ParsedType::I32 => vec![Instruction::ArgumentGet { index }], ParsedType::I32 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromS32],
ParsedType::I64 => vec![Instruction::ArgumentGet { index }], ParsedType::I64 => vec![Instruction::ArgumentGet { index }, Instruction::I64FromS64],
ParsedType::U8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU8], ParsedType::U8 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU8],
ParsedType::U16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU16], ParsedType::U16 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU16],
ParsedType::U32 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU32], ParsedType::U32 => vec![Instruction::ArgumentGet { index }, Instruction::I32FromU32],
@ -142,11 +154,11 @@ impl FnInstructionGenerator for ParsedType {
Instruction::ByteArrayLowerMemory, Instruction::ByteArrayLowerMemory,
], ],
ParsedType::Record(record_name) => { ParsedType::Record(record_name) => {
let type_index = wit_resolver.get_record_type_id(record_name)?; let record_type_id = wit_resolver.get_record_type_id(record_name)? as u32;
vec! [ vec! [
Instruction::ArgumentGet { index }, Instruction::ArgumentGet { index },
Instruction::RecordLowerMemory { type_index }, Instruction::RecordLowerMemory { record_type_id },
] ]
}, },
}; };
@ -160,8 +172,8 @@ impl FnInstructionGenerator for ParsedType {
ParsedType::Boolean => vec![], ParsedType::Boolean => vec![],
ParsedType::I8 => vec![Instruction::S8FromI32], ParsedType::I8 => vec![Instruction::S8FromI32],
ParsedType::I16 => vec![Instruction::S16FromI32], ParsedType::I16 => vec![Instruction::S16FromI32],
ParsedType::I32 => vec![], ParsedType::I32 => vec![Instruction::S32FromI32],
ParsedType::I64 => vec![], ParsedType::I64 => vec![Instruction::S64FromI64],
ParsedType::U8 => vec![Instruction::U8FromI32], ParsedType::U8 => vec![Instruction::U8FromI32],
ParsedType::U16 => vec![Instruction::U16FromI32], ParsedType::U16 => vec![Instruction::U16FromI32],
ParsedType::U32 => vec![Instruction::U32FromI32], ParsedType::U32 => vec![Instruction::U32FromI32],
@ -185,11 +197,11 @@ impl FnInstructionGenerator for ParsedType {
Instruction::CallCore { function_index: DEALLOCATE_FUNC.id }, Instruction::CallCore { function_index: DEALLOCATE_FUNC.id },
], ],
ParsedType::Record(record_name) => { ParsedType::Record(record_name) => {
let type_index = wit_resolver.get_record_type_id(record_name)?; let record_type_id = wit_resolver.get_record_type_id(record_name)? as u32;
vec! [ vec! [
Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id }, Instruction::CallCore { function_index: GET_RESULT_PTR_FUNC.id },
Instruction::RecordLiftMemory { type_index }, Instruction::RecordLiftMemory { record_type_id },
] ]
}, },
}; };

View File

@ -16,13 +16,14 @@
use super::WITGenerator; use super::WITGenerator;
use super::WITResolver; use super::WITResolver;
use super::utils::ptype_to_itype; use super::utils::ptype_to_itype_checked;
use crate::default_export_api_config::*; use crate::default_export_api_config::*;
use crate::Result; use crate::Result;
use fluence_sdk_wit::AstExternModItem; use fluence_sdk_wit::AstExternModItem;
use fluence_sdk_wit::AstExternFnItem; use fluence_sdk_wit::AstExternFnItem;
use fluence_sdk_wit::ParsedType; use fluence_sdk_wit::ParsedType;
use wasmer_wit::ast::FunctionArg as IFunctionArg;
use wasmer_wit::interpreter::Instruction; use wasmer_wit::interpreter::Instruction;
use crate::instructions_generator::utils::wtype_to_itype; use crate::instructions_generator::utils::wtype_to_itype;
@ -51,28 +52,35 @@ fn generate_wit_for_import<'a>(
use wasmer_wit::ast::Type; use wasmer_wit::ast::Type;
use wasmer_wit::ast::Adapter; use wasmer_wit::ast::Adapter;
let inputs = import let arguments = import
.signature .signature
.input_types .arguments
.iter() .iter()
.map(|input_type| ptype_to_itype(input_type, wit_resolver)) .map(|(arg_name, arg_type)| -> Result<IFunctionArg> {
Ok(IFunctionArg {
name: arg_name.clone(),
ty: ptype_to_itype_checked(arg_type, wit_resolver)?,
})
})
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
let outputs = match import.signature.output_type { let output_types = match import.signature.output_type {
Some(ref output_type) => vec![ptype_to_itype(output_type, wit_resolver)?], Some(ref output_type) => vec![ptype_to_itype_checked(output_type, wit_resolver)?],
None => vec![], None => vec![],
}; };
let interfaces = &mut wit_resolver.interfaces; let interfaces = &mut wit_resolver.interfaces;
interfaces.types.push(Type::Function { inputs, outputs }); interfaces.types.push(Type::Function {
arguments,
output_types,
});
let raw_inputs = import let raw_inputs = import
.signature .signature
.input_types .arguments
.iter() .iter()
.map(to_raw_input_types) .map(to_raw_input_types)
.flatten() .flatten()
.map(|wt| wtype_to_itype(&wt))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let raw_outputs = match import.signature.output_type { let raw_outputs = match import.signature.output_type {
@ -84,13 +92,13 @@ fn generate_wit_for_import<'a>(
}; };
interfaces.types.push(Type::Function { interfaces.types.push(Type::Function {
inputs: raw_inputs.clone(), arguments: raw_inputs.clone(),
outputs: raw_outputs.clone(), output_types: raw_outputs.clone(),
}); });
interfaces.types.push(Type::Function { interfaces.types.push(Type::Function {
inputs: raw_inputs, arguments: raw_inputs,
outputs: raw_outputs, output_types: raw_outputs,
}); });
let adapter_idx = (interfaces.types.len() - 2) as u32; let adapter_idx = (interfaces.types.len() - 2) as u32;
@ -116,15 +124,18 @@ fn generate_wit_for_import<'a>(
let mut instructions = import let mut instructions = import
.signature .signature
.input_types .arguments
.iter() .iter()
.try_fold::<_, _, Result<_>>((0, Vec::new()), |(arg_id, mut instructions), input_type| { .try_fold::<_, _, Result<_>>(
let (mut new_instructions, shift) = (0, Vec::new()),
input_type.generate_instructions_for_input_type(arg_id as _, wit_resolver)?; |(arg_id, mut instructions), (_, input_type)| {
let (mut new_instructions, shift) =
input_type.generate_instructions_for_input_type(arg_id as _, wit_resolver)?;
instructions.append(&mut new_instructions); instructions.append(&mut new_instructions);
Ok((arg_id + shift, instructions)) Ok((arg_id + shift, instructions))
})? },
)?
.1; .1;
// TODO: refactor // TODO: refactor
@ -180,8 +191,8 @@ impl ForeignModInstructionGenerator for ParsedType {
ParsedType::Boolean => (vec![Instruction::ArgumentGet { index }], 1), ParsedType::Boolean => (vec![Instruction::ArgumentGet { index }], 1),
ParsedType::I8 => (vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32], 1), ParsedType::I8 => (vec![Instruction::ArgumentGet { index }, Instruction::S8FromI32], 1),
ParsedType::I16 => (vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32], 1), ParsedType::I16 => (vec![Instruction::ArgumentGet { index }, Instruction::S16FromI32], 1),
ParsedType::I32 => (vec![Instruction::ArgumentGet { index }], 1), ParsedType::I32 => (vec![Instruction::ArgumentGet { index }, Instruction::S32FromI32], 1),
ParsedType::I64 => (vec![Instruction::ArgumentGet { index }], 1), ParsedType::I64 => (vec![Instruction::ArgumentGet { index }, Instruction::S64FromI64], 1),
ParsedType::U8 => (vec![Instruction::ArgumentGet { index }, Instruction::U8FromI32], 1), ParsedType::U8 => (vec![Instruction::ArgumentGet { index }, Instruction::U8FromI32], 1),
ParsedType::U16 => (vec![Instruction::ArgumentGet { index }, Instruction::U16FromI32], 1), ParsedType::U16 => (vec![Instruction::ArgumentGet { index }, Instruction::U16FromI32], 1),
ParsedType::U32 => (vec![Instruction::ArgumentGet { index }, Instruction::U32FromI32], 1), ParsedType::U32 => (vec![Instruction::ArgumentGet { index }, Instruction::U32FromI32], 1),
@ -199,11 +210,11 @@ impl ForeignModInstructionGenerator for ParsedType {
Instruction::ByteArrayLiftMemory, Instruction::ByteArrayLiftMemory,
], 2), ], 2),
ParsedType::Record(record_name) => { ParsedType::Record(record_name) => {
let type_index = wit_resolver.get_record_type_id(record_name)?; let record_type_id = wit_resolver.get_record_type_id(record_name)? as u32;
(vec![ (vec![
Instruction::ArgumentGet { index }, Instruction::ArgumentGet { index },
Instruction::RecordLiftMemory { type_index }, Instruction::RecordLiftMemory { record_type_id },
], 1) ], 1)
} }
}; };
@ -217,8 +228,8 @@ impl ForeignModInstructionGenerator for ParsedType {
ParsedType::Boolean => vec![], ParsedType::Boolean => vec![],
ParsedType::I8 => vec![Instruction::I32FromS8], ParsedType::I8 => vec![Instruction::I32FromS8],
ParsedType::I16 => vec![Instruction::I32FromS16], ParsedType::I16 => vec![Instruction::I32FromS16],
ParsedType::I32 => vec![], ParsedType::I32 => vec![Instruction::I32FromS32],
ParsedType::I64 => vec![], ParsedType::I64 => vec![Instruction::I64FromS64],
ParsedType::U8 => vec![Instruction::I32FromU8], ParsedType::U8 => vec![Instruction::I32FromU8],
ParsedType::U16 => vec![Instruction::I32FromU16], ParsedType::U16 => vec![Instruction::I32FromU16],
ParsedType::U32 => vec![Instruction::I32FromU32], ParsedType::U32 => vec![Instruction::I32FromU32],
@ -244,10 +255,10 @@ impl ForeignModInstructionGenerator for ParsedType {
Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id },
], ],
ParsedType::Record(record_name) => { ParsedType::Record(record_name) => {
let type_index = wit_resolver.get_record_type_id(record_name)?; let record_type_id = wit_resolver.get_record_type_id(record_name)? as u32;
vec![ vec![
Instruction::RecordLowerMemory {type_index}, Instruction::RecordLowerMemory { record_type_id },
Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id }, Instruction::CallCore { function_index: SET_RESULT_PTR_FUNC.id },
] ]
}, },
@ -257,10 +268,11 @@ impl ForeignModInstructionGenerator for ParsedType {
} }
} }
use fluence_sdk_wit::WasmType; use fluence_sdk_wit::RustType;
use wasmer_wit::types::InterfaceType as IType;
pub fn to_raw_input_types(ty: &ParsedType) -> Vec<WasmType> { pub fn to_raw_input_types(arg: &(String, ParsedType)) -> Vec<IFunctionArg> {
match ty { match arg.1 {
ParsedType::Boolean ParsedType::Boolean
| ParsedType::I8 | ParsedType::I8
| ParsedType::I16 | ParsedType::I16
@ -268,15 +280,36 @@ pub fn to_raw_input_types(ty: &ParsedType) -> Vec<WasmType> {
| ParsedType::U8 | ParsedType::U8
| ParsedType::U16 | ParsedType::U16
| ParsedType::U32 | ParsedType::U32
| ParsedType::Record(_) => vec![WasmType::I32], | ParsedType::Record(_) => vec![IFunctionArg {
ParsedType::I64 | ParsedType::U64 => vec![WasmType::I64], name: arg.0.clone(),
ParsedType::F32 => vec![WasmType::F32], ty: IType::I32,
ParsedType::F64 => vec![WasmType::F64], }],
ParsedType::Utf8String | ParsedType::ByteVector => vec![WasmType::I32, WasmType::I32], ParsedType::I64 | ParsedType::U64 => vec![IFunctionArg {
name: arg.0.clone(),
ty: IType::I64,
}],
ParsedType::F32 => vec![IFunctionArg {
name: arg.0.clone(),
ty: IType::F32,
}],
ParsedType::F64 => vec![IFunctionArg {
name: arg.0.clone(),
ty: IType::F64,
}],
ParsedType::Utf8String | ParsedType::ByteVector => vec![
IFunctionArg {
name: format!("{}_ptr", arg.0),
ty: IType::I32,
},
IFunctionArg {
name: format!("{}_ptr", arg.0),
ty: IType::I32,
},
],
} }
} }
pub fn to_raw_output_type(ty: &ParsedType) -> Vec<WasmType> { pub fn to_raw_output_type(ty: &ParsedType) -> Vec<RustType> {
match ty { match ty {
ParsedType::Boolean ParsedType::Boolean
| ParsedType::I8 | ParsedType::I8
@ -284,10 +317,10 @@ pub fn to_raw_output_type(ty: &ParsedType) -> Vec<WasmType> {
| ParsedType::I32 | ParsedType::I32
| ParsedType::U8 | ParsedType::U8
| ParsedType::U16 | ParsedType::U16
| ParsedType::U32 => vec![WasmType::I32], | ParsedType::U32 => vec![RustType::I32],
ParsedType::I64 | ParsedType::U64 => vec![WasmType::I64], ParsedType::I64 | ParsedType::U64 => vec![RustType::I64],
ParsedType::F32 => vec![WasmType::F32], ParsedType::F32 => vec![RustType::F32],
ParsedType::F64 => vec![WasmType::F64], ParsedType::F64 => vec![RustType::F64],
ParsedType::Utf8String | ParsedType::ByteVector | ParsedType::Record(_) => vec![], ParsedType::Utf8String | ParsedType::ByteVector | ParsedType::Record(_) => vec![],
} }
} }

View File

@ -20,7 +20,7 @@ use crate::Result;
use fluence_sdk_wit::AstRecordItem; use fluence_sdk_wit::AstRecordItem;
use wasmer_wit::ast::Type; use wasmer_wit::types::RecordFieldType as IRecordFieldType;
use wasmer_wit::types::RecordType; use wasmer_wit::types::RecordType;
use wasmer_wit::vec1::Vec1; use wasmer_wit::vec1::Vec1;
@ -29,8 +29,11 @@ impl WITGenerator for AstRecordItem {
let fields = self let fields = self
.fields .fields
.iter() .iter()
.map(|field| super::utils::ptype_to_itype(&field.ty, wit_resolver)) .map(|field| IRecordFieldType {
.collect::<Result<Vec<_>>>()?; name: field.name.clone().unwrap_or_default(),
ty: super::utils::ptype_to_itype_unchecked(&field.ty, wit_resolver),
})
.collect::<Vec<_>>();
let fields = Vec1::new(fields).map_err(|_| { let fields = Vec1::new(fields).map_err(|_| {
crate::errors::WITGeneratorError::CorruptedRecord(format!( crate::errors::WITGeneratorError::CorruptedRecord(format!(
@ -39,15 +42,12 @@ impl WITGenerator for AstRecordItem {
)) ))
})?; })?;
wit_resolver let new_record_type = RecordType {
.interfaces name: self.name.clone(),
.types fields,
.push(Type::Record(RecordType { fields })); };
wit_resolver.types.insert( wit_resolver.insert_record_type(new_record_type);
self.name.clone(),
(wit_resolver.interfaces.types.len() - 1) as _,
);
Ok(()) Ok(())
} }

View File

@ -19,34 +19,55 @@ use crate::instructions_generator::WITResolver;
use crate::Result; use crate::Result;
use fluence_sdk_wit::ParsedType; use fluence_sdk_wit::ParsedType;
use fluence_sdk_wit::WasmType; use fluence_sdk_wit::RustType;
pub(crate) fn ptype_to_itype(pty: &ParsedType, wit_resolver: &WITResolver) -> Result<IType> { // return error if there is no record with such name
pub(crate) fn ptype_to_itype_checked(
pty: &ParsedType,
wit_resolver: &mut WITResolver,
) -> Result<IType> {
match pty { match pty {
ParsedType::I8 => Ok(IType::S8),
ParsedType::I16 => Ok(IType::S16),
ParsedType::I32 => Ok(IType::S32),
ParsedType::I64 => Ok(IType::S64),
ParsedType::U8 => Ok(IType::U8),
ParsedType::U16 => Ok(IType::U16),
ParsedType::U32 => Ok(IType::U32),
ParsedType::U64 => Ok(IType::U64),
ParsedType::F32 => Ok(IType::F32),
ParsedType::F64 => Ok(IType::F64),
ParsedType::Boolean => Ok(IType::I32),
ParsedType::Utf8String => Ok(IType::String),
ParsedType::ByteVector => Ok(IType::ByteArray),
ParsedType::Record(record_name) => { ParsedType::Record(record_name) => {
Ok(IType::Record(wit_resolver.get_record_type(record_name)?)) let record_type_id = wit_resolver.get_record_type_id(record_name)?;
Ok(IType::Record(record_type_id as _))
}
_ => Ok(ptype_to_itype_unchecked(pty, wit_resolver)),
}
}
pub(crate) fn ptype_to_itype_unchecked(pty: &ParsedType, wit_resolver: &mut WITResolver) -> IType {
match pty {
ParsedType::I8 => IType::S8,
ParsedType::I16 => IType::S16,
ParsedType::I32 => IType::S32,
ParsedType::I64 => IType::S64,
ParsedType::U8 => IType::U8,
ParsedType::U16 => IType::U16,
ParsedType::U32 => IType::U32,
ParsedType::U64 => IType::U64,
ParsedType::F32 => IType::F32,
ParsedType::F64 => IType::F64,
ParsedType::Boolean => IType::I32,
ParsedType::Utf8String => IType::String,
ParsedType::ByteVector => IType::ByteArray,
ParsedType::Record(record_name) => {
let record_type_id = wit_resolver.get_record_type_id_unchecked(record_name);
IType::Record(record_type_id as _)
} }
} }
} }
pub(crate) fn wtype_to_itype(pty: &WasmType) -> IType { pub(crate) fn wtype_to_itype(pty: &RustType) -> IType {
match pty { match pty {
WasmType::I32 => IType::I32, RustType::I8 => IType::S8,
WasmType::I64 => IType::I64, RustType::I16 => IType::S16,
WasmType::F32 => IType::F32, RustType::I32 => IType::S32,
WasmType::F64 => IType::F64, RustType::I64 => IType::S64,
RustType::U8 => IType::U8,
RustType::U16 => IType::U16,
RustType::U32 => IType::U32,
RustType::U64 => IType::U64,
RustType::F32 => IType::F32,
RustType::F64 => IType::F64,
} }
} }

View File

@ -17,6 +17,7 @@
use crate::default_export_api_config::*; use crate::default_export_api_config::*;
use crate::errors::WITGeneratorError; use crate::errors::WITGeneratorError;
use crate::instructions_generator::WITGenerator; use crate::instructions_generator::WITGenerator;
use crate::instructions_generator::WITResolver;
use crate::Result; use crate::Result;
pub use fluence_sdk_wit::FCEAst; pub use fluence_sdk_wit::FCEAst;
@ -77,12 +78,14 @@ fn wasm_ast_extractor(wasm_module: &walrus::Module) -> Result<ModuleAST> {
} }
fn generate_interfaces(module_ast: &ModuleAST) -> Result<Interfaces<'_>> { fn generate_interfaces(module_ast: &ModuleAST) -> Result<Interfaces<'_>> {
let mut wit_resolver = crate::instructions_generator::WITResolver::default(); let mut wit_resolver = WITResolver::default();
generate_default_export_api(&mut wit_resolver.interfaces); generate_default_export_api(&mut wit_resolver.interfaces);
for record in &module_ast.records { for record in &module_ast.records {
record.generate_wit(&mut wit_resolver)?; record.generate_wit(&mut wit_resolver)?;
} }
validate_records(&wit_resolver)?;
for function in &module_ast.functions { for function in &module_ast.functions {
function.generate_wit(&mut wit_resolver)?; function.generate_wit(&mut wit_resolver)?;
} }
@ -102,3 +105,49 @@ fn generate_default_export_api(interfaces: &mut Interfaces) {
SET_RESULT_SIZE_FUNC.update_interfaces(interfaces); SET_RESULT_SIZE_FUNC.update_interfaces(interfaces);
SET_RESULT_PTR_FUNC.update_interfaces(interfaces); SET_RESULT_PTR_FUNC.update_interfaces(interfaces);
} }
fn validate_records(wit_resolver: &WITResolver) -> Result<()> {
const TYPE_RESOLVE_RECURSION_LIMIT: u32 = 1024;
fn validate_record_type(
record_type: &wasmer_wit::types::RecordType,
recursion_level: u32,
wit_resolver: &WITResolver,
) -> Result<()> {
if recursion_level >= TYPE_RESOLVE_RECURSION_LIMIT {
return Err(WITGeneratorError::CorruptedRecord(String::from(
"too many inner structures level",
)));
}
for field in record_type.fields.iter() {
match &field.ty {
wasmer_wit::types::InterfaceType::Record(record_type_id) => {
let inner_record_type = wit_resolver.get_record_type(*record_type_id)?;
validate_record_type(&inner_record_type, recursion_level + 1, wit_resolver)?;
}
_ => continue,
}
}
Ok(())
}
if wit_resolver.unresolved_types_count() != 0 {
return Err(WITGeneratorError::CorruptedRecord(format!(
"{} types unresolved",
wit_resolver.unresolved_types_count()
)));
}
for ty in wit_resolver.interfaces.types.iter() {
let record_type = match ty {
wasmer_wit::ast::Type::Record(ty) => ty,
_ => continue,
};
validate_record_type(record_type, 0, wit_resolver)?;
}
Ok(())
}

View File

@ -11,5 +11,5 @@ name = "fce_wit_interfaces"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.0"} wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.5" }
multimap = "0.8.1" multimap = "0.8.1"

View File

@ -13,7 +13,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
walrus = "0.17.0" walrus = "0.17.0"
wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0"} wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0"}
wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.0"} wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.5" }
fce-wit-interfaces = { path = "../wit-interfaces", version = "0.1.1" } fce-wit-interfaces = { path = "../wit-interfaces", version = "0.1.1" }
anyhow = "1.0.31" anyhow = "1.0.31"

View File

@ -32,9 +32,9 @@ mod extractor;
pub use errors::WITParserError; pub use errors::WITParserError;
pub use embedder::embed_wit;
pub use embedder::embed_text_wit;
pub use deleter::delete_wit_section; pub use deleter::delete_wit_section;
pub use deleter::delete_wit_section_from_file; pub use deleter::delete_wit_section_from_file;
pub use embedder::embed_wit;
pub use embedder::embed_text_wit;
pub use extractor::extract_wit; pub use extractor::extract_wit;
pub use extractor::extract_text_wit; pub use extractor::extract_text_wit;

View File

@ -17,11 +17,11 @@ fce-wit-parser = { path = "../crates/wit-parser", version = "0.1.3" }
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }
# dynamicfunc-fat-closures allows using state inside DynamicFunc # dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0", features = ["dynamicfunc-fat-closures"] } wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.0", features = ["serde"] } wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.5" }
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.0" } wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.0" }
serde = { version = "1.0.114", default-features = false, features = [ "derive" ] }
multimap = "0.8.1" multimap = "0.8.1"
multi-map = "1.3.0"
boolinator = "2.4.0" boolinator = "2.4.0"
parity-wasm = "0.41.0" parity-wasm = "0.41.0"
pwasm-utils = "0.12.0" pwasm-utils = "0.12.0"

View File

@ -21,10 +21,10 @@ use std::collections::hash_map::Entry;
use std::collections::HashMap; use std::collections::HashMap;
/// Represent a function type inside FCE. /// Represent a function type inside FCE.
#[derive(Debug, serde::Serialize)] #[derive(Debug)]
pub struct FCEFunctionSignature<'a> { pub struct FCEFunctionSignature<'a> {
pub name: &'a str, pub name: &'a str,
pub input_types: &'a Vec<IType>, pub arguments: &'a Vec<IFunctionArg>,
pub output_types: &'a Vec<IType>, pub output_types: &'a Vec<IType>,
} }
@ -125,7 +125,7 @@ impl FCE {
self.modules.iter().map(|(module_name, module)| { self.modules.iter().map(|(module_name, module)| {
( (
module_name.as_str(), module_name.as_str(),
Self::get_module_function_signatures(module), Self::get_module_function_signatures(module).collect::<Vec<_>>(),
) )
}) })
} }
@ -134,22 +134,41 @@ impl FCE {
pub fn module_interface<S: AsRef<str>>( pub fn module_interface<S: AsRef<str>>(
&self, &self,
module_name: S, module_name: S,
) -> Result<Vec<FCEFunctionSignature<'_>>> { ) -> Result<impl Iterator<Item = FCEFunctionSignature<'_>>> {
match self.modules.get(module_name.as_ref()) { match self.modules.get(module_name.as_ref()) {
Some(module) => Ok(Self::get_module_function_signatures(module)), Some(module) => Ok(Self::get_module_function_signatures(module)),
None => Err(FCEError::NoSuchModule(module_name.as_ref().to_string())), None => Err(FCEError::NoSuchModule(module_name.as_ref().to_string())),
} }
} }
fn get_module_function_signatures(module: &FCEModule) -> Vec<FCEFunctionSignature<'_>> { /// Return record types of export functions of all loaded info FCE modules.
pub fn record_types(&self) -> impl Iterator<Item = &(u64, IRecordType)> {
self.modules
.iter()
.flat_map(|(_, module)| module.get_export_record_types())
}
/// Return record types exported by module with given name.
pub fn module_record_types<S: AsRef<str>>(
&self,
module_name: S,
) -> Result<impl Iterator<Item = &(u64, IRecordType)>> {
match self.modules.get(module_name.as_ref()) {
Some(module) => Ok(module.get_export_record_types()),
None => Err(FCEError::NoSuchModule(module_name.as_ref().to_string())),
}
}
fn get_module_function_signatures(
module: &FCEModule,
) -> impl Iterator<Item = FCEFunctionSignature<'_>> {
module module
.get_exports_signatures() .get_exports_signatures()
.map(|(name, input_types, output_types)| FCEFunctionSignature { .map(|(name, arguments, output_types)| FCEFunctionSignature {
name, name,
input_types, arguments,
output_types, output_types,
}) })
.collect::<Vec<_>>()
} }
#[rustfmt::skip] #[rustfmt::skip]

View File

@ -38,8 +38,12 @@ pub use engine::FCE;
pub use engine::FCEFunctionSignature; pub use engine::FCEFunctionSignature;
pub use errors::FCEError; pub use errors::FCEError;
pub use module::IValue; pub use module::IValue;
pub use module::IRecordType;
pub use module::IFunctionArg;
pub use module::IType; pub use module::IType;
pub use module::from_interface_values; pub use module::from_interface_values;
pub use module::to_interface_value; pub use module::to_interface_value;
pub use wasmer_wit::types::RecordFieldType as IRecordFieldType;
pub(crate) type Result<T> = std::result::Result<T, FCEError>; pub(crate) type Result<T> = std::result::Result<T, FCEError>;

View File

@ -16,6 +16,7 @@
use super::IValue; use super::IValue;
use super::IType; use super::IType;
use super::IFunctionArg;
use wasmer_wit::interpreter::wasm; use wasmer_wit::interpreter::wasm;
// In current implementation export simply does nothing, because there is no more // In current implementation export simply does nothing, because there is no more
@ -23,7 +24,7 @@ use wasmer_wit::interpreter::wasm;
// but explicit Exports is still required by wasmer-interface-types::Interpreter. // but explicit Exports is still required by wasmer-interface-types::Interpreter.
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct WITExport { pub(crate) struct WITExport {
inputs: Vec<IType>, arguments: Vec<IFunctionArg>,
outputs: Vec<IType>, outputs: Vec<IType>,
function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>, function: fn(arguments: &[IValue]) -> Result<Vec<IValue>, ()>,
} }
@ -32,7 +33,7 @@ impl WITExport {
#[allow(unused)] #[allow(unused)]
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Self { Self {
inputs: vec![], arguments: vec![],
outputs: vec![], outputs: vec![],
function: |_| -> _ { Ok(vec![]) }, function: |_| -> _ { Ok(vec![]) },
} }
@ -41,15 +42,15 @@ impl WITExport {
impl wasm::structures::Export for WITExport { impl wasm::structures::Export for WITExport {
fn inputs_cardinality(&self) -> usize { fn inputs_cardinality(&self) -> usize {
self.inputs.len() as usize self.arguments.len()
} }
fn outputs_cardinality(&self) -> usize { fn outputs_cardinality(&self) -> usize {
self.outputs.len() self.outputs.len()
} }
fn inputs(&self) -> &[IType] { fn arguments(&self) -> &[IFunctionArg] {
&self.inputs &self.arguments
} }
fn outputs(&self) -> &[IType] { fn outputs(&self) -> &[IType] {

View File

@ -15,17 +15,17 @@
*/ */
use super::wit_prelude::*; use super::wit_prelude::*;
use super::{IType, IValue, WValue}; use super::{IType, IRecordType, IFunctionArg, IValue, WValue};
use crate::Result; use crate::Result;
use crate::FCEModuleConfig; use crate::FCEModuleConfig;
use fce_wit_interfaces::FCEWITInterfaces; use fce_wit_interfaces::FCEWITInterfaces;
use fce_wit_parser::extract_wit;
use wasmer_core::Instance as WasmerInstance; use wasmer_core::Instance as WasmerInstance;
use wasmer_core::import::Namespace; use wasmer_core::import::Namespace;
use wasmer_runtime::compile; use wasmer_runtime::compile;
use wasmer_runtime::ImportObject; use wasmer_runtime::ImportObject;
use wasmer_wit::interpreter::Interpreter; use wasmer_wit::interpreter::Interpreter;
use fce_wit_parser::extract_wit;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
@ -38,8 +38,8 @@ type WITInterpreter =
#[derive(Clone)] #[derive(Clone)]
pub(super) struct WITModuleFunc { pub(super) struct WITModuleFunc {
interpreter: Arc<WITInterpreter>, interpreter: Arc<WITInterpreter>,
pub(super) inputs: Vec<IType>, pub(super) arguments: Vec<IFunctionArg>,
pub(super) outputs: Vec<IType>, pub(super) output_types: Vec<IType>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -65,7 +65,7 @@ impl Callable {
pub(crate) struct FCEModule { pub(crate) struct FCEModule {
// wasmer_instance is needed because WITInstance contains dynamic functions // wasmer_instance is needed because WITInstance contains dynamic functions
// that internally keep pointer to Wasmer instance. // that internally keep pointer to it.
#[allow(unused)] #[allow(unused)]
wasmer_instance: Box<WasmerInstance>, wasmer_instance: Box<WasmerInstance>,
@ -80,7 +80,10 @@ pub(crate) struct FCEModule {
host_import_object: ImportObject, host_import_object: ImportObject,
// TODO: replace with dyn Trait // TODO: replace with dyn Trait
exports_funcs: HashMap<String, Arc<Callable>>, export_funcs: HashMap<String, Arc<Callable>>,
// TODO: save refs instead of copies
record_types: Vec<(u64, IRecordType)>,
} }
impl FCEModule { impl FCEModule {
@ -116,7 +119,8 @@ impl FCEModule {
std::mem::transmute::<_, Arc<WITInstance>>(wit_instance) std::mem::transmute::<_, Arc<WITInstance>>(wit_instance)
}; };
let exports_funcs = Self::instantiate_wit_exports(wit_instance, &fce_wit)?; let export_funcs = Self::instantiate_wit_exports(&wit_instance, &fce_wit)?;
let record_types = Self::extract_export_record_types(&export_funcs, &wit_instance)?;
// call _start to populate the WASI state of the module // call _start to populate the WASI state of the module
#[rustfmt::skip] #[rustfmt::skip]
@ -128,12 +132,13 @@ impl FCEModule {
wasmer_instance: Box::new(wasmer_instance), wasmer_instance: Box::new(wasmer_instance),
import_object, import_object,
host_import_object: config.imports, host_import_object: config.imports,
exports_funcs, export_funcs,
record_types,
}) })
} }
pub(crate) fn call(&mut self, function_name: &str, args: &[IValue]) -> Result<Vec<IValue>> { pub(crate) fn call(&mut self, function_name: &str, args: &[IValue]) -> Result<Vec<IValue>> {
match self.exports_funcs.get_mut(function_name) { match self.export_funcs.get_mut(function_name) {
Some(func) => Arc::make_mut(func).call(args), Some(func) => Arc::make_mut(func).call(args),
None => Err(FCEError::NoSuchFunction(format!( None => Err(FCEError::NoSuchFunction(format!(
"{} hasn't been found while calling", "{} hasn't been found while calling",
@ -144,23 +149,27 @@ impl FCEModule {
pub(crate) fn get_exports_signatures( pub(crate) fn get_exports_signatures(
&self, &self,
) -> impl Iterator<Item = (&String, &Vec<IType>, &Vec<IType>)> { ) -> impl Iterator<Item = (&String, &Vec<IFunctionArg>, &Vec<IType>)> {
self.exports_funcs.iter().map(|(func_name, func)| { self.export_funcs.iter().map(|(func_name, func)| {
( (
func_name, func_name,
&func.wit_module_func.inputs, &func.wit_module_func.arguments,
&func.wit_module_func.outputs, &func.wit_module_func.output_types,
) )
}) })
} }
pub(crate) fn get_export_record_types(&self) -> impl Iterator<Item = &(u64, IRecordType)> {
self.record_types.iter()
}
pub(crate) fn get_wasi_state(&mut self) -> &wasmer_wasi::state::WasiState { pub(crate) fn get_wasi_state(&mut self) -> &wasmer_wasi::state::WasiState {
unsafe { wasmer_wasi::state::get_wasi_state(self.wasmer_instance.context_mut()) } unsafe { wasmer_wasi::state::get_wasi_state(self.wasmer_instance.context_mut()) }
} }
// TODO: change the cloning Callable behaviour after changes of Wasmer API // TODO: change the cloning Callable behaviour after changes of Wasmer API
pub(super) fn get_callable(&self, function_name: &str) -> Result<Arc<Callable>> { pub(super) fn get_callable(&self, function_name: &str) -> Result<Arc<Callable>> {
match self.exports_funcs.get(function_name) { match self.export_funcs.get(function_name) {
Some(func) => Ok(func.clone()), Some(func) => Ok(func.clone()),
None => Err(FCEError::NoSuchFunction(format!( None => Err(FCEError::NoSuchFunction(format!(
"{} hasn't been found while calling", "{} hasn't been found while calling",
@ -170,7 +179,7 @@ impl FCEModule {
} }
fn instantiate_wit_exports( fn instantiate_wit_exports(
wit_instance: Arc<WITInstance>, wit_instance: &Arc<WITInstance>,
wit: &FCEWITInterfaces<'_>, wit: &FCEWITInterfaces<'_>,
) -> Result<HashMap<String, Arc<Callable>>> { ) -> Result<HashMap<String, Arc<Callable>>> {
use fce_wit_interfaces::WITAstType; use fce_wit_interfaces::WITAstType;
@ -197,13 +206,14 @@ impl FCEModule {
match wit_type { match wit_type {
WITAstType::Function { WITAstType::Function {
inputs, outputs, .. arguments,
output_types,
} => { } => {
let interpreter: WITInterpreter = adapter_instructions.try_into()?; let interpreter: WITInterpreter = adapter_instructions.try_into()?;
let wit_module_func = WITModuleFunc { let wit_module_func = WITModuleFunc {
interpreter: Arc::new(interpreter), interpreter: Arc::new(interpreter),
inputs: inputs.clone(), arguments: arguments.clone(),
outputs: outputs.clone(), output_types: output_types.clone(),
}; };
Ok(( Ok((
@ -233,9 +243,9 @@ impl FCEModule {
use wasmer_core::vm::Ctx; use wasmer_core::vm::Ctx;
// returns function that will be called from imports of Wasmer module // returns function that will be called from imports of Wasmer module
fn dyn_func_from_raw_import<F>( fn dyn_func_from_raw_import<'a, 'b, F>(
inputs: Vec<IType>, inputs: impl Iterator<Item = &'a IType>,
outputs: Vec<IType>, outputs: impl Iterator<Item = &'b IType>,
raw_import: F, raw_import: F,
) -> DynamicFunc<'static> ) -> DynamicFunc<'static>
where where
@ -244,8 +254,8 @@ impl FCEModule {
use wasmer_core::types::FuncSig; use wasmer_core::types::FuncSig;
use super::type_converters::itype_to_wtype; use super::type_converters::itype_to_wtype;
let inputs = inputs.iter().map(itype_to_wtype).collect::<Vec<_>>(); let inputs = inputs.map(itype_to_wtype).collect::<Vec<_>>();
let outputs = outputs.iter().map(itype_to_wtype).collect::<Vec<_>>(); let outputs = outputs.map(itype_to_wtype).collect::<Vec<_>>();
DynamicFunc::new(Arc::new(FuncSig::new(inputs, outputs)), raw_import) DynamicFunc::new(Arc::new(FuncSig::new(inputs, outputs)), raw_import)
} }
@ -257,7 +267,10 @@ impl FCEModule {
import_name: String, import_name: String,
) -> impl Fn(&mut Ctx, &[WValue]) -> Vec<WValue> + 'static { ) -> impl Fn(&mut Ctx, &[WValue]) -> Vec<WValue> + 'static {
move |_: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> { move |_: &mut Ctx, inputs: &[WValue]| -> Vec<WValue> {
use wasmer_wit::interpreter::stack::Stackable;
use super::type_converters::wval_to_ival; use super::type_converters::wval_to_ival;
use super::type_converters::ival_to_wval;
log::trace!( log::trace!(
"raw import for {}.{} called with {:?}\n", "raw import for {}.{} called with {:?}\n",
@ -269,13 +282,13 @@ impl FCEModule {
// copy here because otherwise wit_instance will be consumed by the closure // copy here because otherwise wit_instance will be consumed by the closure
let wit_instance_callable = wit_instance.clone(); let wit_instance_callable = wit_instance.clone();
let wit_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>(); let wit_inputs = inputs.iter().map(wval_to_ival).collect::<Vec<_>>();
unsafe { let outputs = unsafe {
// error here will be propagated by the special error instruction // error here will be propagated by the special error instruction
let _ = interpreter.run( interpreter.run(
&wit_inputs, &wit_inputs,
Arc::make_mut(&mut wit_instance_callable.assume_init()), Arc::make_mut(&mut wit_instance_callable.assume_init()),
); )
} };
log::trace!( log::trace!(
"\nraw import for {}.{} finished", "\nraw import for {}.{} finished",
@ -283,9 +296,13 @@ impl FCEModule {
import_name import_name
); );
// wit import functions should only change the stack state - // TODO: optimize by prevent copying stack values
// the result will be returned by an export function outputs
vec![] .unwrap_or_default()
.as_slice()
.iter()
.map(ival_to_wval)
.collect::<Vec<_>>()
} }
} }
@ -309,7 +326,10 @@ impl FCEModule {
let wit_type = wit.type_by_idx_r(adapter_function_type)?; let wit_type = wit.type_by_idx_r(adapter_function_type)?;
match wit_type { match wit_type {
WITAstType::Function { inputs, outputs } => { WITAstType::Function {
arguments,
output_types,
} => {
let interpreter: WITInterpreter = adapter_instructions.try_into()?; let interpreter: WITInterpreter = adapter_instructions.try_into()?;
let raw_import = create_raw_import( let raw_import = create_raw_import(
@ -318,8 +338,12 @@ impl FCEModule {
import_namespace.to_string(), import_namespace.to_string(),
import_name.to_string(), import_name.to_string(),
); );
let wit_import =
dyn_func_from_raw_import(inputs.clone(), outputs.clone(), raw_import); let wit_import = dyn_func_from_raw_import(
arguments.iter().map(|IFunctionArg { ty, .. }| ty),
output_types.iter(),
raw_import,
);
Ok((import_namespace.to_string(), (*import_name, wit_import))) Ok((import_namespace.to_string(), (*import_name, wit_import)))
} }
@ -344,4 +368,57 @@ impl FCEModule {
Ok(import_object) Ok(import_object)
} }
fn extract_export_record_types(
export_funcs: &HashMap<String, Arc<Callable>>,
wit_instance: &Arc<WITInstance>,
) -> Result<Vec<(u64, IRecordType)>> {
fn handle_record_type(
record_type_id: u64,
wit_instance: &Arc<WITInstance>,
export_record_types: &mut Vec<(u64, IRecordType)>,
) -> Result<()> {
use wasmer_wit::interpreter::wasm::structures::Instance;
let record_type = wit_instance
.wit_record_by_id(record_type_id)
.ok_or_else(|| {
FCEError::WasmerResolveError(format!(
"record type with type id {} not found",
record_type_id
))
})?;
export_record_types.push((record_type_id, record_type.clone()));
for field in record_type.fields.iter() {
if let IType::Record(record_type_id) = &field.ty {
handle_record_type(*record_type_id, wit_instance, export_record_types)?;
}
}
Ok(())
}
let export_record_ids = export_funcs
.iter()
.flat_map(|(_, ref mut callable)| {
callable
.wit_module_func
.arguments
.iter()
.map(|arg| &arg.ty)
.chain(callable.wit_module_func.output_types.iter())
})
.filter_map(|itype| match itype {
IType::Record(record_type_id) => Some(record_type_id),
_ => None,
});
let mut export_record_types = Vec::new();
for record_type_id in export_record_ids {
handle_record_type(*record_type_id, wit_instance, &mut export_record_types)?;
}
Ok(export_record_types)
}
} }

View File

@ -22,6 +22,8 @@ mod type_converters;
mod fce_module; mod fce_module;
pub use wasmer_wit::types::InterfaceType as IType; pub use wasmer_wit::types::InterfaceType as IType;
pub use wasmer_wit::types::RecordType as IRecordType;
pub use wasmer_wit::ast::FunctionArg as IFunctionArg;
pub use wasmer_wit::values::InterfaceValue as IValue; pub use wasmer_wit::values::InterfaceValue as IValue;
pub use wasmer_wit::values::from_interface_values; pub use wasmer_wit::values::from_interface_values;
pub use wasmer_wit::values::to_interface_value; pub use wasmer_wit::values::to_interface_value;

View File

@ -15,7 +15,7 @@
*/ */
use super::fce_module::FCEModule; use super::fce_module::FCEModule;
use super::{IType, IValue, WValue}; use super::{IType, IFunctionArg, IValue, WValue};
use super::fce_module::Callable; use super::fce_module::Callable;
use crate::Result; use crate::Result;
@ -28,7 +28,7 @@ use std::sync::Arc;
enum WITFunctionInner { enum WITFunctionInner {
Export { Export {
func: Arc<DynFunc<'static>>, func: Arc<DynFunc<'static>>,
inputs: Vec<IType>, arguments: Vec<IFunctionArg>,
outputs: Vec<IType>, outputs: Vec<IType>,
}, },
Import { Import {
@ -49,10 +49,14 @@ impl WITFunction {
use super::type_converters::wtype_to_itype; use super::type_converters::wtype_to_itype;
let signature = dyn_func.signature(); let signature = dyn_func.signature();
let inputs = signature let arguments = signature
.params() .params()
.iter() .iter()
.map(wtype_to_itype) .map(|wtype| IFunctionArg {
// here it's considered as an anonymous arguments
name: String::new(),
ty: wtype_to_itype(wtype),
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let outputs = signature let outputs = signature
.returns() .returns()
@ -62,7 +66,7 @@ impl WITFunction {
let inner = WITFunctionInner::Export { let inner = WITFunctionInner::Export {
func: Arc::new(dyn_func), func: Arc::new(dyn_func),
inputs, arguments,
outputs, outputs,
}; };
@ -82,29 +86,31 @@ impl WITFunction {
impl wasm::structures::LocalImport for WITFunction { impl wasm::structures::LocalImport for WITFunction {
fn inputs_cardinality(&self) -> usize { fn inputs_cardinality(&self) -> usize {
match &self.inner { match &self.inner {
WITFunctionInner::Export { ref inputs, .. } => inputs.len(), WITFunctionInner::Export { arguments, .. } => arguments.len(),
WITFunctionInner::Import { ref callable, .. } => callable.wit_module_func.inputs.len(), WITFunctionInner::Import { callable, .. } => callable.wit_module_func.arguments.len(),
} }
} }
fn outputs_cardinality(&self) -> usize { fn outputs_cardinality(&self) -> usize {
match &self.inner { match &self.inner {
WITFunctionInner::Export { ref outputs, .. } => outputs.len(), WITFunctionInner::Export { ref outputs, .. } => outputs.len(),
WITFunctionInner::Import { ref callable, .. } => callable.wit_module_func.outputs.len(), WITFunctionInner::Import { ref callable, .. } => {
callable.wit_module_func.output_types.len()
}
} }
} }
fn inputs(&self) -> &[IType] { fn arguments(&self) -> &[IFunctionArg] {
match &self.inner { match &self.inner {
WITFunctionInner::Export { ref inputs, .. } => inputs, WITFunctionInner::Export { ref arguments, .. } => arguments,
WITFunctionInner::Import { ref callable, .. } => &callable.wit_module_func.inputs, WITFunctionInner::Import { ref callable, .. } => &callable.wit_module_func.arguments,
} }
} }
fn outputs(&self) -> &[IType] { fn outputs(&self) -> &[IType] {
match &self.inner { match &self.inner {
WITFunctionInner::Export { ref outputs, .. } => outputs, WITFunctionInner::Export { ref outputs, .. } => outputs,
WITFunctionInner::Import { ref callable, .. } => &callable.wit_module_func.outputs, WITFunctionInner::Import { ref callable, .. } => &callable.wit_module_func.output_types,
} }
} }

View File

@ -16,6 +16,7 @@
use super::wit_prelude::*; use super::wit_prelude::*;
use super::fce_module::FCEModule; use super::fce_module::FCEModule;
use super::IRecordType;
use crate::Result; use crate::Result;
use fce_wit_interfaces::FCEWITInterfaces; use fce_wit_interfaces::FCEWITInterfaces;
@ -29,9 +30,13 @@ use std::collections::HashMap;
/// Contains all import and export functions that could be called from WIT context by call-core. /// Contains all import and export functions that could be called from WIT context by call-core.
#[derive(Clone)] #[derive(Clone)]
pub(super) struct WITInstance { pub(super) struct WITInstance {
/// WIT functions indexed by id.
funcs: HashMap<usize, WITFunction>, funcs: HashMap<usize, WITFunction>,
/// WIT memories.
memories: Vec<WITMemory>, memories: Vec<WITMemory>,
record_types: HashMap<u32, WITAstType>,
record_types_by_id: HashMap<u64, IRecordType>,
} }
impl WITInstance { impl WITInstance {
@ -47,12 +52,12 @@ impl WITInstance {
exports.extend(imports); exports.extend(imports);
let funcs = exports; let funcs = exports;
let record_types = Self::extract_record_types(wit); let record_types_by_id = Self::extract_record_types(wit);
Ok(Self { Ok(Self {
funcs, funcs,
memories, memories,
record_types, record_types_by_id,
}) })
} }
@ -121,14 +126,21 @@ impl WITInstance {
memories memories
} }
fn extract_record_types(wit: &FCEWITInterfaces<'_>) -> HashMap<u32, WITAstType> { fn extract_record_types(wit: &FCEWITInterfaces<'_>) -> HashMap<u64, IRecordType> {
wit.types() let record_types_by_id = wit.types().fold(
.enumerate() (HashMap::new(), 0u64),
.filter_map(|(id, ty)| match ty { |(mut record_types_by_id, id), ty| {
WITAstType::Record(_) => Some((id as u32, ty.clone())), match ty {
_ => None, WITAstType::Record(record_type) => {
}) record_types_by_id.insert(id, record_type.clone());
.collect::<HashMap<_, _>>() }
WITAstType::Function { .. } => {}
};
(record_types_by_id, id + 1)
},
);
record_types_by_id.0
} }
} }
@ -140,10 +152,7 @@ impl wasm::structures::Instance<WITExport, WITFunction, WITMemory, WITMemoryView
None None
} }
fn local_or_import<I: TypedIndex + LocalImportIndex>( fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&WITFunction> {
&mut self,
index: I,
) -> Option<&WITFunction> {
self.funcs.get(&index.index()) self.funcs.get(&index.index())
} }
@ -155,7 +164,7 @@ impl wasm::structures::Instance<WITExport, WITFunction, WITMemory, WITMemoryView
} }
} }
fn wit_type(&self, index: u32) -> Option<&WITAstType> { fn wit_record_by_id(&self, index: u64) -> Option<&IRecordType> {
self.record_types.get(&index) self.record_types_by_id.get(&index)
} }
} }

View File

@ -18,26 +18,25 @@ use fce::FCE;
use fce::IValue; use fce::IValue;
#[test] #[test]
#[ignore]
pub fn records() { pub fn records() {
let effector_wasm_bytes = std::fs::read("../examples/records/artifacts/wasm_modules/effector") let effector_wasm_bytes = std::fs::read("../examples/records/artifacts/records_effector.wasm")
.expect("../examples/records/artifacts/wasm_modules/effector.wasm should presence"); .expect("../examples/records/artifacts/records_effector.wasm should presence");
let pure_wasm_bytes = std::fs::read("../examples/records/artifacts/wasm_modules/pure") let pure_wasm_bytes = std::fs::read("../examples/records/artifacts/records_pure.wasm")
.expect("../examples/records/artifacts/wasm_modules/pure.wasm should presence"); .expect("../examples/records/artifacts/records_pure.wasm should presence");
let mut fce = FCE::new(); let mut fce = FCE::new();
let load_result = fce.load_module("pure", &pure_wasm_bytes, <_>::default()); let load_result = fce.load_module("pure", &pure_wasm_bytes, <_>::default());
assert!(load_result.is_err()); assert!(load_result.is_err());
fce.load_module("effector", &effector_wasm_bytes, <_>::default()) fce.load_module("records_effector", &effector_wasm_bytes, <_>::default())
.unwrap_or_else(|e| panic!("can't load a module into FCE: {:?}", e)); .unwrap_or_else(|e| panic!("can't load a module into FCE: {:?}", e));
fce.load_module("pure", &pure_wasm_bytes, <_>::default()) fce.load_module("records_pure", &pure_wasm_bytes, <_>::default())
.unwrap_or_else(|e| panic!("can't load a module into FCE: {:?}", e)); .unwrap_or_else(|e| panic!("can't load a module into FCE: {:?}", e));
let result = fce let result = fce
.call("pure", "invoke", &[]) .call("records_pure", "invoke", &[])
.unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e)); .unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e));
assert_eq!( assert_eq!(

View File

@ -32,6 +32,7 @@ pub async fn download(url: &str) -> bytes::Bytes {
} }
#[tokio::test] #[tokio::test]
#[ignore]
async fn redis() { async fn redis() {
let wasm_bytes = download(REDIS_DOWNLOAD_URL).await; let wasm_bytes = download(REDIS_DOWNLOAD_URL).await;

9
examples/greeting/build.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
# This script builds all subprojects and puts all created Wasm modules in one dir
cargo update
fce build --release
rm artifacts/*
cp ../../target/wasm32-wasi/release/greeting.wasm artifacts/
cp ../../target/wasm32-wasi/release/greeting_cp.wasm artifacts/

14
examples/ipfs-node/build.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
# This script builds all subprojects and puts all created Wasm modules in one dir
cd effector
cargo update
fce build --release
cd ../pure
cargo update
fce build --release
cd ..
rm artifacts/*
cp ../../target/wasm32-wasi/release/ipfs_effector.wasm artifacts/
cp ../../target/wasm32-wasi/release/ipfs_pure.wasm artifacts/

View File

@ -9,5 +9,5 @@ name = "ipfs_effector"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] } fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"]}
log = "0.4.11" log = "0.4.11"

View File

@ -1,11 +1,11 @@
modules_dir = "artifacts/" modules_dir = "artifacts/"
[[module]] [[module]]
name = "effector" name = "records_effector"
mem_pages_count = 1 mem_pages_count = 1
logger_enabled = true logger_enabled = true
[[module]] [[module]]
name = "pure" name = "records_pure"
mem_pages_count = 1 mem_pages_count = 1
logger_enabled = true logger_enabled = true

14
examples/records/build.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
# This script builds all subprojects and puts all created Wasm modules in one dir
cd effector
cargo update
fce build --release
cd ../pure
cargo update
fce build --release
cd ..
rm artifacts/*
cp ../../target/wasm32-wasi/release/records_effector.wasm artifacts/
cp ../../target/wasm32-wasi/release/records_pure.wasm artifacts/

View File

@ -5,9 +5,9 @@ authors = ["Fluence Labs"]
edition = "2018" edition = "2018"
[[bin]] [[bin]]
name = "effector" name = "records_effector"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk" } fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] }
test-record = { path = "../test-record" } test-record = { path = "../test-record" }

View File

@ -20,7 +20,7 @@ use test_record::TestRecord;
pub fn main() {} pub fn main() {}
#[fce] #[fce]
pub fn mutate_struct(mut test_record: TestRecord) -> TestRecord { pub fn mutate_struct(mut test_record: test_record::TestRecord) -> TestRecord {
test_record.field_0 = true; test_record.field_0 = true;
test_record.field_1 = 1; test_record.field_1 = 1;
test_record.field_2 = 2; test_record.field_2 = 2;

View File

@ -5,9 +5,9 @@ authors = ["Fluence Labs"]
edition = "2018" edition = "2018"
[[bin]] [[bin]]
name = "pure" name = "records_pure"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk" } fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] }
test-record = { path = "../test-record" } test-record = { path = "../test-record" }

View File

@ -41,7 +41,7 @@ pub fn invoke() -> TestRecord {
} }
#[fce] #[fce]
#[link(wasm_import_module = "effector")] #[link(wasm_import_module = "records_effector")]
extern "C" { extern "C" {
pub fn mutate_struct(test_record: TestRecord) -> TestRecord; pub fn mutate_struct(test_record: TestRecord) -> TestRecord;
} }

View File

@ -9,4 +9,4 @@ name = "test_record"
path = "src/test_record.rs" path = "src/test_record.rs"
[dependencies] [dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk" } fluence = { git = "https://github.com/fluencelabs/rust-sdk", branch = "record_support" }

View File

@ -9,6 +9,6 @@ name = "site-storage"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk", features = ["logger"] } fluence = { git = "https://github.com/fluencelabs/rust-sdk", branch = "record_support", features = ["logger"] }
anyhow = "1.0.31" anyhow = "1.0.31"
log = "0.4.8" log = "0.4.8"

View File

@ -62,10 +62,8 @@ impl AppService {
arguments: serde_json::Value, arguments: serde_json::Value,
call_parameters: crate::CallParameters, call_parameters: crate::CallParameters,
) -> Result<Vec<IValue>> { ) -> Result<Vec<IValue>> {
let arguments = Self::json_to_ivalue(arguments)?;
self.faas self.faas
.call(module_name, func_name, &arguments, call_parameters) .call_with_json(module_name, func_name, arguments, call_parameters)
.map_err(Into::into) .map_err(Into::into)
} }
@ -132,33 +130,6 @@ impl AppService {
Ok(config) Ok(config)
} }
fn json_to_ivalue(arguments: serde_json::Value) -> Result<Vec<IValue>> {
// If arguments are on of: null, [] or {}, avoid calling `to_interface_value`
let is_null = arguments.is_null();
let is_empty_arr = arguments.as_array().map_or(false, |a| a.is_empty());
let is_empty_obj = arguments.as_object().map_or(false, |m| m.is_empty());
let arguments = if !is_null && !is_empty_arr && !is_empty_obj {
Some(fluence_faas::to_interface_value(&arguments).map_err(|e| {
AppServiceError::InvalidConfig(format!(
"can't parse arguments as array of interface types: {}",
e
))
})?)
} else {
None
};
match arguments {
Some(IValue::Record(arguments)) => Ok(arguments.into_vec()),
// Convert null, [] and {} into vec![]
None => Ok(vec![]),
other => Err(AppServiceError::InvalidConfig(format!(
"expected array of interface values: got {:?}",
other
))),
}
}
} }
// This API is intended for testing purposes (mostly in FCE REPL) // This API is intended for testing purposes (mostly in FCE REPL)

View File

@ -8,23 +8,27 @@ edition = "2018"
[dependencies] [dependencies]
fce = { path = "../engine", version = "0.1.3" } fce = { path = "../engine", version = "0.1.3" }
fluence-sdk-main = "=0.2.2" fluence-sdk-main = "=0.2.3"
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }
# dynamicfunc-fat-closures allows using state inside DynamicFunc # dynamicfunc-fat-closures allows using state inside DynamicFunc
wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0", features = ["dynamicfunc-fat-closures"] } wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0", features = ["dynamicfunc-fat-closures"] }
wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.0" } wasmer-wasi = { package = "wasmer-wasi-fl", version = "0.17.0" }
wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.5" }
toml = "0.5.6" toml = "0.5.6"
serde = { version = "1.0.111", features = ["derive"] } serde = { version = "1.0.111", features = ["derive"] }
serde_json = "1.0.53" serde_json = "1.0.53"
serde_derive = "1.0.111" serde_derive = "1.0.111"
itertools = "0.9.0"
cmd_lib = "0.7.8" cmd_lib = "0.7.8"
log = "0.4.8" log = "0.4.8"
safe-transmute = "0.11.0" safe-transmute = "0.11.0"
[dev-dependencies] [dev-dependencies]
wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.0"} wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.5" }
once_cell = "1.4.0"
env_logger = "0.7.1"
[features] [features]
raw-module-api = [] raw-module-api = []

View File

@ -16,6 +16,8 @@
use fce::FCEError; use fce::FCEError;
use serde_json::error::Error as SerdeError;
use std::io::Error as IOError; use std::io::Error as IOError;
use std::error::Error; use std::error::Error;
@ -30,6 +32,18 @@ pub enum FaaSError {
/// Various errors related to file i/o. /// Various errors related to file i/o.
IOError(String), IOError(String),
/// A function with specified name is missing.
MissingFunctionError(String),
/// An argument with specified name is missing.
MissingArgumentError(String),
/// Not enough arguments provided for FCE call.
JsonArgumentsDeserializationError(String),
/// An error occurred when incorrect json argument is supplied.
ArgumentDeserializationError(SerdeError),
/// FCE errors. /// FCE errors.
EngineError(FCEError), EngineError(FCEError),
} }
@ -41,6 +55,14 @@ impl std::fmt::Display for FaaSError {
match self { match self {
FaaSError::ConfigParseError(err_msg) => write!(f, "{}", err_msg), FaaSError::ConfigParseError(err_msg) => write!(f, "{}", err_msg),
FaaSError::InstantiationError(err_msg) => write!(f, "{}", err_msg), FaaSError::InstantiationError(err_msg) => write!(f, "{}", err_msg),
FaaSError::MissingFunctionError(func_name) => {
write!(f, "function with name `{}` is missing", func_name)
}
FaaSError::MissingArgumentError(arg_name) => {
write!(f, "argument with name `{}` is missing", arg_name)
}
FaaSError::JsonArgumentsDeserializationError(args) => write!(f, "{}", args),
FaaSError::ArgumentDeserializationError(err_msg) => write!(f, "{:?}", err_msg),
FaaSError::IOError(err_msg) => write!(f, "{}", err_msg), FaaSError::IOError(err_msg) => write!(f, "{}", err_msg),
FaaSError::EngineError(err) => write!(f, "{}", err), FaaSError::EngineError(err) => write!(f, "{}", err),
} }

View File

@ -15,6 +15,7 @@
*/ */
use crate::misc::ModulesConfig; use crate::misc::ModulesConfig;
use crate::misc::ModulesLoadStrategy;
use crate::faas_interface::FaaSFunctionSignature; use crate::faas_interface::FaaSFunctionSignature;
use crate::faas_interface::FaaSInterface; use crate::faas_interface::FaaSInterface;
use crate::FaaSError; use crate::FaaSError;
@ -31,70 +32,10 @@ use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use std::path::Path;
// TODO: remove and use mutex instead // TODO: remove and use mutex instead
unsafe impl Send for FluenceFaaS {} unsafe impl Send for FluenceFaaS {}
/// Strategies for module loading.
pub enum ModulesLoadStrategy<'a> {
/// Try to load all files in a given directory
#[allow(dead_code)]
All,
/// Try to load only files contained in the set
Named(&'a HashSet<String>),
/// In a given directory, try to load all files ending with .wasm
WasmOnly,
}
impl<'a> ModulesLoadStrategy<'a> {
#[inline]
/// Returns true if `module` should be loaded.
pub fn should_load(&self, module: &Path) -> bool {
match self {
ModulesLoadStrategy::All => true,
ModulesLoadStrategy::Named(set) => set.contains(module.to_string_lossy().as_ref()),
ModulesLoadStrategy::WasmOnly => module.extension().map_or(false, |e| e == "wasm"),
}
}
#[inline]
/// Returns the number of modules that must be loaded.
pub fn required_modules_len(&self) -> usize {
match self {
ModulesLoadStrategy::Named(set) => set.len(),
_ => 0,
}
}
#[inline]
/// Returns difference between required and loaded modules.
pub fn missing_modules<'s>(&self, loaded: impl Iterator<Item = &'s String>) -> Vec<&'s String> {
match self {
ModulesLoadStrategy::Named(set) => loaded.fold(vec![], |mut vec, module| {
if !set.contains(module) {
vec.push(module)
}
vec
}),
_ => <_>::default(),
}
}
#[inline]
pub fn extract_module_name(&self, module: String) -> String {
match self {
ModulesLoadStrategy::WasmOnly => {
let path: &Path = module.as_ref();
path.file_stem()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or(module)
}
_ => module,
}
}
}
pub struct FluenceFaaS { pub struct FluenceFaaS {
/// The Fluence Compute Engine instance. /// The Fluence Compute Engine instance.
fce: FCE, fce: FCE,
@ -223,7 +164,7 @@ impl FluenceFaaS {
} }
/// Call a specified function of loaded on a startup module by its name. /// Call a specified function of loaded on a startup module by its name.
pub fn call<MN: AsRef<str>, FN: AsRef<str>>( pub fn call_with_ivalues<MN: AsRef<str>, FN: AsRef<str>>(
&mut self, &mut self,
module_name: MN, module_name: MN,
func_name: FN, func_name: FN,
@ -237,8 +178,50 @@ impl FluenceFaaS {
.map_err(Into::into) .map_err(Into::into)
} }
/// Call a specified function of loaded on a startup module by its name.
pub fn call_with_json<MN: AsRef<str>, FN: AsRef<str>>(
&mut self,
module_name: MN,
func_name: FN,
json_args: serde_json::Value,
call_parameters: fluence_sdk_main::CallParameters,
) -> Result<Vec<IValue>> {
let module_name = module_name.as_ref();
let func_name = func_name.as_ref();
let iargs = {
let mut func_signatures = self.fce.module_interface(module_name)?;
let func_signature = func_signatures
.find(|sign| sign.name == func_name)
.ok_or_else(|| FaaSError::MissingFunctionError(func_name.to_string()))?;
// TODO: cache record types
let record_types = self
.fce
.module_record_types(module_name)?
.map(|(type_id, record_type)| (type_id, record_type))
.collect::<HashMap<_, _>>();
crate::misc::json_to_ivalues(json_args, &func_signature, &record_types)?
};
self.call_parameters.replace(call_parameters);
self.fce
.call(module_name, func_name, &iargs)
.map_err(Into::into)
}
/// Return all export functions (name and signatures) of loaded modules. /// Return all export functions (name and signatures) of loaded modules.
pub fn get_interface(&self) -> FaaSInterface<'_> { pub fn get_interface(&self) -> FaaSInterface<'_> {
use itertools::Itertools;
let record_types = self
.fce
.record_types()
.map(|(id, record_type)| (*id, record_type))
.unique()
.collect::<HashMap<_, _>>();
let modules = self let modules = self
.fce .fce
.interface() .interface()
@ -249,7 +232,7 @@ impl FluenceFaaS {
( (
f.name, f.name,
FaaSFunctionSignature { FaaSFunctionSignature {
input_types: f.input_types, arguments: f.arguments,
output_types: f.output_types, output_types: f.output_types,
}, },
) )
@ -259,7 +242,10 @@ impl FluenceFaaS {
}) })
.collect(); .collect();
FaaSInterface { modules } FaaSInterface {
record_types,
modules,
}
} }
} }

View File

@ -15,6 +15,8 @@
*/ */
use super::IType; use super::IType;
use super::IRecordType;
use super::IFunctionArg;
use serde::Serialize; use serde::Serialize;
use serde::Serializer; use serde::Serializer;
@ -24,27 +26,63 @@ use std::collections::HashMap;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct FaaSInterface<'a> { pub struct FaaSInterface<'a> {
pub record_types: HashMap<u64, &'a IRecordType>,
pub modules: HashMap<&'a str, HashMap<&'a str, FaaSFunctionSignature<'a>>>, pub modules: HashMap<&'a str, HashMap<&'a str, FaaSFunctionSignature<'a>>>,
} }
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct FaaSFunctionSignature<'a> { pub struct FaaSFunctionSignature<'a> {
pub input_types: &'a Vec<IType>, pub arguments: &'a Vec<IFunctionArg>,
pub output_types: &'a Vec<IType>, pub output_types: &'a Vec<IType>,
} }
impl<'a> fmt::Display for FaaSInterface<'a> { impl<'a> fmt::Display for FaaSInterface<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let type_text_view = |arg_ty: &IType| {
match arg_ty {
IType::Record(record_type_id) => {
// unwrap is safe because FaasInterface here is well-formed
// (it was checked on the module startup stage)
let record = self.record_types.get(record_type_id).unwrap();
record.name.clone()
}
t => format!("{:?}", t),
}
};
for (_, record_type) in self.record_types.iter() {
writeln!(f, "{} {{", record_type.name)?;
for field in record_type.fields.iter() {
writeln!(f, " {}: {:?}", field.name, type_text_view(&field.ty))?;
}
writeln!(f, "}}")?;
}
if !self.record_types.is_empty() {
writeln!(f)?;
}
for (name, functions) in self.modules.iter() { for (name, functions) in self.modules.iter() {
writeln!(f, "{}", *name)?; writeln!(f, "{}:", *name)?;
for (name, signature) in functions.iter() { for (name, signature) in functions.iter() {
writeln!( write!(f, " pub fn {}(", name)?;
f,
" pub fn {}({:?}) -> {:?}", for arg in signature.arguments {
name, signature.input_types, signature.output_types write!(f, "{}: {}", arg.name, type_text_view(&arg.ty))?;
)?; }
if signature.output_types.is_empty() {
write!(f, ")")?;
} else if signature.output_types.len() == 1 {
write!(f, ") -> {}", type_text_view(&signature.output_types[0]))?;
} else {
// At now, multi values aren't supported - only one output type is possible
unimplemented!()
}
} }
writeln!(f)?
} }
Ok(()) Ok(())
@ -59,10 +97,17 @@ impl<'a> Serialize for FaaSInterface<'a> {
#[derive(Serialize)] #[derive(Serialize)]
pub struct Function<'a> { pub struct Function<'a> {
pub name: &'a str, pub name: &'a str,
pub input_types: &'a Vec<IType>, pub arguments: Vec<(&'a String, &'a IType)>,
pub output_types: &'a Vec<IType>, pub output_types: &'a Vec<IType>,
} }
#[derive(Serialize)]
pub struct RecordType<'a> {
pub name: &'a str,
pub id: u64,
pub fields: Vec<(&'a String, &'a IType)>,
}
#[derive(Serialize)] #[derive(Serialize)]
pub struct Module<'a> { pub struct Module<'a> {
pub name: &'a str, pub name: &'a str,
@ -71,9 +116,27 @@ impl<'a> Serialize for FaaSInterface<'a> {
#[derive(Serialize)] #[derive(Serialize)]
pub struct Interface<'a> { pub struct Interface<'a> {
pub record_types: Vec<RecordType<'a>>,
pub modules: Vec<Module<'a>>, pub modules: Vec<Module<'a>>,
} }
let record_types: Vec<_> = self
.record_types
.iter()
.map(|(id, IRecordType { name, fields })| {
let fields = fields
.iter()
.map(|field| (&field.name, &field.ty))
.collect::<Vec<_>>();
RecordType {
name: name.as_str(),
id: *id,
fields,
}
})
.collect();
let modules: Vec<_> = self let modules: Vec<_> = self
.modules .modules
.iter() .iter()
@ -84,13 +147,15 @@ impl<'a> Serialize for FaaSInterface<'a> {
|( |(
name, name,
FaaSFunctionSignature { FaaSFunctionSignature {
input_types, arguments,
output_types, output_types,
}, },
)| { )| {
let arguments =
arguments.iter().map(|arg| (&arg.name, &arg.ty)).collect();
Function { Function {
name, name,
input_types, arguments,
output_types, output_types,
} }
}, },
@ -100,6 +165,10 @@ impl<'a> Serialize for FaaSInterface<'a> {
}) })
.collect(); .collect();
Interface { modules }.serialize(serializer) Interface {
record_types,
modules,
}
.serialize(serializer)
} }
} }

View File

@ -34,6 +34,8 @@ pub(crate) type Result<T> = std::result::Result<T, FaaSError>;
pub use errors::FaaSError; pub use errors::FaaSError;
pub use fce::IValue; pub use fce::IValue;
pub use fce::IRecordType;
pub use fce::IFunctionArg;
pub use fce::IType; pub use fce::IType;
pub use fce::to_interface_value; pub use fce::to_interface_value;
pub use fce::from_interface_values; pub use fce::from_interface_values;

View File

@ -0,0 +1,289 @@
/*
* 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::IValue;
use crate::IType;
use crate::Result;
use crate::FaaSError;
use serde_json::Value as SerdeValue;
use wasmer_wit::vec1::Vec1;
use wasmer_wit::types::RecordType;
use std::collections::HashMap;
pub(crate) fn json_to_ivalues(
json_args: serde_json::Value,
func_signature: &fce::FCEFunctionSignature<'_>,
record_types: &HashMap<&u64, &RecordType>,
) -> Result<Vec<IValue>> {
let ivalues = match json_args {
SerdeValue::Object(json_map) => json_map_to_ivalues(
json_map,
func_signature
.arguments
.iter()
.map(|arg| (&arg.name, &arg.ty)),
&record_types,
)?,
SerdeValue::Array(json_array) => json_array_to_ivalues(
json_array,
func_signature.arguments.iter().map(|arg| &arg.ty),
&record_types,
)?,
SerdeValue::String(json_string) => json_string_to_ivalue(json_string, func_signature)?,
json_bool @ SerdeValue::Bool(_) => json_bool_to_ivalue(json_bool, func_signature)?,
json_number @ SerdeValue::Number(_) => json_number_to_ivalue(json_number, func_signature)?,
SerdeValue::Null => json_null_to_ivalue(func_signature)?,
};
Ok(ivalues)
}
fn json_map_to_ivalues<'a, 'b>(
mut json_map: serde_json::Map<String, SerdeValue>,
signature: impl Iterator<Item = (&'a String, &'a IType)>,
record_types: &'b HashMap<&'b u64, &'b RecordType>,
) -> Result<Vec<IValue>> {
let mut iargs = Vec::new();
for (arg_name, arg_type) in signature {
let json_value = json_map
.remove(arg_name)
.ok_or_else(|| FaaSError::MissingArgumentError(arg_name.clone()))?;
let iarg = json_value_to_ivalue(json_value, arg_type, record_types)?;
iargs.push(iarg);
}
if !json_map.is_empty() {
return Err(FaaSError::JsonArgumentsDeserializationError(format!(
"function requires {} arguments, {} provided",
iargs.len(),
iargs.len() + json_map.len()
)));
}
Ok(iargs)
}
fn json_array_to_ivalues<'a, 'b>(
mut json_array: Vec<SerdeValue>,
signature: impl Iterator<Item = &'a IType> + std::iter::ExactSizeIterator,
record_types: &'b HashMap<&'b u64, &'b RecordType>,
) -> Result<Vec<IValue>> {
if json_array.len() != signature.len() {
return Err(FaaSError::JsonArgumentsDeserializationError(format!(
"function requires {} arguments, {} provided",
signature.len(),
json_array.len()
)));
}
let mut iargs = Vec::with_capacity(signature.len());
for arg_type in signature {
// remove here is safe because we've already checked sizes
let json_value = json_array.remove(0);
let iarg = json_value_to_ivalue(json_value, arg_type, record_types)?;
iargs.push(iarg);
}
Ok(iargs)
}
fn json_string_to_ivalue(
json_string: String,
func_signature: &fce::FCEFunctionSignature<'_>,
) -> Result<Vec<IValue>> {
if func_signature.arguments.len() != 1 || func_signature.arguments[0].ty != IType::String {
return Err(FaaSError::JsonArgumentsDeserializationError(format!(
"the called function has the following signature: {:?}, but only one string argument is provided",
func_signature
)));
}
Ok(vec![IValue::String(json_string)])
}
fn json_bool_to_ivalue(
json_bool: SerdeValue,
func_signature: &fce::FCEFunctionSignature<'_>,
) -> Result<Vec<IValue>> {
if func_signature.arguments.len() != 1 {
return Err(FaaSError::JsonArgumentsDeserializationError(format!(
"the called function has the following signature: {:?}, but only one bool argument is provided",
func_signature
)));
}
Ok(vec![json_value_to_ivalue(
json_bool,
&func_signature.arguments[0].ty,
&HashMap::new(),
)?])
}
fn json_number_to_ivalue(
json_number: SerdeValue,
func_signature: &fce::FCEFunctionSignature<'_>,
) -> Result<Vec<IValue>> {
if func_signature.arguments.len() != 1 {
return Err(FaaSError::JsonArgumentsDeserializationError(format!(
"the called function has the following signature: {:?}, but only one number argument is provided",
func_signature
)));
}
Ok(vec![json_value_to_ivalue(
json_number,
&func_signature.arguments[0].ty,
&HashMap::new(),
)?])
}
fn json_null_to_ivalue(func_signature: &fce::FCEFunctionSignature<'_>) -> Result<Vec<IValue>> {
if !func_signature.arguments.is_empty() {
return Err(FaaSError::JsonArgumentsDeserializationError(format!(
"the called function has the following signature: {:?}, but no arguments is provided",
func_signature
)));
}
Ok(vec![])
}
fn json_value_to_ivalue(
json_value: SerdeValue,
ty: &IType,
record_types: &HashMap<&u64, &RecordType>,
) -> Result<IValue> {
// TODO: get rid of copy-past
match ty {
IType::S8 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::S8(value))
}
IType::S16 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::S16(value))
}
IType::S32 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::S32(value))
}
IType::S64 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::S64(value))
}
IType::U8 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::U8(value))
}
IType::U16 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::U16(value))
}
IType::U32 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::U32(value))
}
IType::U64 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::U64(value))
}
IType::F32 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::F32(value))
}
IType::F64 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::F64(value))
}
IType::String => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::String(value))
}
IType::ByteArray => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::ByteArray(value))
}
IType::I32 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::I32(value))
}
IType::I64 => {
let value = serde_json::from_value(json_value)
.map_err(FaaSError::ArgumentDeserializationError)?;
Ok(IValue::I64(value))
}
IType::Record(record_type_id) => {
let value = json_record_type_to_ivalue(json_value, record_type_id, &record_types)?;
Ok(IValue::Record(value))
}
IType::Anyref => Err(FaaSError::JsonArgumentsDeserializationError(String::from(
"anyref interface-type is unsupported now",
))),
}
}
#[allow(clippy::ptr_arg)]
fn json_record_type_to_ivalue(
json_value: SerdeValue,
record_type_id: &u64,
record_types: &HashMap<&u64, &RecordType>,
) -> Result<Vec1<IValue>> {
let record_type = record_types.get(record_type_id).ok_or_else(|| {
FaaSError::JsonArgumentsDeserializationError(format!(
"record with type id `{}` wasn't found",
record_type_id
))
})?;
match json_value {
SerdeValue::Object(json_map) => Ok(Vec1::new(json_map_to_ivalues(
json_map,
record_type
.fields
.iter()
.map(|field| (&field.name, &field.ty)),
record_types,
)?)
.unwrap()),
SerdeValue::Array(json_array) => Ok(Vec1::new(json_array_to_ivalues(
json_array,
record_type.fields.iter().map(|field| (&field.ty)),
record_types,
)?)
.unwrap()),
_ => Err(FaaSError::JsonArgumentsDeserializationError(format!(
"record with type id `{}` should be encoded as array or map of fields",
record_type_id
))),
}
}

View File

@ -1,12 +1,32 @@
mod imports; /*
mod utils; * Copyright 2020 Fluence Labs Limited
mod config; *
* 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.
*/
pub(crate) use utils::make_fce_config; mod config;
pub(crate) use config::load_config; mod imports;
mod json_to_ivalues;
mod modules_load_strategy;
mod utils;
pub use config::RawModulesConfig; pub use config::RawModulesConfig;
pub use config::RawModuleConfig; pub use config::RawModuleConfig;
pub use config::ModulesConfig; pub use config::ModulesConfig;
pub use config::ModuleConfig; pub use config::ModuleConfig;
pub use config::WASIConfig; pub use config::WASIConfig;
pub(crate) use config::load_config;
pub(crate) use json_to_ivalues::json_to_ivalues;
pub(crate) use modules_load_strategy::ModulesLoadStrategy;
pub(crate) use utils::make_fce_config;

View File

@ -0,0 +1,77 @@
/*
* 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 std::path::Path;
use std::collections::HashSet;
/// Strategies for module loading.
pub enum ModulesLoadStrategy<'a> {
/// Try to load all files in a given directory
#[allow(dead_code)]
All,
/// Try to load only files contained in the set
Named(&'a HashSet<String>),
/// In a given directory, try to load all files ending with .wasm
WasmOnly,
}
impl<'a> ModulesLoadStrategy<'a> {
#[inline]
/// Returns true if `module` should be loaded.
pub fn should_load(&self, module: &Path) -> bool {
match self {
ModulesLoadStrategy::All => true,
ModulesLoadStrategy::Named(set) => set.contains(module.to_string_lossy().as_ref()),
ModulesLoadStrategy::WasmOnly => module.extension().map_or(false, |e| e == "wasm"),
}
}
#[inline]
/// Returns the number of modules that must be loaded.
pub fn required_modules_len(&self) -> usize {
match self {
ModulesLoadStrategy::Named(set) => set.len(),
_ => 0,
}
}
#[inline]
/// Returns difference between required and loaded modules.
pub fn missing_modules<'s>(&self, loaded: impl Iterator<Item = &'s String>) -> Vec<&'s String> {
match self {
ModulesLoadStrategy::Named(set) => loaded.fold(vec![], |mut vec, module| {
if !set.contains(module) {
vec.push(module)
}
vec
}),
_ => <_>::default(),
}
}
#[inline]
pub fn extract_module_name(&self, module: String) -> String {
match self {
ModulesLoadStrategy::WasmOnly => {
let path: &Path = module.as_ref();
path.file_stem()
.map(|s| s.to_string_lossy().to_string())
.unwrap_or(module)
}
_ => module,
}
}
}

View File

@ -0,0 +1,557 @@
/*
* 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 fluence_faas::FluenceFaaS;
use fluence_faas::IValue;
use once_cell::sync::Lazy;
use serde_json::json;
static ARG_CONFIG: Lazy<fluence_faas::RawModulesConfig> = Lazy::new(|| {
let argument_passing_config_raw =
std::fs::read("./tests/json_wasm_tests/arguments_passing/Config.toml")
.expect("../examples/greeting/artifacts/greeting.wasm should presence");
let mut arguments_passing_config: fluence_faas::RawModulesConfig =
toml::from_slice(&argument_passing_config_raw)
.expect("argument passing test config should be well-formed");
arguments_passing_config.modules_dir = Some(String::from(
"./tests/json_wasm_tests/arguments_passing/artifacts",
));
arguments_passing_config
});
#[test]
pub fn get_interfaces() {
let faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let interface = faas.get_interface();
let string_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::String,
}];
let string_type_output_types = vec![fluence_faas::IType::String];
let string_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &string_type_arguments,
output_types: &string_type_output_types,
};
let bytearray_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::ByteArray,
}];
let bytearray_type_output_types = vec![fluence_faas::IType::ByteArray];
let bytearray_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &bytearray_type_arguments,
output_types: &bytearray_type_output_types,
};
let i32_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::S32,
}];
let i32_type_output_types = vec![fluence_faas::IType::S32];
let i32_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &i32_type_arguments,
output_types: &i32_type_output_types,
};
let i64_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::S64,
}];
let i64_type_output_types = vec![fluence_faas::IType::S64];
let i64_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &i64_type_arguments,
output_types: &i64_type_output_types,
};
let u32_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::U32,
}];
let u32_type_output_types = vec![fluence_faas::IType::U32];
let u32_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &u32_type_arguments,
output_types: &u32_type_output_types,
};
let u64_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::U64,
}];
let u64_type_output_types = vec![fluence_faas::IType::U64];
let u64_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &u64_type_arguments,
output_types: &u64_type_output_types,
};
let f32_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::F32,
}];
let f32_type_output_types = vec![fluence_faas::IType::F32];
let f32_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &f32_type_arguments,
output_types: &f32_type_output_types,
};
let f64_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::F64,
}];
let f64_type_output_types = vec![fluence_faas::IType::F64];
let f64_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &f64_type_arguments,
output_types: &f64_type_output_types,
};
let empty_type_arguments = vec![];
let empty_type_output_types = vec![fluence_faas::IType::String];
let empty_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &empty_type_arguments,
output_types: &empty_type_output_types,
};
let bool_type_arguments = vec![fluence_faas::IFunctionArg {
name: String::from("arg"),
ty: fluence_faas::IType::I32,
}];
let bool_type_output_types = vec![fluence_faas::IType::I32];
let bool_type_sign = fluence_faas::FaaSFunctionSignature {
arguments: &bool_type_arguments,
output_types: &bool_type_output_types,
};
let all_types_arguments = vec![
fluence_faas::IFunctionArg {
name: String::from("arg_0"),
ty: fluence_faas::IType::S8,
},
fluence_faas::IFunctionArg {
name: String::from("arg_1"),
ty: fluence_faas::IType::S16,
},
fluence_faas::IFunctionArg {
name: String::from("arg_2"),
ty: fluence_faas::IType::S32,
},
fluence_faas::IFunctionArg {
name: String::from("arg_3"),
ty: fluence_faas::IType::S64,
},
fluence_faas::IFunctionArg {
name: String::from("arg_4"),
ty: fluence_faas::IType::U8,
},
fluence_faas::IFunctionArg {
name: String::from("arg_5"),
ty: fluence_faas::IType::U16,
},
fluence_faas::IFunctionArg {
name: String::from("arg_6"),
ty: fluence_faas::IType::U32,
},
fluence_faas::IFunctionArg {
name: String::from("arg_7"),
ty: fluence_faas::IType::U64,
},
fluence_faas::IFunctionArg {
name: String::from("arg_8"),
ty: fluence_faas::IType::F32,
},
fluence_faas::IFunctionArg {
name: String::from("arg_9"),
ty: fluence_faas::IType::F64,
},
fluence_faas::IFunctionArg {
name: String::from("arg_10"),
ty: fluence_faas::IType::String,
},
fluence_faas::IFunctionArg {
name: String::from("arg_11"),
ty: fluence_faas::IType::ByteArray,
},
];
let all_types_output_types = vec![fluence_faas::IType::ByteArray];
let all_types_sign = fluence_faas::FaaSFunctionSignature {
arguments: &all_types_arguments,
output_types: &all_types_output_types,
};
let mut functions = std::collections::HashMap::new();
functions.insert("string_type", string_type_sign);
functions.insert("bytearray_type", bytearray_type_sign);
functions.insert("i32_type", i32_type_sign);
functions.insert("i64_type", i64_type_sign);
functions.insert("u32_type", u32_type_sign);
functions.insert("u64_type", u64_type_sign);
functions.insert("f32_type", f32_type_sign);
functions.insert("f64_type", f64_type_sign);
functions.insert("empty_type", empty_type_sign);
functions.insert("bool_type", bool_type_sign);
functions.insert("all_types", all_types_sign);
let mut modules = std::collections::HashMap::new();
modules.insert("pure", functions.clone());
modules.insert("effector", functions);
assert_eq!(
interface,
fluence_faas::FaaSInterface {
record_types: <_>::default(),
modules
}
);
}
#[test]
pub fn all_types() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "all_types", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "all_types", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json(
"pure",
"all_types",
json!({
"arg_0": 0,
"arg_1": 1,
"arg_2": 2,
"arg_3": 3,
"arg_4": 4,
"arg_5": 5,
"arg_6": 6,
"arg_7": 7,
"arg_8": 8.1,
"arg_9": 9.1,
"arg_10": "fluence",
"arg_11": vec! [0x13, 0x37],
}),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke all_types: {:?}", e));
assert_eq!(
result3,
vec![IValue::ByteArray(vec![
0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0,
0, 65, 1, 153, 154, 64, 34, 51, 51, 51, 51, 51, 51, 102, 108, 117, 101, 110, 99, 101,
19, 55, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 65, 1, 153, 154, 64, 34, 51, 51, 51, 51, 51, 51, 102, 108, 117, 101, 110,
99, 101, 19, 55
])]
);
let result4 = faas
.call_with_json(
"pure",
"all_types",
json!([
0,
1,
2,
3,
4,
5,
6,
7,
8.1,
9.1,
"fluence",
vec![0x13, 0x37]
]),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke all_types: {:?}", e));
assert_eq!(
result4,
vec![IValue::ByteArray(vec![
0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0,
0, 65, 1, 153, 154, 64, 34, 51, 51, 51, 51, 51, 51, 102, 108, 117, 101, 110, 99, 101,
19, 55, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 6, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 65, 1, 153, 154, 64, 34, 51, 51, 51, 51, 51, 51, 102, 108, 117, 101, 110,
99, 101, 19, 55
])]
);
}
#[test]
pub fn i32_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "i32_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "i32_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json("pure", "i32_type", json!({ "arg": 1 }), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke i32_type: {:?}", e));
assert_eq!(result3, vec![IValue::S32(3)]);
let result4 = faas
.call_with_json("pure", "i32_type", json!(1), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke i32_type: {:?}", e));
assert_eq!(result4, vec![IValue::S32(3)]);
}
#[test]
pub fn i64_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "i64_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "i64_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json("pure", "i64_type", json!({ "arg": 1 }), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke i64_type: {:?}", e));
assert_eq!(result3, vec![IValue::S64(3)]);
let result4 = faas
.call_with_json("pure", "i64_type", json!(1), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke i64_type: {:?}", e));
assert_eq!(result4, vec![IValue::S64(3)]);
}
#[test]
pub fn u32_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "u32_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "u32_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json("pure", "u32_type", json!({ "arg": 1 }), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke u32_type: {:?}", e));
assert_eq!(result3, vec![IValue::U32(3)]);
let result4 = faas
.call_with_json("pure", "u32_type", json!(1), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke u32_type: {:?}", e));
assert_eq!(result4, vec![IValue::U32(3)]);
}
#[test]
pub fn u64_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "u64_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "u64_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json("pure", "u64_type", json!({ "arg": 1 }), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke u64_type: {:?}", e));
assert_eq!(result3, vec![IValue::U64(3)]);
let result4 = faas
.call_with_json("pure", "u64_type", json!(1), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke u64_type: {:?}", e));
assert_eq!(result4, vec![IValue::U64(3)]);
}
#[test]
pub fn f32_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "f32_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "f32_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json("pure", "f32_type", json!({ "arg": 1.0 }), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke f32_type: {:?}", e));
assert_eq!(result3, vec![IValue::F32(3.0)]);
let result4 = faas
.call_with_json("pure", "f32_type", json!(1.0), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke f32_type: {:?}", e));
assert_eq!(result4, vec![IValue::F32(3.0)]);
}
#[test]
pub fn f64_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "f64_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "f64_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json("pure", "f64_type", json!({ "arg": 1.0 }), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke f64_type: {:?}", e));
assert_eq!(result3, vec![IValue::F64(3.0)]);
let result4 = faas
.call_with_json("pure", "f64_type", json!(1.0), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke f64_type: {:?}", e));
assert_eq!(result4, vec![IValue::F64(3.0)]);
}
#[test]
pub fn string_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "string_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "string_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json(
"pure",
"string_type",
json!({ "arg": "Fluence" }),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke string_type: {:?}", e));
assert_eq!(
result3,
vec![IValue::String(String::from(
"Fluence_Fluence_Fluence_Fluence"
))]
);
let result4 = faas
.call_with_json("pure", "string_type", json!("Fluence"), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke string_type: {:?}", e));
assert_eq!(
result4,
vec![IValue::String(String::from(
"Fluence_Fluence_Fluence_Fluence"
))]
);
}
#[test]
pub fn bytearray_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "bytearray_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "bytearray_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json(
"pure",
"bytearray_type",
json!({ "arg": [0x13, 0x37] }),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke bytearray_type: {:?}", e));
assert_eq!(result3, vec![IValue::ByteArray(vec![0x13, 0x37, 0x1, 0x1])]);
let result4 = faas
.call_with_json(
"pure",
"bytearray_type",
json!([[0x13, 0x37]]),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke bytearray_type: {:?}", e));
assert_eq!(result4, vec![IValue::ByteArray(vec![0x13, 0x37, 0x1, 0x1])]);
}
#[test]
pub fn bool_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas.call_with_json("pure", "bool_type", json!({}), <_>::default());
assert!(result1.is_err());
let result2 = faas.call_with_json("pure", "bool_type", json!([]), <_>::default());
assert!(result2.is_err());
let result3 = faas
.call_with_json("pure", "bool_type", json!({ "arg": 0 }), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke bool_type: {:?}", e));
assert_eq!(result3, vec![IValue::I32(1)]);
let result4 = faas
.call_with_json("pure", "bool_type", json!(0), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke bool_type: {:?}", e));
assert_eq!(result4, vec![IValue::I32(1)]);
}
#[test]
pub fn empty_type() {
let mut faas = FluenceFaaS::with_raw_config(ARG_CONFIG.clone())
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas
.call_with_json("pure", "empty_type", json!({}), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke empty_type: {:?}", e));
assert_eq!(result1, vec![IValue::String(String::from("success"))]);
let result2 = faas
.call_with_json("pure", "empty_type", json!([]), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke empty_type: {:?}", e));
assert_eq!(result2, vec![IValue::String(String::from("success"))]);
let result3 = faas
.call_with_json("pure", "empty_type", json!([]), <_>::default())
.unwrap_or_else(|e| panic!("can't invoke empty_type: {:?}", e));
assert_eq!(result3, vec![IValue::String(String::from("success"))]);
let result4 = faas.call_with_json("pure", "empty_type", json!([1]), <_>::default());
assert!(result4.is_err());
}

View File

@ -38,7 +38,7 @@ pub fn call_parameters() {
let application_id = "0x31337"; let application_id = "0x31337";
let result = faas let result = faas
.call( .call_with_ivalues(
"call_parameters", "call_parameters",
"call_parameters", "call_parameters",
&[], &[],

View File

@ -32,7 +32,7 @@ pub fn greeting() {
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e)); .unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result1 = faas let result1 = faas
.call( .call_with_ivalues(
"greeting", "greeting",
"greeting", "greeting",
&[IValue::String(String::from("Fluence"))], &[IValue::String(String::from("Fluence"))],
@ -41,7 +41,7 @@ pub fn greeting() {
.unwrap_or_else(|e| panic!("can't invoke greeting: {:?}", e)); .unwrap_or_else(|e| panic!("can't invoke greeting: {:?}", e));
let result2 = faas let result2 = faas
.call( .call_with_ivalues(
"greeting", "greeting",
"greeting", "greeting",
&[IValue::String(String::from(""))], &[IValue::String(String::from(""))],
@ -69,10 +69,15 @@ pub fn get_interfaces() {
let interface = faas.get_interface(); let interface = faas.get_interface();
let string_type_params = vec![fluence_faas::IType::String]; let arguments = vec![fluence_faas::IFunctionArg {
name: String::from("name"),
ty: fluence_faas::IType::String,
}];
let output_types = vec![fluence_faas::IType::String];
let greeting_sign = fluence_faas::FaaSFunctionSignature { let greeting_sign = fluence_faas::FaaSFunctionSignature {
input_types: &string_type_params, arguments: &arguments,
output_types: &string_type_params, output_types: &output_types,
}; };
let mut functions = std::collections::HashMap::new(); let mut functions = std::collections::HashMap::new();
@ -81,5 +86,11 @@ pub fn get_interfaces() {
let mut modules = std::collections::HashMap::new(); let mut modules = std::collections::HashMap::new();
modules.insert("greeting", functions); modules.insert("greeting", functions);
assert_eq!(interface, fluence_faas::FaaSInterface { modules }); assert_eq!(
interface,
fluence_faas::FaaSInterface {
record_types: <_>::default(),
modules
}
);
} }

View File

@ -0,0 +1,17 @@
[package]
name = "arguments-passing-test"
version = "0.1.0"
authors = ["Fluence Labs"]
edition = "2018"
[[bin]]
name = "pure"
path = "src/pure.rs"
[[bin]]
name = "effector"
path = "src/effector.rs"
[dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk" }
safe-transmute = "0.11.0"

View File

@ -0,0 +1,11 @@
modules_dir = "./artifacts/"
[[module]]
name = "effector"
mem_pages_count = 1
logger_enabled = true
[[module]]
name = "pure"
mem_pages_count = 1
logger_enabled = true

View File

@ -0,0 +1,103 @@
/*
* 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 fluence::fce;
pub fn main() {}
#[fce]
pub fn all_types(
arg_0: i8,
arg_1: i16,
arg_2: i32,
arg_3: i64,
arg_4: u8,
arg_5: u16,
arg_6: u32,
arg_7: u64,
arg_8: f32,
arg_9: f64,
arg_10: String,
arg_11: Vec<u8>,
) -> Vec<u8> {
let mut result = Vec::new();
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 {
format!("{}_{}", arg, arg)
}
#[fce]
pub fn bytearray_type(mut arg: Vec<u8>) -> Vec<u8> {
arg.push(1);
arg
}
#[fce]
pub fn bool_type(arg: bool) -> bool {
!arg
}
#[fce]
pub fn f32_type(arg: f32) -> f32 {
arg + 1.0
}
#[fce]
pub fn f64_type(arg: f64) -> f64 {
arg + 1.0
}
#[fce]
pub fn u32_type(arg: u32) -> u32 {
arg + 1
}
#[fce]
pub fn u64_type(arg: u64) -> u64 {
arg + 1
}
#[fce]
pub fn i32_type(arg: i32) -> i32 {
arg + 1
}
#[fce]
pub fn i64_type(arg: i64) -> i64 {
arg + 1
}
#[fce]
pub fn empty_type() -> String {
String::from("success")
}

View File

@ -0,0 +1,167 @@
/*
* 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 fluence::fce;
pub fn main() {}
#[fce]
pub fn all_types(
arg_0: i8,
arg_1: i16,
arg_2: i32,
arg_3: i64,
arg_4: u8,
arg_5: u16,
arg_6: u32,
arg_7: u64,
arg_8: f32,
arg_9: f64,
arg_10: String,
arg_11: Vec<u8>,
) -> Vec<u8> {
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<u8>) -> Vec<u8> {
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 = "effector")]
extern "C" {
pub fn all_types(
arg_0: i8,
arg_1: i16,
arg_2: i32,
arg_3: i64,
arg_4: u8,
arg_5: u16,
arg_6: u32,
arg_7: u64,
arg_8: f32,
arg_9: f64,
arg_10: String,
arg_11: Vec<u8>,
) -> Vec<u8>;
pub fn string_type(arg: String) -> String;
pub fn bytearray_type(arg: Vec<u8>) -> Vec<u8>;
pub fn bool_type(arg: bool) -> bool;
pub fn f32_type(arg: f32) -> f32;
pub fn f64_type(arg: f64) -> f64;
pub fn u32_type(arg: u32) -> u32;
pub fn u64_type(arg: u64) -> u64;
pub fn i32_type(arg: i32) -> i32;
pub fn i64_type(arg: i64) -> i64;
pub fn empty_type() -> String;
}
}

View File

@ -0,0 +1,13 @@
[package]
name = "inner-records-test"
version = "0.1.0"
authors = ["Fluence Labs"]
edition = "2018"
[[bin]]
name = "inner_records_pure"
path = "src/pure.rs"
[dependencies]
fluence = { git = "https://github.com/fluencelabs/rust-sdk" }
safe-transmute = "0.11.0"

View File

@ -0,0 +1,6 @@
modules_dir = "./artifacts/"
[[module]]
name = "inner_records_pure"
mem_pages_count = 1
logger_enabled = true

View File

@ -0,0 +1,45 @@
/*
* 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 fluence::fce;
#[fce]
pub struct TestRecord0 {
pub field_0: i32,
}
#[fce]
pub struct TestRecord1 {
pub field_0: i32,
pub field_1: String,
pub field_2: Vec<u8>,
pub test_record_0: TestRecord0,
}
#[fce]
pub struct TestRecord2 {
pub test_record_0: TestRecord0,
pub test_record_1: TestRecord1,
}
fn main() {}
#[fce]
fn test_record(mut test_record: TestRecord2) -> TestRecord2 {
test_record.test_record_0 = TestRecord0 { field_0: 1 };
test_record
}

View File

@ -17,8 +17,9 @@
use fluence_faas::FluenceFaaS; use fluence_faas::FluenceFaaS;
use fluence_faas::IValue; use fluence_faas::IValue;
use serde_json::json;
#[test] #[test]
#[ignore]
pub fn records() { pub fn records() {
let records_config_path = "../examples/records/Config.toml"; let records_config_path = "../examples/records/Config.toml";
@ -27,17 +28,176 @@ pub fn records() {
let mut records_config: fluence_faas::RawModulesConfig = let mut records_config: fluence_faas::RawModulesConfig =
toml::from_slice(&records_config_raw).expect("records config should be well-formed"); toml::from_slice(&records_config_raw).expect("records config should be well-formed");
records_config.modules_dir = Some(String::from("../examples/records/artifacts/wasm_modules/")); records_config.modules_dir = Some(String::from("../examples/records/artifacts/"));
let mut faas = FluenceFaaS::with_raw_config(records_config) let mut faas = FluenceFaaS::with_raw_config(records_config)
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e)); .unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result = faas let result1 = faas
.call("pure", "invoke", &[], <_>::default()) .call_with_ivalues("records_pure", "invoke", &[], <_>::default())
.unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e)); .unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e));
assert_eq!( assert_eq!(
result, result1,
vec![IValue::Record(
wasmer_wit::vec1::Vec1::new(vec![
IValue::I32(1),
IValue::S8(1),
IValue::S16(2),
IValue::S32(3),
IValue::S64(4),
IValue::U8(5),
IValue::U16(6),
IValue::U32(7),
IValue::U64(8),
IValue::F32(9.0),
IValue::F64(10.0),
IValue::String(String::from("field_11")),
IValue::ByteArray(vec![0x13, 0x37])
])
.unwrap()
)]
);
let result2 = faas
.call_with_json(
"records_effector",
"mutate_struct",
json!({
"test_record": {
"field_0": 0,
"field_1": 0,
"field_2": 0,
"field_3": 0,
"field_4": 0,
"field_5": 0,
"field_6": 0,
"field_7": 0,
"field_8": 0,
"field_9": 0,
"field_10": 0,
"field_11": "field",
"field_12": vec![1],
}
}),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e));
assert_eq!(
result2,
vec![IValue::Record(
wasmer_wit::vec1::Vec1::new(vec![
IValue::I32(1),
IValue::S8(1),
IValue::S16(2),
IValue::S32(3),
IValue::S64(4),
IValue::U8(5),
IValue::U16(6),
IValue::U32(7),
IValue::U64(8),
IValue::F32(9.0),
IValue::F64(10.0),
IValue::String(String::from("field_11")),
IValue::ByteArray(vec![0x13, 0x37])
])
.unwrap()
)]
);
let result3 = faas
.call_with_json(
"records_effector",
"mutate_struct",
json!({
"test_record": [0,0,0,0,0,0,0,0,0,0,0,"",[1]]
}),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e));
assert_eq!(
result3,
vec![IValue::Record(
wasmer_wit::vec1::Vec1::new(vec![
IValue::I32(1),
IValue::S8(1),
IValue::S16(2),
IValue::S32(3),
IValue::S64(4),
IValue::U8(5),
IValue::U16(6),
IValue::U32(7),
IValue::U64(8),
IValue::F32(9.0),
IValue::F64(10.0),
IValue::String(String::from("field_11")),
IValue::ByteArray(vec![0x13, 0x37])
])
.unwrap()
)]
);
let result4 = faas
.call_with_json(
"records_effector",
"mutate_struct",
json!([{
"field_0": 0,
"field_1": 0,
"field_2": 0,
"field_3": 0,
"field_4": 0,
"field_5": 0,
"field_6": 0,
"field_7": 0,
"field_8": 0,
"field_9": 0,
"field_10": 0,
"field_11": "",
"field_12": vec![1],
}
]),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e));
assert_eq!(
result4,
vec![IValue::Record(
wasmer_wit::vec1::Vec1::new(vec![
IValue::I32(1),
IValue::S8(1),
IValue::S16(2),
IValue::S32(3),
IValue::S64(4),
IValue::U8(5),
IValue::U16(6),
IValue::U32(7),
IValue::U64(8),
IValue::F32(9.0),
IValue::F64(10.0),
IValue::String(String::from("field_11")),
IValue::ByteArray(vec![0x13, 0x37])
])
.unwrap()
)]
);
let result5 = faas
.call_with_json(
"records_effector",
"mutate_struct",
json!([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", [1]]]),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke pure: {:?}", e));
assert_eq!(
result5,
vec![IValue::Record( vec![IValue::Record(
wasmer_wit::vec1::Vec1::new(vec![ wasmer_wit::vec1::Vec1::new(vec![
IValue::I32(1), IValue::I32(1),
@ -58,3 +218,63 @@ pub fn records() {
)] )]
); );
} }
#[test]
fn inner_records() {
let inner_records_config_raw =
std::fs::read("./tests/json_wasm_tests/inner_records/Config.toml")
.expect("../examples/greeting/artifacts/greeting.wasm should presence");
let mut inner_records_config: fluence_faas::RawModulesConfig =
toml::from_slice(&inner_records_config_raw)
.expect("argument passing test config should be well-formed");
inner_records_config.modules_dir = Some(String::from(
"./tests/json_wasm_tests/inner_records/artifacts",
));
let mut faas = FluenceFaaS::with_raw_config(inner_records_config)
.unwrap_or_else(|e| panic!("can't create Fluence FaaS instance: {:?}", e));
let result = faas
.call_with_json(
"inner_records_pure",
"test_record",
json!({
"test_record": {
"test_record_0": {
"field_0": 0
},
"test_record_1": {
"field_0": 1,
"field_1": "",
"field_2": vec![1],
"test_record_0": {
"field_0": 1
}
}
}
}),
<_>::default(),
)
.unwrap_or_else(|e| panic!("can't invoke inner_records_pure: {:?}", e));
assert_eq!(
result,
vec![IValue::Record(
wasmer_wit::vec1::Vec1::new(vec![
IValue::Record(wasmer_wit::vec1::Vec1::new(vec![IValue::S32(1),]).unwrap()),
IValue::Record(
wasmer_wit::vec1::Vec1::new(vec![
IValue::S32(1),
IValue::String(String::new()),
IValue::ByteArray(vec![1]),
IValue::Record(wasmer_wit::vec1::Vec1::new(vec![IValue::S32(1),]).unwrap())
])
.unwrap()
),
])
.unwrap()
)]
);
}

View File

@ -142,7 +142,7 @@ impl REPL {
} }
Some("interface") => { Some("interface") => {
let interface = self.app_service.get_interface(); let interface = self.app_service.get_interface();
println!("application service interface:\n{}", interface); println!("Application service interface:\n\n{}", interface);
} }
Some("h") | Some("help") | None => { Some("h") | Some("help") | None => {
println!( println!(