Print Aqua-compatible types (#86)

This commit is contained in:
Mike Voronov 2021-05-20 20:20:57 +03:00 committed by GitHub
parent c51b5982d6
commit c62a278897
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1155 additions and 583 deletions

171
Cargo.lock generated
View File

@ -2,6 +2,16 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "Inflector"
version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
dependencies = [
"lazy_static",
"regex",
]
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.15.1" version = "0.15.1"
@ -713,6 +723,8 @@ dependencies = [
[[package]] [[package]]
name = "fluence-app-service" name = "fluence-app-service"
version = "0.7.2" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3b1d2c199d6bc140c9ec5ffa323ebd34ac134fb37828bbfd7aeed0339cab78"
dependencies = [ dependencies = [
"fluence-faas 0.7.2", "fluence-faas 0.7.2",
"log", "log",
@ -726,11 +738,9 @@ dependencies = [
[[package]] [[package]]
name = "fluence-app-service" name = "fluence-app-service"
version = "0.7.2" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3b1d2c199d6bc140c9ec5ffa323ebd34ac134fb37828bbfd7aeed0339cab78"
dependencies = [ dependencies = [
"fluence-faas 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "fluence-faas 0.7.3",
"log", "log",
"maplit", "maplit",
"serde", "serde",
@ -740,32 +750,6 @@ dependencies = [
"wasmer-wasi-fl", "wasmer-wasi-fl",
] ]
[[package]]
name = "fluence-faas"
version = "0.7.2"
dependencies = [
"cmd_lib",
"env_logger 0.7.1",
"fluence",
"fluence-sdk-main",
"itertools 0.9.0",
"log",
"marine-runtime 0.5.0",
"marine-utils 0.2.0",
"once_cell",
"pretty_assertions",
"safe-transmute",
"serde",
"serde_derive",
"serde_json",
"thiserror",
"toml",
"wasmer-interface-types-fl",
"wasmer-runtime-core-fl",
"wasmer-runtime-fl",
"wasmer-wasi-fl",
]
[[package]] [[package]]
name = "fluence-faas" name = "fluence-faas"
version = "0.7.2" version = "0.7.2"
@ -791,6 +775,33 @@ dependencies = [
"wasmer-wasi-fl", "wasmer-wasi-fl",
] ]
[[package]]
name = "fluence-faas"
version = "0.7.3"
dependencies = [
"cmd_lib",
"env_logger 0.7.1",
"fluence",
"fluence-sdk-main",
"itertools 0.9.0",
"log",
"marine-module-interface",
"marine-runtime 0.5.0",
"marine-utils 0.2.0",
"once_cell",
"pretty_assertions",
"safe-transmute",
"serde",
"serde_derive",
"serde_json",
"thiserror",
"toml",
"wasmer-interface-types-fl",
"wasmer-runtime-core-fl",
"wasmer-runtime-fl",
"wasmer-wasi-fl",
]
[[package]] [[package]]
name = "fluence-it-types" name = "fluence-it-types"
version = "0.3.0" version = "0.3.0"
@ -830,11 +841,11 @@ dependencies = [
[[package]] [[package]]
name = "fluence-test" name = "fluence-test"
version = "0.1.7" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7be0d7928e5e6a74a8e303b7f539116fdb4043f5788f78e9eaf32c53700c4c18" checksum = "886ac15e0e95754d5d9339b541a5119dc47cc1a8d80101dc4e3e238d06a4b28b"
dependencies = [ dependencies = [
"fluence-app-service 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "fluence-app-service 0.7.2",
"marine-test-macro", "marine-test-macro",
"serde", "serde",
"serde_json", "serde_json",
@ -994,9 +1005,9 @@ dependencies = [
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
@ -1064,8 +1075,8 @@ dependencies = [
"http", "http",
"indexmap", "indexmap",
"slab", "slab",
"tokio 1.5.0", "tokio 1.6.0",
"tokio-util 0.6.6", "tokio-util 0.6.7",
"tracing", "tracing",
] ]
@ -1200,7 +1211,7 @@ dependencies = [
"itoa", "itoa",
"pin-project", "pin-project",
"socket2 0.4.0", "socket2 0.4.0",
"tokio 1.5.0", "tokio 1.6.0",
"tower-service", "tower-service",
"tracing", "tracing",
"want", "want",
@ -1228,7 +1239,7 @@ dependencies = [
"bytes 1.0.1", "bytes 1.0.1",
"hyper 0.14.7", "hyper 0.14.7",
"native-tls", "native-tls",
"tokio 1.5.0", "tokio 1.6.0",
"tokio-native-tls", "tokio-native-tls",
] ]
@ -1446,14 +1457,15 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]] [[package]]
name = "marine" name = "marine"
version = "0.6.1" version = "0.6.3"
dependencies = [ dependencies = [
"Inflector",
"anyhow", "anyhow",
"check-latest", "check-latest",
"clap", "clap",
"exitfailure", "exitfailure",
"marine-it-generator 0.5.1", "marine-it-generator 0.5.2",
"marine-it-parser 0.6.0", "marine-it-parser 0.6.1",
"marine-module-info-parser 0.1.0", "marine-module-info-parser 0.1.0",
"semver 0.11.0", "semver 0.11.0",
"serde", "serde",
@ -1483,11 +1495,11 @@ dependencies = [
[[package]] [[package]]
name = "marine-it-generator" name = "marine-it-generator"
version = "0.5.1" version = "0.5.2"
dependencies = [ dependencies = [
"cargo_toml", "cargo_toml",
"it-lilo", "it-lilo",
"marine-it-parser 0.6.0", "marine-it-parser 0.6.1",
"marine-macro-impl", "marine-macro-impl",
"once_cell", "once_cell",
"serde", "serde",
@ -1534,10 +1546,12 @@ dependencies = [
[[package]] [[package]]
name = "marine-it-parser" name = "marine-it-parser"
version = "0.6.0" version = "0.6.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"itertools 0.10.0",
"marine-it-interfaces 0.4.0", "marine-it-interfaces 0.4.0",
"marine-module-interface",
"nom", "nom",
"semver 0.11.0", "semver 0.11.0",
"serde", "serde",
@ -1600,6 +1614,22 @@ dependencies = [
"wasmer-runtime-core-fl", "wasmer-runtime-core-fl",
] ]
[[package]]
name = "marine-module-interface"
version = "0.1.0"
dependencies = [
"anyhow",
"itertools 0.10.0",
"marine-it-interfaces 0.4.0",
"nom",
"semver 0.11.0",
"serde",
"thiserror",
"walrus",
"wasmer-interface-types-fl",
"wasmer-runtime-core-fl",
]
[[package]] [[package]]
name = "marine-runtime" name = "marine-runtime"
version = "0.5.0" version = "0.5.0"
@ -1609,10 +1639,11 @@ dependencies = [
"bytes 0.5.6", "bytes 0.5.6",
"it-lilo", "it-lilo",
"log", "log",
"marine-it-generator 0.5.1", "marine-it-generator 0.5.2",
"marine-it-interfaces 0.4.0", "marine-it-interfaces 0.4.0",
"marine-it-parser 0.6.0", "marine-it-parser 0.6.1",
"marine-module-info-parser 0.1.0", "marine-module-info-parser 0.1.0",
"marine-module-interface",
"marine-utils 0.2.0", "marine-utils 0.2.0",
"multimap", "multimap",
"once_cell", "once_cell",
@ -1670,9 +1701,9 @@ dependencies = [
[[package]] [[package]]
name = "marine-test-macro" name = "marine-test-macro"
version = "0.1.6" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "709eebc4ee6c8e6aa49066ab066c9f137d9cf164f298f578a67bfb11a0508f65" checksum = "089a1d98ebee2fa24928e23019b477222562beda663f8625d3d490dce290e532"
dependencies = [ dependencies = [
"marine-test-macro-impl", "marine-test-macro-impl",
"proc-macro-error", "proc-macro-error",
@ -1683,12 +1714,12 @@ dependencies = [
[[package]] [[package]]
name = "marine-test-macro-impl" name = "marine-test-macro-impl"
version = "0.1.5" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2432fd5233a088981c79324668b76f3ee2ae6d313d4522b5490226e5e7827ce" checksum = "b6e79cfbde74677cbeb60fe5944c345617739aae37dc5ac5ef5f12d487472071"
dependencies = [ dependencies = [
"darling 0.12.4", "darling 0.12.4",
"fluence-app-service 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "fluence-app-service 0.7.2",
"marine-it-parser 0.5.0", "marine-it-parser 0.5.0",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
@ -1829,13 +1860,13 @@ dependencies = [
[[package]] [[package]]
name = "mrepl" name = "mrepl"
version = "0.7.2" version = "0.7.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"check-latest", "check-latest",
"clap", "clap",
"env_logger 0.7.1", "env_logger 0.7.1",
"fluence-app-service 0.7.2", "fluence-app-service 0.7.3",
"fluence-sdk-main", "fluence-sdk-main",
"itertools 0.9.0", "itertools 0.9.0",
"log", "log",
@ -2181,9 +2212,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.26" version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
dependencies = [ dependencies = [
"unicode-xid", "unicode-xid",
] ]
@ -2242,7 +2273,7 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
dependencies = [ dependencies = [
"getrandom 0.2.2", "getrandom 0.2.3",
] ]
[[package]] [[package]]
@ -2267,9 +2298,9 @@ dependencies = [
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.5.0" version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"crossbeam-deque", "crossbeam-deque",
@ -2279,9 +2310,9 @@ dependencies = [
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.9.0" version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"crossbeam-deque", "crossbeam-deque",
@ -2355,7 +2386,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [ dependencies = [
"getrandom 0.2.2", "getrandom 0.2.3",
"redox_syscall 0.2.8", "redox_syscall 0.2.8",
] ]
@ -2446,7 +2477,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"tokio 1.5.0", "tokio 1.6.0",
"tokio-native-tls", "tokio-native-tls",
"url", "url",
"wasm-bindgen", "wasm-bindgen",
@ -2934,9 +2965,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.5.0" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5" checksum = "bd3076b5c8cc18138b8f8814895c11eb4de37114a5d127bafdc5e55798ceef37"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes 1.0.1", "bytes 1.0.1",
@ -2965,7 +2996,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
dependencies = [ dependencies = [
"native-tls", "native-tls",
"tokio 1.5.0", "tokio 1.6.0",
] ]
[[package]] [[package]]
@ -2994,16 +3025,16 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.6.6" version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "940a12c99365c31ea8dd9ba04ec1be183ffe4920102bb7122c2f515437601e8e" checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592"
dependencies = [ dependencies = [
"bytes 1.0.1", "bytes 1.0.1",
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"log", "log",
"pin-project-lite 0.2.6", "pin-project-lite 0.2.6",
"tokio 1.5.0", "tokio 1.6.0",
] ]
[[package]] [[package]]
@ -3183,7 +3214,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [ dependencies = [
"getrandom 0.2.2", "getrandom 0.2.3",
] ]
[[package]] [[package]]

View File

@ -4,6 +4,7 @@ members = [
"crates/it-interfaces", "crates/it-interfaces",
"crates/it-parser", "crates/it-parser",
"crates/module-info-parser", "crates/module-info-parser",
"crates/module-interface",
"crates/utils", "crates/utils",
"examples/call_parameters", "examples/call_parameters",
"examples/greeting", "examples/greeting",

View File

@ -148,7 +148,7 @@ fn generate_it_instructions<'f>(
Ok(()) Ok(())
} }
pub(crate) fn generate_raw_args<'f>(signature: &FnSignature) -> Rc<Vec<IFunctionArg>> { pub(crate) fn generate_raw_args(signature: &FnSignature) -> Rc<Vec<IFunctionArg>> {
let raw_inputs = signature let raw_inputs = signature
.arguments .arguments
.iter() .iter()
@ -159,7 +159,7 @@ pub(crate) fn generate_raw_args<'f>(signature: &FnSignature) -> Rc<Vec<IFunction
Rc::new(raw_inputs) Rc::new(raw_inputs)
} }
pub(crate) fn generate_raw_output_type<'f>(signature: &FnSignature) -> Rc<Vec<IType>> { pub(crate) fn generate_raw_output_type(signature: &FnSignature) -> Rc<Vec<IType>> {
let raw_outputs = signature let raw_outputs = signature
.output_types .output_types
.iter() .iter()

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine-it-parser" name = "marine-it-parser"
description = "Fluence Marine interface types parser" description = "Fluence Marine interface types parser"
version = "0.6.0" version = "0.6.1"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
@ -12,6 +12,7 @@ path = "src/lib.rs"
[dependencies] [dependencies]
marine-it-interfaces = { path = "../it-interfaces", version = "0.4.0" } marine-it-interfaces = { path = "../it-interfaces", version = "0.4.0" }
marine-module-interface = { path = "../module-interface", version = "0.1.0" }
anyhow = "1.0.31" anyhow = "1.0.31"
walrus = "0.18.0" walrus = "0.18.0"
@ -19,6 +20,7 @@ wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0"}
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.0" } wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.0" }
nom = "5.1" nom = "5.1"
itertools = "0.10.0"
semver = "0.11.0" semver = "0.11.0"
serde = "=1.0.118" serde = "=1.0.118"
thiserror = "1.0.24" thiserror = "1.0.24"

View File

@ -16,7 +16,7 @@
use super::custom::ITCustomSection; use super::custom::ITCustomSection;
use super::errors::ITParserError; use super::errors::ITParserError;
use crate::Result; use crate::ParserResult;
use walrus::ModuleConfig; use walrus::ModuleConfig;
use wasmer_it::{ use wasmer_it::{
@ -28,7 +28,7 @@ use wasmer_it::ToBytes;
use std::path::Path; use std::path::Path;
/// Embed provided IT to a Wasm file by path. /// Embed provided IT to a Wasm file by path.
pub fn embed_text_it<I, O>(in_wasm_path: I, out_wasm_path: O, it: &str) -> Result<()> pub fn embed_text_it<I, O>(in_wasm_path: I, out_wasm_path: O, it: &str) -> ParserResult<()>
where where
I: AsRef<Path>, I: AsRef<Path>,
O: AsRef<Path>, O: AsRef<Path>,

View File

@ -14,6 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
use marine_module_interface::interface::InterfaceError;
use marine_module_interface::it_interface::ITInterfaceError;
use wasmer_it::decoders::wat::Error as WATError; use wasmer_it::decoders::wat::Error as WATError;
use thiserror::Error as ThisError; use thiserror::Error as ThisError;
@ -45,6 +48,14 @@ pub enum ITParserError {
#[error("{0}")] #[error("{0}")]
IncorrectITFormat(String), IncorrectITFormat(String),
/// An error occurred while processing module interface.
#[error("{0}")]
ModuleInterfaceError(#[from] InterfaceError),
/// An error occurred while processing module IT interface.
#[error("{0}")]
ModuleITInterfaceError(#[from] ITInterfaceError),
/// An error occurred while parsing file in Wat format. /// An error occurred while parsing file in Wat format.
#[error("provided file with IT definitions is corrupted: {0}")] #[error("provided file with IT definitions is corrupted: {0}")]
CorruptedITFile(#[from] WATError), CorruptedITFile(#[from] WATError),

View File

@ -14,38 +14,41 @@
* limitations under the License. * limitations under the License.
*/ */
mod functions;
mod it; mod it;
pub use functions::*;
pub use it::*; pub use it::*;
use crate::Result; use crate::interface::ModuleInterface;
use crate::it_interface::IModuleInterface;
use crate::ParserResult;
use crate::ITParserError; use crate::ITParserError;
use marine_module_interface::it_interface;
use marine_module_interface::interface;
use marine_it_interfaces::MITInterfaces; use marine_it_interfaces::MITInterfaces;
use std::path::Path; use std::path::Path;
pub fn module_interface<P>(module_path: P) -> Result<ServiceInterface> pub fn module_interface<P>(module_path: P) -> ParserResult<ModuleInterface>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
create_mit_with(module_path, |it| get_interface(&it)) create_mit_with(module_path, |it| interface::get_interface(&it))
} }
pub fn module_raw_interface<P>(module_path: P) -> Result<MModuleInterface> pub fn module_it_interface<P>(module_path: P) -> ParserResult<IModuleInterface>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
create_mit_with(module_path, |it| get_raw_interface(&it)) create_mit_with(module_path, |it| it_interface::get_interface(&it))
} }
fn create_mit_with<P, T>( fn create_mit_with<P, T, E>(
module_path: P, module_path: P,
transformer: impl FnOnce(MITInterfaces<'_>) -> Result<T>, transformer: impl FnOnce(MITInterfaces<'_>) -> std::result::Result<T, E>,
) -> Result<T> ) -> ParserResult<T>
where where
P: AsRef<Path>, P: AsRef<Path>,
ITParserError: From<E>,
{ {
let module = walrus::ModuleConfig::new() let module = walrus::ModuleConfig::new()
.parse_file(module_path) .parse_file(module_path)
@ -56,5 +59,5 @@ where
let mit = MITInterfaces::new(it); let mit = MITInterfaces::new(it);
transformer(mit) transformer(mit).map_err(Into::into)
} }

View File

@ -1,213 +0,0 @@
/*
* Copyright 2020 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::Result;
use crate::ITParserError;
use marine_it_interfaces::MITInterfaces;
use wasmer_it::IRecordType;
use wasmer_it::ast::FunctionArg as IFunctionArg;
use wasmer_it::IType;
use serde::Serialize;
use serde::Deserialize;
use std::collections::HashMap;
use std::rc::Rc;
pub type MRecordTypes = HashMap<u64, Rc<IRecordType>>;
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct MFunctionSignature {
pub name: Rc<String>,
pub arguments: Rc<Vec<IFunctionArg>>,
pub outputs: Rc<Vec<IType>>,
}
#[derive(PartialEq, Eq, Debug, Clone, Serialize)]
pub struct MModuleInterface {
pub record_types: MRecordTypes,
pub function_signatures: Vec<MFunctionSignature>,
}
pub fn get_interface(mit: &MITInterfaces<'_>) -> Result<ServiceInterface> {
let marine_interface = get_raw_interface(mit)?;
let service_interface = into_service_interface(marine_interface);
Ok(service_interface)
}
pub fn get_raw_interface(mit: &MITInterfaces<'_>) -> Result<MModuleInterface> {
let function_signatures = get_exports(mit)?;
let record_types = extract_record_types(mit);
let mm_interface = MModuleInterface {
record_types,
function_signatures,
};
Ok(mm_interface)
}
fn get_exports(it: &MITInterfaces<'_>) -> Result<Vec<MFunctionSignature>> {
use marine_it_interfaces::ITAstType;
it.implementations()
.filter_map(|(adapter_function_type, core_function_type)| {
it.exports_by_type(*core_function_type)
.map(|export_function_name| (adapter_function_type, export_function_name))
})
.map(|(adapter_function_type, export_function_names)| {
export_function_names
.iter()
.map(move |export_function_name| (*adapter_function_type, export_function_name))
})
.flatten()
.map(|(adapter_function_type, export_function_name)| {
let it_type = it.type_by_idx_r(adapter_function_type).unwrap();
match it_type {
ITAstType::Function {
arguments,
output_types,
} => {
let signature = MFunctionSignature {
name: Rc::new(export_function_name.to_string()),
arguments: arguments.clone(),
outputs: output_types.clone(),
};
Ok(signature)
}
_ => Err(ITParserError::IncorrectITFormat(format!(
"type with idx = {} isn't a function type",
adapter_function_type
))),
}
})
.collect::<Result<Vec<MFunctionSignature>>>()
}
fn extract_record_types(it: &MITInterfaces<'_>) -> MRecordTypes {
use marine_it_interfaces::ITAstType;
let (record_types_by_id, _) = it.types().fold(
(HashMap::new(), 0u64),
|(mut record_types_by_id, id), ty| {
match ty {
ITAstType::Record(record_type) => {
record_types_by_id.insert(id, record_type.clone());
}
ITAstType::Function { .. } => {}
};
(record_types_by_id, id + 1)
},
);
record_types_by_id
}
#[derive(Serialize)]
pub struct FunctionSignature {
pub name: String,
pub arguments: Vec<(String, String)>,
pub output_types: Vec<String>,
}
#[derive(Serialize)]
pub struct RecordType {
pub name: String,
pub id: u64,
pub fields: Vec<(String, String)>,
}
#[derive(Serialize)]
pub struct ServiceInterface {
pub function_signatures: Vec<FunctionSignature>,
pub record_types: Vec<RecordType>,
}
pub(crate) fn into_service_interface(mm_interface: MModuleInterface) -> ServiceInterface {
let record_types = mm_interface.record_types;
let function_signatures = mm_interface
.function_signatures
.into_iter()
.map(|sign| serialize_function_signature(sign, &record_types))
.collect();
let record_types = record_types
.iter()
.map(|(id, record)| serialize_record_type(*id, record.clone(), &record_types))
.collect::<Vec<_>>();
ServiceInterface {
function_signatures,
record_types,
}
}
fn serialize_function_signature(
signature: MFunctionSignature,
record_types: &MRecordTypes,
) -> FunctionSignature {
let arguments = signature
.arguments
.iter()
.map(|arg| (arg.name.clone(), itype_text_view(&arg.ty, record_types)))
.collect();
let output_types = signature
.outputs
.iter()
.map(|itype| itype_text_view(itype, record_types))
.collect();
FunctionSignature {
name: signature.name.to_string(),
arguments,
output_types,
}
}
fn serialize_record_type(
id: u64,
record: Rc<IRecordType>,
record_types: &MRecordTypes,
) -> RecordType {
let fields = record
.fields
.iter()
.map(|field| (field.name.clone(), itype_text_view(&field.ty, record_types)))
.collect::<Vec<_>>();
RecordType {
name: record.name.clone(),
id,
fields,
}
}
fn itype_text_view(arg_ty: &IType, record_types: &MRecordTypes) -> String {
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 = record_types.get(record_type_id).unwrap();
record.name.clone()
}
IType::Array(array_ty) => format!("Array<{}>", itype_text_view(array_ty, record_types)),
t => format!("{:?}", t),
}
}

View File

@ -16,7 +16,7 @@
use crate::custom::IT_SECTION_NAME; use crate::custom::IT_SECTION_NAME;
use crate::errors::ITParserError; use crate::errors::ITParserError;
use crate::Result; use crate::ParserResult;
use walrus::IdsToIndices; use walrus::IdsToIndices;
use wasmer_it::ast::Interfaces; use wasmer_it::ast::Interfaces;
@ -26,7 +26,7 @@ use std::borrow::Cow;
use std::path::Path; use std::path::Path;
/// Extracts IT section of provided Wasm binary and converts it to a string. /// Extracts IT section of provided Wasm binary and converts it to a string.
pub fn extract_text_it<P>(wasm_file_path: P) -> Result<String> pub fn extract_text_it<P>(wasm_file_path: P) -> ParserResult<String>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
@ -42,7 +42,7 @@ where
} }
/// Extracts IT section of provided Wasm binary and converts it to a MITInterfaces. /// Extracts IT section of provided Wasm binary and converts it to a MITInterfaces.
pub fn extract_it_from_module(wasmer_module: &WasmerModule) -> Result<Interfaces<'_>> { pub fn extract_it_from_module(wasmer_module: &WasmerModule) -> ParserResult<Interfaces<'_>> {
let wit_sections = wasmer_module let wit_sections = wasmer_module
.custom_sections(IT_SECTION_NAME) .custom_sections(IT_SECTION_NAME)
.ok_or(ITParserError::NoITSection)?; .ok_or(ITParserError::NoITSection)?;
@ -54,7 +54,7 @@ pub fn extract_it_from_module(wasmer_module: &WasmerModule) -> Result<Interfaces
extract_it_from_bytes(&wit_sections[0]) extract_it_from_bytes(&wit_sections[0])
} }
pub fn extract_version_from_module(module: &walrus::Module) -> Result<semver::Version> { pub fn extract_version_from_module(module: &walrus::Module) -> ParserResult<semver::Version> {
let raw_custom_section = extract_custom_section(&module)?; let raw_custom_section = extract_custom_section(&module)?;
let wit_section_bytes = raw_custom_section.as_ref(); let wit_section_bytes = raw_custom_section.as_ref();
let it = extract_it_from_bytes(wit_section_bytes)?; let it = extract_it_from_bytes(wit_section_bytes)?;
@ -62,7 +62,7 @@ pub fn extract_version_from_module(module: &walrus::Module) -> Result<semver::Ve
Ok(it.version) Ok(it.version)
} }
pub(crate) fn extract_it_from_bytes(wit_section_bytes: &[u8]) -> Result<Interfaces<'_>> { pub(crate) fn extract_it_from_bytes(wit_section_bytes: &[u8]) -> ParserResult<Interfaces<'_>> {
match wasmer_it::decoders::binary::parse::<(&[u8], nom::error::ErrorKind)>(wit_section_bytes) { match wasmer_it::decoders::binary::parse::<(&[u8], nom::error::ErrorKind)>(wit_section_bytes) {
Ok((remainder, it)) if remainder.is_empty() => Ok(it), Ok((remainder, it)) if remainder.is_empty() => Ok(it),
Ok(_) => Err(ITParserError::ITRemainderNotEmpty), Ok(_) => Err(ITParserError::ITRemainderNotEmpty),
@ -70,7 +70,7 @@ pub(crate) fn extract_it_from_bytes(wit_section_bytes: &[u8]) -> Result<Interfac
} }
} }
pub(crate) fn extract_custom_section(module: &walrus::Module) -> Result<Cow<'_, [u8]>> { pub(crate) fn extract_custom_section(module: &walrus::Module) -> ParserResult<Cow<'_, [u8]>> {
let sections = module let sections = module
.customs .customs
.iter() .iter()

View File

@ -42,16 +42,20 @@ pub use extractor::extract_it_from_module;
pub use extractor::extract_version_from_module; pub use extractor::extract_version_from_module;
pub use extractor::extract_text_it; pub use extractor::extract_text_it;
pub use extractor::module_interface; pub use extractor::module_interface;
pub use extractor::module_raw_interface; pub use extractor::module_it_interface;
pub mod interface { pub mod interface {
pub use crate::extractor::ServiceInterface; pub use marine_module_interface::interface::ModuleInterface;
pub use crate::extractor::RecordType; pub use marine_module_interface::interface::RecordType;
pub use crate::extractor::FunctionSignature; pub use marine_module_interface::interface::RecordField;
pub use marine_module_interface::interface::FunctionSignature;
}
pub mod it_interface {
pub use marine_module_interface::it_interface::IModuleInterface;
pub use marine_module_interface::it_interface::IRecordTypes;
pub use marine_module_interface::it_interface::IFunctionSignature;
pub use crate::extractor::MModuleInterface;
pub use crate::extractor::MRecordTypes;
pub use crate::extractor::MFunctionSignature;
pub mod it { pub mod it {
pub use wasmer_it::IType; pub use wasmer_it::IType;
pub use wasmer_it::ast::FunctionArg as IFunctionArg; pub use wasmer_it::ast::FunctionArg as IFunctionArg;
@ -60,4 +64,4 @@ pub mod interface {
} }
} }
pub(crate) type Result<T> = std::result::Result<T, ITParserError>; pub(crate) type ParserResult<T> = std::result::Result<T, ITParserError>;

View File

@ -0,0 +1,26 @@
[package]
name = "marine-module-interface"
description = "Fluence Marine module interface"
version = "0.1.0"
authors = ["Fluence Labs"]
license = "Apache-2.0"
edition = "2018"
[lib]
name = "marine_module_interface"
path = "src/lib.rs"
[dependencies]
marine-it-interfaces = { path = "../it-interfaces", version = "0.4.0" }
#marine-it-generator = { path = "../it-generator", verision = "0.5.2"}
anyhow = "1.0.31"
walrus = "0.18.0"
wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0"}
wasmer-it = { package = "wasmer-interface-types-fl", version = "0.20.0" }
nom = "5.1"
itertools = "0.10.0"
semver = "0.11.0"
serde = "=1.0.118"
thiserror = "1.0.24"

View File

@ -0,0 +1,27 @@
/*
* 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::it_interface::ITInterfaceError;
use thiserror::Error as ThisError;
#[derive(Debug, ThisError)]
pub enum InterfaceError {
#[error("record type with type id {0} not found")]
NotFoundRecordTypeId(u64),
#[error("{0}")]
ITInterfaceError(#[from] ITInterfaceError),
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::ModuleInterface;
use super::InterfaceResult;
use super::FunctionSignature;
use super::records_transformer::RecordsTransformer;
use crate::it_interface::IModuleInterface;
use crate::it_interface::IFunctionSignature;
use crate::it_interface::IRecordTypes;
pub fn it_to_module_interface(mm_interface: IModuleInterface) -> InterfaceResult<ModuleInterface> {
let record_types = mm_interface.export_record_types;
let function_signatures = mm_interface
.function_signatures
.into_iter()
.map(|sign| serialize_function_signature(sign, &record_types))
.collect();
let record_types = RecordsTransformer::transform(&record_types)?;
let interface = ModuleInterface {
function_signatures,
record_types,
};
Ok(interface)
}
fn serialize_function_signature(
signature: IFunctionSignature,
record_types: &IRecordTypes,
) -> FunctionSignature {
use super::itype_text_view;
let arguments = signature
.arguments
.iter()
.map(|arg| (arg.name.clone(), itype_text_view(&arg.ty, record_types)))
.collect();
let output_types = signature
.outputs
.iter()
.map(|itype| itype_text_view(itype, record_types))
.collect();
FunctionSignature {
name: signature.name.to_string(),
arguments,
output_types,
}
}

View File

@ -0,0 +1,50 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::it_interface::IRecordTypes;
use wasmer_it::IType;
/// Converts the supplied IType to a Aqua0compatible text representation.
///
/// SAFETY:
/// It's assumed that arguments are well-formed and all records have a corresponded type in
/// record_types.
pub fn itype_text_view(arg_ty: &IType, record_types: &IRecordTypes) -> String {
match arg_ty {
IType::Record(record_type_id) => {
// assumed that this functions called with well-formed args
let record = record_types.get(record_type_id).unwrap();
record.name.clone()
}
IType::Array(array_ty) => format!("[]{}", itype_text_view(array_ty, record_types)),
IType::Boolean => "bool".to_string(),
IType::S8 => "i8".to_string(),
IType::S16 => "i16".to_string(),
IType::S32 => "i32".to_string(),
IType::S64 => "i64".to_string(),
IType::U8 => "u8".to_string(),
IType::U16 => "u16".to_string(),
IType::U32 => "u32".to_string(),
IType::U64 => "u64".to_string(),
IType::F32 => "f32".to_string(),
IType::F64 => "f64".to_string(),
IType::String => "string".to_string(),
IType::ByteArray => "[]u8".to_string(),
IType::I32 => "i32".to_string(),
IType::I64 => "i64".to_string(),
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod errors;
mod interface_transformer;
mod itype_to_text;
mod module_interface;
mod records_transformer;
pub use errors::InterfaceError;
pub use interface_transformer::it_to_module_interface;
pub use itype_to_text::*;
pub use module_interface::*;
pub type InterfaceResult<T> = std::result::Result<T, InterfaceError>;
use marine_it_interfaces::MITInterfaces;
/// Returns interface of a Marine module.
pub fn get_interface(mit: &MITInterfaces<'_>) -> InterfaceResult<ModuleInterface> {
let it_interface = crate::it_interface::get_interface(mit)?;
let interface = it_to_module_interface(it_interface)?;
Ok(interface)
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use serde::Serialize;
use serde::Deserialize;
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct FunctionSignature {
pub name: String,
pub arguments: Vec<(String, String)>,
pub output_types: Vec<String>,
}
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct RecordField {
pub name: String,
pub ty: String,
}
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct RecordType {
pub name: String,
pub id: u64,
pub fields: Vec<RecordField>,
}
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct ModuleInterface {
pub function_signatures: Vec<FunctionSignature>,
// record types are guaranteed to be topological sorted
pub record_types: Vec<RecordType>,
}
use std::fmt;
impl fmt::Display for FunctionSignature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use itertools::Itertools;
let output = match self.output_types.len() {
0 => "()",
1 => &self.output_types[0],
_ => unimplemented!("more than 1 output type is unsupported"),
};
if self.arguments.is_empty() {
writeln!(f, "{}: -> {}", self.name, output)
} else {
let args = self.arguments.iter().map(|(_, ty)| ty).format(",");
writeln!(f, "{}: {} -> {}", self.name, args, output)
}
}
}
impl fmt::Display for RecordType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "data {}:", self.name)?;
for field in self.fields.iter() {
writeln!(f, " {}: {}", field.name, field.ty)?;
}
Ok(())
}
}

View File

@ -0,0 +1,128 @@
/*
* 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 super::RecordType;
use super::RecordField;
use super::InterfaceResult;
use super::InterfaceError;
use crate::it_interface::IRecordTypes;
use wasmer_it::IRecordType;
use wasmer_it::IType;
use std::collections::HashSet;
use std::rc::Rc;
pub(crate) struct RecordsTransformer {
used: HashSet<u64>,
sorted_order: Vec<u64>,
}
impl RecordsTransformer {
pub(crate) fn transform(record_types: &IRecordTypes) -> InterfaceResult<Vec<RecordType>> {
let records_count = record_types.len();
let mut transformer = Self {
used: HashSet::with_capacity(records_count),
sorted_order: Vec::with_capacity(records_count),
};
// TODO: check for cycles
transformer.topological_sort(record_types)?;
let record_types = transformer.into_transformed_records(record_types);
Ok(record_types)
}
fn topological_sort(&mut self, exported_records: &IRecordTypes) -> InterfaceResult<()> {
for (id, record) in exported_records {
self.dfs(*id, record, exported_records)?;
}
Ok(())
}
fn dfs(
&mut self,
record_id: u64,
record: &Rc<IRecordType>,
exported_records: &IRecordTypes,
) -> InterfaceResult<()> {
if !self.used.insert(record_id) {
return Ok(());
}
for field in (&record.fields).iter() {
self.type_dfs(&field.ty, exported_records)?;
}
self.sorted_order.push(record_id);
Ok(())
}
fn type_dfs(
&mut self,
field_ty: &IType,
exported_records: &IRecordTypes,
) -> InterfaceResult<()> {
match field_ty {
IType::Record(type_id) => {
let child_record = exported_records
.get(type_id)
.ok_or(InterfaceError::NotFoundRecordTypeId(*type_id))?;
self.dfs(*type_id, child_record, exported_records)
}
IType::Array(ty) => self.type_dfs(ty, exported_records),
_ => Ok(()),
}
}
fn into_transformed_records(self, record_types: &IRecordTypes) -> Vec<RecordType> {
self.sorted_order
.into_iter()
.map(|id| {
// unwrap is safe here because sorted_order is constructed based on record_types
let record = record_types.get(&id).unwrap();
Self::convert_record(id, record, &record_types)
})
.collect::<Vec<_>>()
}
fn convert_record(
id: u64,
record: &Rc<IRecordType>,
record_types: &IRecordTypes,
) -> RecordType {
use super::itype_text_view;
let fields = record
.fields
.iter()
.map(|field| RecordField {
name: field.name.clone(),
ty: itype_text_view(&field.ty, record_types),
})
.collect::<Vec<_>>();
RecordType {
name: record.name.clone(),
id,
fields,
}
}
}

View File

@ -0,0 +1,33 @@
/*
* 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 marine_it_interfaces::MITInterfacesError;
use thiserror::Error as ThisError;
#[derive(Debug, ThisError)]
pub enum ITInterfaceError {
#[error("type with idx = {0} isn't a function type")]
ITTypeNotFunction(u32),
#[error("record type with type id {0} not found")]
NotFoundRecordTypeId(u64),
#[error("mailformed module: a record contains more recursion level then allowed")]
TooManyRecursionLevels,
#[error("{0}")]
MITInterfacesError(#[from] MITInterfacesError),
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::IFunctionSignature;
use super::ITInterfaceError;
use super::RIResult;
use marine_it_interfaces::MITInterfaces;
use std::rc::Rc;
pub struct ITExportFuncDescriptor<'n> {
pub adapter_function_type: u32,
pub name: &'n str,
}
/// Returns all exported IT functions descriptors.
pub fn get_export_funcs_descriptors<'i>(
mit: &'i MITInterfaces<'_>,
) -> Vec<ITExportFuncDescriptor<'i>> {
// An IT function is exported if it lies in export functions and have implementation.
// An export IT function without implementation is a hack and used to call core function from
// a Wasm module. This hack is needed because there is only one call instruction in the
// interface-types crates and it's needed to distinguish somehow between calling export IT or
// core functions. This scheme is a kind of mess and it needs to be refactored one day.
mit.implementations()
.filter_map(|(adapter_function_type, core_function_type)| {
mit.exports_by_type(*core_function_type)
.map(|export_function_name| (adapter_function_type, export_function_name))
})
.map(|(&adapter_function_type, export_function_names)| {
export_function_names
.iter()
.map(move |name| ITExportFuncDescriptor {
adapter_function_type,
name,
})
})
.flatten()
.collect::<Vec<_>>()
}
/// Returns all exported IT functions.
pub fn get_export_funcs(mit: &MITInterfaces<'_>) -> RIResult<Vec<IFunctionSignature>> {
use marine_it_interfaces::ITAstType;
let funcs_descriptors = get_export_funcs_descriptors(mit);
funcs_descriptors
.into_iter()
.map(|descriptor| {
let it_type = mit.type_by_idx_r(descriptor.adapter_function_type)?;
match it_type {
ITAstType::Function {
arguments,
output_types,
} => {
let signature = IFunctionSignature {
name: Rc::new(descriptor.name.to_string()),
arguments: arguments.clone(),
outputs: output_types.clone(),
adapter_function_type: descriptor.adapter_function_type,
};
Ok(signature)
}
_ => Err(ITInterfaceError::ITTypeNotFunction(
descriptor.adapter_function_type,
)),
}
})
.collect::<RIResult<Vec<IFunctionSignature>>>()
}

View File

@ -0,0 +1,129 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use super::IRecordTypes;
use super::RIResult;
use super::ITInterfaceError;
use super::IFunctionSignature;
use marine_it_interfaces::MITInterfaces;
use wasmer_it::IType;
use std::collections::HashMap;
const TYPE_RESOLVE_RECURSION_LIMIT: u32 = 1024;
pub struct FullRecordTypes {
pub record_types: IRecordTypes,
pub export_record_types: IRecordTypes,
}
pub fn get_record_types<'f>(
mit: &MITInterfaces<'_>,
export_funcs: impl ExactSizeIterator<Item = &'f IFunctionSignature>,
) -> RIResult<FullRecordTypes> {
let all_record_types = get_all_records(mit);
let mut export_record_types = HashMap::new();
let itypes = export_funcs.flat_map(|s| {
s.arguments
.as_ref()
.iter()
.map(|a| &a.ty)
.chain(s.outputs.as_ref().iter())
});
for itype in itypes {
handle_itype(itype, &all_record_types, &mut export_record_types, 0)?;
}
let full_record_types = FullRecordTypes {
record_types: all_record_types,
export_record_types,
};
Ok(full_record_types)
}
fn handle_itype(
itype: &IType,
all_record_types: &IRecordTypes,
export_record_types: &mut IRecordTypes,
recursion_level: u32,
) -> RIResult<()> {
if recursion_level > TYPE_RESOLVE_RECURSION_LIMIT {
return Err(ITInterfaceError::TooManyRecursionLevels);
}
match itype {
IType::Record(record_type_id) => handle_record_type(
*record_type_id,
all_record_types,
export_record_types,
recursion_level + 1,
)?,
IType::Array(array_ty) => handle_itype(
array_ty,
all_record_types,
export_record_types,
recursion_level + 1,
)?,
_ => {}
}
Ok(())
}
fn handle_record_type(
record_type_id: u64,
all_record_types: &IRecordTypes,
export_record_types: &mut IRecordTypes,
recursion_level: u32,
) -> RIResult<()> {
let record_type = all_record_types
.get(&record_type_id)
.ok_or(ITInterfaceError::NotFoundRecordTypeId(record_type_id))?;
export_record_types.insert(record_type_id, record_type.clone());
for field in record_type.fields.iter() {
handle_itype(
&field.ty,
all_record_types,
export_record_types,
recursion_level + 1,
)?;
}
Ok(())
}
fn get_all_records(mit: &MITInterfaces<'_>) -> IRecordTypes {
use marine_it_interfaces::ITAstType;
mit.types()
.enumerate()
.fold(HashMap::new(), |mut record_types_by_id, (id, ty)| {
match ty {
ITAstType::Record(record_type) => {
record_types_by_id.insert(id as u64, record_type.clone());
}
ITAstType::Function { .. } => {}
};
record_types_by_id
})
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use wasmer_it::IType;
use wasmer_it::ast::FunctionArg as IFunctionArg;
use wasmer_it::IRecordType;
use serde::Serialize;
use serde::Deserialize;
use std::collections::HashMap;
use std::rc::Rc;
pub type IRecordTypes = HashMap<u64, Rc<IRecordType>>;
/// Represent a function type inside Marine module.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct IFunctionSignature {
pub name: Rc<String>,
pub arguments: Rc<Vec<IFunctionArg>>,
pub outputs: Rc<Vec<IType>>,
pub adapter_function_type: u32,
}
/// Represent an interface of a Wasm module.
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
pub struct IModuleInterface {
pub export_record_types: IRecordTypes,
pub record_types: IRecordTypes,
pub function_signatures: Vec<IFunctionSignature>,
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod errors;
mod export_it_functions;
mod export_it_records;
mod it_module_interface;
pub use errors::*;
pub use export_it_functions::*;
pub use export_it_records::*;
pub use it_module_interface::*;
pub type RIResult<T> = std::result::Result<T, ITInterfaceError>;
use marine_it_interfaces::MITInterfaces;
/// Returns Marine module interface that includes both export and all record types.
pub fn get_interface(mit: &MITInterfaces<'_>) -> RIResult<IModuleInterface> {
let function_signatures = get_export_funcs(mit)?;
let FullRecordTypes {
record_types,
export_record_types,
} = get_record_types(mit, function_signatures.iter())?;
let mm_interface = IModuleInterface {
record_types,
export_record_types,
function_signatures,
};
Ok(mm_interface)
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2021 Fluence Labs Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#![warn(rust_2018_idioms)]
#![deny(
dead_code,
nonstandard_style,
unused_imports,
unused_mut,
unused_variables,
unused_unsafe,
unreachable_patterns
)]
pub mod interface;
pub mod it_interface;

View File

@ -1,13 +1,13 @@
[package] [package]
name = "fluence-app-service" name = "fluence-app-service"
description = "Fluence Application Service" description = "Fluence Application Service"
version = "0.7.2" version = "0.7.3"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
fluence-faas = { path = "../fluence-faas", version = "0.7.2" } fluence-faas = { path = "../fluence-faas", version = "0.7.3" }
maplit = "1.0.2" maplit = "1.0.2"
log = "0.4.8" log = "0.4.8"

View File

@ -17,7 +17,7 @@
use fluence_faas::FaaSModuleInterface; use fluence_faas::FaaSModuleInterface;
use fluence_faas::FaaSFunctionSignature; use fluence_faas::FaaSFunctionSignature;
use fluence_faas::IRecordType; use fluence_faas::IRecordType;
use fluence_faas::RecordTypes; use fluence_faas::MRecordTypes;
use fluence_faas::itype_text_view; use fluence_faas::itype_text_view;
use serde::Serialize; use serde::Serialize;
@ -66,7 +66,7 @@ pub(crate) fn into_service_interface(faas_interface: FaaSModuleInterface<'_>) ->
fn serialize_function_signature( fn serialize_function_signature(
signature: FaaSFunctionSignature, signature: FaaSFunctionSignature,
record_types: &RecordTypes, record_types: &MRecordTypes,
) -> FunctionSignature { ) -> FunctionSignature {
let arguments = signature let arguments = signature
.arguments .arguments
@ -90,7 +90,7 @@ fn serialize_function_signature(
fn serialize_record_type( fn serialize_record_type(
id: u64, id: u64,
record: Rc<IRecordType>, record: Rc<IRecordType>,
record_types: &RecordTypes, record_types: &MRecordTypes,
) -> RecordType { ) -> RecordType {
let fields = record let fields = record
.fields .fields

View File

@ -1,13 +1,14 @@
[package] [package]
name = "fluence-faas" name = "fluence-faas"
description = "Fluence FaaS" description = "Fluence FaaS"
version = "0.7.2" version = "0.7.3"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
marine-runtime = { path = "../runtime", version = "0.5.0" } marine-runtime = { path = "../runtime", version = "0.5.0" }
marine-module-interface = { path = "../crates/module-interface", version = "0.1.0" }
marine-utils = { path = "../crates/utils", version = "0.2.0" } marine-utils = { path = "../crates/utils", version = "0.2.0" }
fluence-sdk-main = { version = "0.6.9", features = ["logger"] } fluence-sdk-main = { version = "0.6.9", features = ["logger"] }
fluence = { version = "0.6.3", features = ["logger"] } fluence = { version = "0.6.3", features = ["logger"] }

View File

@ -28,7 +28,7 @@ use crate::host_imports::logger::WASM_LOG_ENV_NAME;
use marine::Marine; use marine::Marine;
use marine::IFunctionArg; use marine::IFunctionArg;
use marine_utils::SharedString; use marine_utils::SharedString;
use marine::RecordTypes; use marine::MRecordTypes;
use fluence::CallParameters; use fluence::CallParameters;
use serde_json::Value as JValue; use serde_json::Value as JValue;
@ -39,7 +39,7 @@ use std::rc::Rc;
struct ModuleInterface { struct ModuleInterface {
function_signatures: HashMap<SharedString, (Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>)>, function_signatures: HashMap<SharedString, (Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>)>,
record_types: Rc<RecordTypes>, record_types: Rc<MRecordTypes>,
} }
// TODO: remove and use mutex instead // TODO: remove and use mutex instead
@ -186,7 +186,7 @@ impl FluenceFaaS {
&'faas mut self, &'faas mut self,
module_name: &str, module_name: &str,
func_name: &str, func_name: &str,
) -> Result<(Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>, Rc<RecordTypes>)> { ) -> Result<(Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>, Rc<MRecordTypes>)> {
use FaaSError::NoSuchModule; use FaaSError::NoSuchModule;
use FaaSError::MissingFunctionError; use FaaSError::MissingFunctionError;

View File

@ -14,17 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
use super::IType;
use super::IRecordType; use super::IRecordType;
use super::itype_text_view;
use crate::FaaSModuleInterface; use crate::FaaSModuleInterface;
use marine::RecordTypes;
use itertools::Itertools; use itertools::Itertools;
use serde::Serialize; use serde::Serialize;
use std::fmt; use std::fmt;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashSet;
#[derive(Debug, PartialEq, Eq, Clone, Serialize)] #[derive(Debug, PartialEq, Eq, Clone, Serialize)]
pub struct FaaSInterface<'a> { pub struct FaaSInterface<'a> {
@ -33,78 +31,80 @@ pub struct FaaSInterface<'a> {
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 mut printed_record_types: HashSet<&IRecordType> = HashSet::new(); print_record_types(self.modules.values(), f)?;
print_functions_sign(self.modules.iter(), f)
for (_, module_interface) in self.modules.iter() {
for (_, record_type) in module_interface.record_types.iter() {
if !printed_record_types.insert(record_type) {
// do not print record if it has been already printed
continue;
}
writeln!(f, "{} {{", record_type.name)?;
for field in record_type.fields.iter() {
writeln!(
f,
" {}: {}",
field.name,
itype_text_view(&field.ty, &module_interface.record_types)
)?;
}
writeln!(f, "}}")?;
}
}
for (name, module_interface) in self.modules.iter() {
writeln!(f, "\n{}:", *name)?;
for function_signature in module_interface.function_signatures.iter() {
write!(f, " fn {}(", function_signature.name)?;
let args = function_signature
.arguments
.iter()
.map(|arg| {
format!(
"{}: {}",
arg.name,
itype_text_view(&arg.ty, &module_interface.record_types)
)
})
.join(", ");
let outputs = &function_signature.outputs;
if outputs.is_empty() {
writeln!(f, "{})", args)?;
} else if outputs.len() == 1 {
writeln!(
f,
"{}) -> {}",
args,
itype_text_view(&outputs[0], &module_interface.record_types)
)?;
} else {
// At now, multi values aren't supported - only one output type is possible
unimplemented!()
}
}
}
Ok(())
} }
} }
pub fn itype_text_view(arg_ty: &IType, record_types: &RecordTypes) -> String { fn print_record_types<'r>(
match arg_ty { modules: impl Iterator<Item = &'r FaaSModuleInterface<'r>>,
IType::Record(record_type_id) => { f: &mut fmt::Formatter<'_>,
// unwrap is safe because FaaSInterface here is well-formed ) -> fmt::Result {
// (it was checked on the module startup stage) use std::collections::HashSet;
let record = record_types.get(record_type_id).unwrap();
record.name.clone() let mut printed_record_types: HashSet<&IRecordType> = HashSet::new();
for module in modules {
for (_, record_type) in module.record_types.iter() {
if !printed_record_types.insert(record_type) {
// do not print record if it has been already printed
continue;
}
writeln!(f, "data {}:", record_type.name)?;
for field in record_type.fields.iter() {
writeln!(
f,
" {}: {}",
field.name,
itype_text_view(&field.ty, &module.record_types)
)?;
}
} }
IType::Array(array_ty) => format!("Array<{}>", itype_text_view(array_ty, record_types)),
t => format!("{:?}", t),
} }
writeln!(f)
}
fn print_functions_sign<'r>(
modules: impl Iterator<Item = (&'r &'r str, &'r FaaSModuleInterface<'r>)>,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
for (name, module_interface) in modules {
writeln!(f, "{}:", *name)?;
for function_signature in module_interface.function_signatures.iter() {
write!(f, " fn {}(", function_signature.name)?;
let args = function_signature
.arguments
.iter()
.map(|arg| {
format!(
"{}: {}",
arg.name,
itype_text_view(&arg.ty, &module_interface.record_types)
)
})
.join(", ");
let outputs = &function_signature.outputs;
if outputs.is_empty() {
writeln!(f, "{})", args)?;
} else if outputs.len() == 1 {
writeln!(
f,
"{}) -> {}",
args,
itype_text_view(&outputs[0], &module_interface.record_types)
)?;
} else {
// At now, multi values aren't supported - only one output type is possible
unimplemented!()
}
}
}
Ok(())
} }

View File

@ -19,13 +19,13 @@ use crate::IType;
use crate::Result; use crate::Result;
use crate::errors::FaaSError::JsonOutputSerializationError as OutputDeError; use crate::errors::FaaSError::JsonOutputSerializationError as OutputDeError;
use marine::RecordTypes; use marine::MRecordTypes;
use serde_json::Value as JValue; use serde_json::Value as JValue;
pub(crate) fn ivalues_to_json( pub(crate) fn ivalues_to_json(
mut ivalues: Vec<IValue>, mut ivalues: Vec<IValue>,
outputs: &[IType], outputs: &[IType],
record_types: &RecordTypes, record_types: &MRecordTypes,
) -> Result<JValue> { ) -> Result<JValue> {
if outputs.len() != ivalues.len() { if outputs.len() != ivalues.len() {
return Err(OutputDeError(format!( return Err(OutputDeError(format!(
@ -42,7 +42,7 @@ pub(crate) fn ivalues_to_json(
} }
} }
fn ivalue_to_json(ivalue: IValue, output: &IType, record_types: &RecordTypes) -> Result<JValue> { fn ivalue_to_json(ivalue: IValue, output: &IType, record_types: &MRecordTypes) -> Result<JValue> {
use serde_json::json; use serde_json::json;
// clone here needed because binding by-value and by-ref in the same pattern in unstable // clone here needed because binding by-value and by-ref in the same pattern in unstable

View File

@ -19,7 +19,7 @@ use crate::IType;
use crate::Result; use crate::Result;
use crate::FaaSError::JsonArgumentsDeserializationError as ArgDeError; use crate::FaaSError::JsonArgumentsDeserializationError as ArgDeError;
use marine::RecordTypes; use marine::MRecordTypes;
use serde_json::Value as JValue; use serde_json::Value as JValue;
use wasmer_it::NEVec; use wasmer_it::NEVec;
@ -30,7 +30,7 @@ use std::iter::ExactSizeIterator;
pub(crate) fn json_to_ivalues<'a, 'b>( pub(crate) fn json_to_ivalues<'a, 'b>(
json_args: JValue, json_args: JValue,
arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator, arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
record_types: &'b RecordTypes, record_types: &'b MRecordTypes,
) -> Result<Vec<IValue>> { ) -> Result<Vec<IValue>> {
let ivalues = match json_args { let ivalues = match json_args {
JValue::Object(json_map) => json_map_to_ivalues(json_map, arg_types, &record_types)?, JValue::Object(json_map) => json_map_to_ivalues(json_map, arg_types, &record_types)?,
@ -48,7 +48,7 @@ pub(crate) fn json_to_ivalues<'a, 'b>(
fn json_map_to_ivalues<'a, 'b>( fn json_map_to_ivalues<'a, 'b>(
mut json_map: serde_json::Map<String, JValue>, mut json_map: serde_json::Map<String, JValue>,
arg_types: impl Iterator<Item = (&'a String, &'a IType)>, arg_types: impl Iterator<Item = (&'a String, &'a IType)>,
record_types: &'b RecordTypes, record_types: &'b MRecordTypes,
) -> Result<Vec<IValue>> { ) -> Result<Vec<IValue>> {
let mut iargs = Vec::new(); let mut iargs = Vec::new();
@ -75,7 +75,7 @@ fn json_map_to_ivalues<'a, 'b>(
fn json_array_to_ivalues<'a, 'b>( fn json_array_to_ivalues<'a, 'b>(
json_array: Vec<JValue>, json_array: Vec<JValue>,
arg_types: impl Iterator<Item = &'a IType> + ExactSizeIterator, arg_types: impl Iterator<Item = &'a IType> + ExactSizeIterator,
record_types: &'b RecordTypes, record_types: &'b MRecordTypes,
) -> Result<Vec<IValue>> { ) -> Result<Vec<IValue>> {
if json_array.len() != arg_types.len() { if json_array.len() != arg_types.len() {
return Err(ArgDeError(format!( return Err(ArgDeError(format!(
@ -129,7 +129,7 @@ fn json_null_to_ivalues<'a>(
} }
/// Convert one JValue to an array of ivalues according to the supplied argument type. /// Convert one JValue to an array of ivalues according to the supplied argument type.
fn jvalue_to_ivalue(jvalue: JValue, ty: &IType, record_types: &RecordTypes) -> Result<IValue> { fn jvalue_to_ivalue(jvalue: JValue, ty: &IType, record_types: &MRecordTypes) -> Result<IValue> {
macro_rules! to_ivalue( macro_rules! to_ivalue(
($json_value:expr, $ty:ident) => { ($json_value:expr, $ty:ident) => {
{ {
@ -211,7 +211,7 @@ fn jvalue_to_ivalue(jvalue: JValue, ty: &IType, record_types: &RecordTypes) -> R
fn json_record_type_to_ivalue( fn json_record_type_to_ivalue(
json_value: JValue, json_value: JValue,
record_type_id: &u64, record_type_id: &u64,
record_types: &RecordTypes, record_types: &MRecordTypes,
) -> Result<NEVec<IValue>> { ) -> Result<NEVec<IValue>> {
let record_type = record_types.get(record_type_id).ok_or_else(|| { let record_type = record_types.get(record_type_id).ok_or_else(|| {
ArgDeError(format!( ArgDeError(format!(

View File

@ -36,7 +36,6 @@ pub(crate) type Result<T> = std::result::Result<T, FaaSError>;
pub use faas::FluenceFaaS; pub use faas::FluenceFaaS;
pub use faas_interface::FaaSInterface; pub use faas_interface::FaaSInterface;
pub use faas_interface::itype_text_view;
pub use config::FaaSConfig; pub use config::FaaSConfig;
pub use config::FaaSModuleConfig; pub use config::FaaSModuleConfig;
@ -57,7 +56,7 @@ pub use marine::IFunctionArg;
pub use marine::IType; pub use marine::IType;
pub use marine::MModuleInterface as FaaSModuleInterface; pub use marine::MModuleInterface as FaaSModuleInterface;
pub use marine::MFunctionSignature as FaaSFunctionSignature; pub use marine::MFunctionSignature as FaaSFunctionSignature;
pub use marine::RecordTypes; pub use marine::MRecordTypes;
pub use marine::HostExportedFunc; pub use marine::HostExportedFunc;
pub use marine::HostImportDescriptor; pub use marine::HostImportDescriptor;
pub use marine::HostImportError; pub use marine::HostImportError;
@ -67,6 +66,8 @@ pub use marine::ne_vec;
pub use marine::min_sdk_version; pub use marine::min_sdk_version;
pub use marine::min_it_version; pub use marine::min_it_version;
pub use marine_module_interface::interface::itype_text_view;
pub use fluence::CallParameters; pub use fluence::CallParameters;
pub use fluence::SecurityTetraplet; pub use fluence::SecurityTetraplet;

View File

@ -15,6 +15,7 @@ marine-module-info-parser = { path = "../crates/module-info-parser", version = "
marine-it-interfaces = { path = "../crates/it-interfaces", version = "0.4.0" } marine-it-interfaces = { path = "../crates/it-interfaces", version = "0.4.0" }
marine-it-parser = { path = "../crates/it-parser", version = "0.6.0" } marine-it-parser = { path = "../crates/it-parser", version = "0.6.0" }
marine-it-generator = { path = "../crates/it-generator", version = "0.5.0" } marine-it-generator = { path = "../crates/it-generator", version = "0.5.0" }
marine-module-interface = { path = "../crates/module-interface", version = "0.1.0" }
marine-utils = { path = "../crates/utils", version = "0.2.0" } marine-utils = { path = "../crates/utils", version = "0.2.0" }
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }

View File

@ -16,7 +16,7 @@
use super::*; use super::*;
use crate::module::MModule; use crate::module::MModule;
use crate::module::RecordTypes; use crate::module::MRecordTypes;
use serde::Serialize; use serde::Serialize;
@ -27,7 +27,7 @@ use std::rc::Rc;
/// Represent Marine module interface. /// Represent Marine module interface.
#[derive(PartialEq, Eq, Debug, Clone, Serialize)] #[derive(PartialEq, Eq, Debug, Clone, Serialize)]
pub struct MModuleInterface<'a> { pub struct MModuleInterface<'a> {
pub record_types: &'a RecordTypes, pub record_types: &'a MRecordTypes,
pub function_signatures: Vec<MFunctionSignature>, pub function_signatures: Vec<MFunctionSignature>,
} }
@ -119,7 +119,7 @@ impl Marine {
} }
/// Return record types exported by module with given name. /// Return record types exported by module with given name.
pub fn module_record_types<S: AsRef<str>>(&self, module_name: S) -> Option<&RecordTypes> { pub fn module_record_types<S: AsRef<str>>(&self, module_name: S) -> Option<&MRecordTypes> {
self.modules self.modules
.get(module_name.as_ref()) .get(module_name.as_ref())
.map(|module| module.export_record_types()) .map(|module| module.export_record_types())

View File

@ -18,6 +18,7 @@ use crate::HostImportError;
use marine_it_interfaces::MITInterfacesError; use marine_it_interfaces::MITInterfacesError;
use marine_it_parser::ITParserError; use marine_it_parser::ITParserError;
use marine_module_info_parser::ModuleInfoError; use marine_module_info_parser::ModuleInfoError;
use marine_module_interface::it_interface::ITInterfaceError;
use wasmer_runtime::error as wasmer_error; use wasmer_runtime::error as wasmer_error;
@ -63,6 +64,10 @@ pub enum MError {
#[error("{0}")] #[error("{0}")]
WASIPrepareError(String), WASIPrepareError(String),
/// Errors occurred inside marine-module-interface crate.
#[error("{0}")]
ModuleInterfaceError(#[from] ITInterfaceError),
/// Error arisen during execution of Wasm modules (especially, interface types). /// Error arisen during execution of Wasm modules (especially, interface types).
#[error("Execution error: {0}")] #[error("Execution error: {0}")]
ITInstructionError(#[from] wasmer_it::errors::InstructionError), ITInstructionError(#[from] wasmer_it::errors::InstructionError),

View File

@ -22,7 +22,7 @@ use super::lowering::LoHelper;
use super::utils::itypes_args_to_wtypes; use super::utils::itypes_args_to_wtypes;
use super::utils::itypes_output_to_wtypes; use super::utils::itypes_output_to_wtypes;
use crate::RecordTypes; use crate::MRecordTypes;
use crate::init_wasm_func_once; use crate::init_wasm_func_once;
use crate::call_wasm_func; use crate::call_wasm_func;
use crate::HostImportDescriptor; use crate::HostImportDescriptor;
@ -41,7 +41,7 @@ use std::ops::Deref;
pub(crate) fn create_host_import_func( pub(crate) fn create_host_import_func(
descriptor: HostImportDescriptor, descriptor: HostImportDescriptor,
record_types: Rc<RecordTypes>, record_types: Rc<MRecordTypes>,
) -> DynamicFunc<'static> { ) -> DynamicFunc<'static> {
let allocate_func: AllocateFunc = Box::new(RefCell::new(None)); let allocate_func: AllocateFunc = Box::new(RefCell::new(None));
let set_result_ptr_func: SetResultPtrFunc = Box::new(RefCell::new(None)); let set_result_ptr_func: SetResultPtrFunc = Box::new(RefCell::new(None));

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
use crate::RecordTypes; use crate::MRecordTypes;
use crate::IRecordType; use crate::IRecordType;
use it_lilo::traits::RecordResolvable; use it_lilo::traits::RecordResolvable;
use it_lilo::traits::RecordResolvableError; use it_lilo::traits::RecordResolvableError;
@ -22,11 +22,11 @@ use it_lilo::traits::RecordResolvableError;
use std::rc::Rc; use std::rc::Rc;
pub(crate) struct LiHelper { pub(crate) struct LiHelper {
record_types: Rc<RecordTypes>, record_types: Rc<MRecordTypes>,
} }
impl LiHelper { impl LiHelper {
pub(crate) fn new(record_types: Rc<RecordTypes>) -> Self { pub(crate) fn new(record_types: Rc<MRecordTypes>) -> Self {
Self { record_types } Self { record_types }
} }
} }

View File

@ -45,7 +45,7 @@ pub use module::IValue;
pub use module::IRecordType; pub use module::IRecordType;
pub use module::IFunctionArg; pub use module::IFunctionArg;
pub use module::IType; pub use module::IType;
pub use module::RecordTypes; pub use module::MRecordTypes;
pub use module::MFunctionSignature; pub use module::MFunctionSignature;
pub use module::from_interface_values; pub use module::from_interface_values;
pub use module::to_interface_value; pub use module::to_interface_value;

View File

@ -15,8 +15,9 @@
*/ */
use super::wit_prelude::*; use super::wit_prelude::*;
use super::MFunctionSignature;
use super::MRecordTypes;
use super::{IType, IRecordType, IFunctionArg, IValue, WValue}; use super::{IType, IRecordType, IFunctionArg, IValue, WValue};
use super::RecordTypes;
use crate::MResult; use crate::MResult;
use crate::MModuleConfig; use crate::MModuleConfig;
@ -29,9 +30,6 @@ use wasmer_runtime::compile;
use wasmer_runtime::ImportObject; use wasmer_runtime::ImportObject;
use wasmer_it::interpreter::Interpreter; use wasmer_it::interpreter::Interpreter;
use serde::Serialize;
use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
@ -48,18 +46,10 @@ pub(super) struct ITModuleFunc {
pub(super) output_types: Rc<Vec<IType>>, pub(super) output_types: Rc<Vec<IType>>,
} }
/// Represent a function type inside Marine module.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct MFunctionSignature {
pub name: Rc<String>,
pub arguments: Rc<Vec<IFunctionArg>>,
pub outputs: Rc<Vec<IType>>,
}
#[derive(Clone)] #[derive(Clone)]
pub(super) struct Callable { pub(super) struct Callable {
pub(super) wit_instance: Arc<ITInstance>, pub(super) it_instance: Arc<ITInstance>,
pub(super) wit_module_func: ITModuleFunc, pub(super) it_module_func: ITModuleFunc,
} }
impl Callable { impl Callable {
@ -67,9 +57,9 @@ impl Callable {
use wasmer_it::interpreter::stack::Stackable; use wasmer_it::interpreter::stack::Stackable;
let result = self let result = self
.wit_module_func .it_module_func
.interpreter .interpreter
.run(args, Arc::make_mut(&mut self.wit_instance))? .run(args, Arc::make_mut(&mut self.it_instance))?
.as_slice() .as_slice()
.to_owned(); .to_owned();
@ -105,7 +95,7 @@ pub(crate) struct MModule {
// TODO: save refs instead copying of a record types HashMap. // TODO: save refs instead copying of a record types HashMap.
/// Record types used in exported functions as arguments or return values. /// Record types used in exported functions as arguments or return values.
export_record_types: RecordTypes, export_record_types: MRecordTypes,
} }
impl MModule { impl MModule {
@ -130,7 +120,7 @@ impl MModule {
Self::create_import_objects(config, &mit, wit_import_object.clone())?; Self::create_import_objects(config, &mit, wit_import_object.clone())?;
let wasmer_instance = wasmer_module.instantiate(&wasi_import_object)?; let wasmer_instance = wasmer_module.instantiate(&wasi_import_object)?;
let wit_instance = unsafe { let it_instance = unsafe {
// get_mut_unchecked here is safe because currently only this modules have reference to // get_mut_unchecked here is safe because currently only this modules have reference to
// it and the environment is single-threaded // it and the environment is single-threaded
*Arc::get_mut_unchecked(&mut wit_instance) = *Arc::get_mut_unchecked(&mut wit_instance) =
@ -138,8 +128,7 @@ impl MModule {
std::mem::transmute::<_, Arc<ITInstance>>(wit_instance) std::mem::transmute::<_, Arc<ITInstance>>(wit_instance)
}; };
let export_funcs = Self::instantiate_wit_exports(&wit_instance, &mit)?; let (export_funcs, export_record_types) = Self::instantiate_exports(&it_instance, &mit)?;
let export_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]
@ -179,12 +168,12 @@ impl MModule {
.iter() .iter()
.map(|(func_name, func)| MFunctionSignature { .map(|(func_name, func)| MFunctionSignature {
name: func_name.0.clone(), name: func_name.0.clone(),
arguments: func.wit_module_func.arguments.clone(), arguments: func.it_module_func.arguments.clone(),
outputs: func.wit_module_func.output_types.clone(), outputs: func.it_module_func.output_types.clone(),
}) })
} }
pub(crate) fn export_record_types(&self) -> &RecordTypes { pub(crate) fn export_record_types(&self) -> &MRecordTypes {
&self.export_record_types &self.export_record_types
} }
@ -260,54 +249,36 @@ impl MModule {
Ok((wasi_import_object, host_closures_import_object)) Ok((wasi_import_object, host_closures_import_object))
} }
fn instantiate_wit_exports( fn instantiate_exports(
wit_instance: &Arc<ITInstance>, it_instance: &Arc<ITInstance>,
wit: &MITInterfaces<'_>, mit: &MITInterfaces<'_>,
) -> MResult<ExportFunctions> { ) -> MResult<(ExportFunctions, MRecordTypes)> {
use marine_it_interfaces::ITAstType; let module_interface = marine_module_interface::it_interface::get_interface(mit)?;
wit.implementations() let export_funcs = module_interface
.filter_map(|(adapter_function_type, core_function_type)| { .function_signatures
wit.exports_by_type(*core_function_type) .into_iter()
.map(|export_function_name| (adapter_function_type, export_function_name)) .map(|sign| {
let adapter_instructions = mit.adapter_by_type_r(sign.adapter_function_type)?;
let interpreter: ITInterpreter = adapter_instructions.clone().try_into()?;
let it_module_func = ITModuleFunc {
interpreter: Arc::new(interpreter),
arguments: sign.arguments.clone(),
output_types: sign.outputs.clone(),
};
let shared_string = SharedString(sign.name);
let callable = Rc::new(Callable {
it_instance: it_instance.clone(),
it_module_func,
});
Ok((shared_string, callable))
}) })
.map(|(adapter_function_type, export_function_names)| { .collect::<MResult<ExportFunctions>>()?;
export_function_names
.iter()
.map(move |export_function_name| (*adapter_function_type, export_function_name))
})
.flatten()
.map(|(adapter_function_type, export_function_name)| {
let adapter_instructions = wit.adapter_by_type_r(adapter_function_type)?;
let wit_type = wit.type_by_idx_r(adapter_function_type)?;
match wit_type { Ok((export_funcs, module_interface.export_record_types))
ITAstType::Function {
arguments,
output_types,
} => {
let interpreter: ITInterpreter = adapter_instructions.clone().try_into()?;
let wit_module_func = ITModuleFunc {
interpreter: Arc::new(interpreter),
arguments: arguments.clone(),
output_types: output_types.clone(),
};
let shared_string = SharedString(Rc::new(export_function_name.to_string()));
let callable = Rc::new(Callable {
wit_instance: wit_instance.clone(),
wit_module_func,
});
Ok((shared_string, callable))
}
_ => Err(MError::IncorrectWIT(format!(
"type with idx = {} isn't a function type",
adapter_function_type
))),
}
})
.collect::<MResult<ExportFunctions>>()
} }
// this function deals only with import functions that have an adaptor implementation // this function deals only with import functions that have an adaptor implementation
@ -442,92 +413,4 @@ impl MModule {
Ok(import_object) Ok(import_object)
} }
// TODO : move it to a separate crate
fn extract_export_record_types(
export_funcs: &ExportFunctions,
wit_instance: &Arc<ITInstance>,
) -> MResult<RecordTypes> {
use marine_it_generator::TYPE_RESOLVE_RECURSION_LIMIT;
use MError::RecordResolveError;
fn handle_itype(
itype: &IType,
wit_instance: &Arc<ITInstance>,
export_record_types: &mut RecordTypes,
recursion_level: u32,
) -> MResult<()> {
use wasmer_it::interpreter::wasm::structures::Instance;
if recursion_level > TYPE_RESOLVE_RECURSION_LIMIT {
return Err(RecordResolveError(String::from(
"mailformed module: a record contains more recursion level then allowed",
)));
}
fn handle_record_type(
record_type_id: u64,
wit_instance: &Arc<ITInstance>,
export_record_types: &mut RecordTypes,
recursion_level: u32,
) -> MResult<()> {
let record_type =
wit_instance
.wit_record_by_id(record_type_id)
.ok_or_else(|| {
RecordResolveError(format!(
"record type with type id {} not found",
record_type_id
))
})?;
export_record_types.insert(record_type_id, record_type.clone());
for field in record_type.fields.iter() {
handle_itype(
&field.ty,
wit_instance,
export_record_types,
recursion_level + 1,
)?;
}
Ok(())
}
match itype {
IType::Record(record_type_id) => handle_record_type(
*record_type_id,
wit_instance,
export_record_types,
recursion_level + 1,
)?,
IType::Array(array_ty) => handle_itype(
array_ty,
wit_instance,
export_record_types,
recursion_level + 1,
)?,
_ => {}
}
Ok(())
}
let mut export_record_types = HashMap::new();
let itypes = 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())
});
for itype in itypes {
handle_itype(itype, wit_instance, &mut export_record_types, 0)?;
}
Ok(export_record_types)
}
} }

View File

@ -21,16 +21,26 @@ mod wit_function;
mod wit_instance; mod wit_instance;
mod type_converters; mod type_converters;
pub use wit_instance::RecordTypes; pub use wit_instance::MRecordTypes;
pub use wasmer_it::IType; pub use wasmer_it::IType;
pub use wasmer_it::IRecordType; pub use wasmer_it::IRecordType;
pub use wasmer_it::ast::FunctionArg as IFunctionArg; pub use wasmer_it::ast::FunctionArg as IFunctionArg;
pub use wasmer_it::IValue; pub use wasmer_it::IValue;
pub use marine_module::MFunctionSignature;
pub use wasmer_it::from_interface_values; pub use wasmer_it::from_interface_values;
pub use wasmer_it::to_interface_value; pub use wasmer_it::to_interface_value;
use serde::Serialize;
use serde::Deserialize;
use std::rc::Rc;
/// Represent a function type inside Marine module.
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub struct MFunctionSignature {
pub name: Rc<String>,
pub arguments: Rc<Vec<IFunctionArg>>,
pub outputs: Rc<Vec<IType>>,
}
pub(crate) use marine_module::MModule; pub(crate) use marine_module::MModule;
pub(self) use wasmer_core::types::Type as WType; pub(self) use wasmer_core::types::Type as WType;
pub(self) use wasmer_core::types::Value as WValue; pub(self) use wasmer_core::types::Value as WValue;

View File

@ -29,7 +29,7 @@ use std::collections::HashMap;
use std::cell::Cell; use std::cell::Cell;
use std::rc::Rc; use std::rc::Rc;
pub type RecordTypes = HashMap<u64, Rc<IRecordType>>; pub type MRecordTypes = HashMap<u64, Rc<IRecordType>>;
/// Contains all import and export functions that could be called from IT context by call-core. /// Contains all import and export functions that could be called from IT context by call-core.
#[derive(Clone)] #[derive(Clone)]
@ -41,7 +41,7 @@ pub(super) struct ITInstance {
memories: Vec<WITMemory>, memories: Vec<WITMemory>,
/// All record types that instance contains. /// All record types that instance contains.
record_types_by_id: RecordTypes, record_types_by_id: MRecordTypes,
} }
impl ITInstance { impl ITInstance {
@ -158,7 +158,7 @@ impl ITInstance {
memories memories
} }
fn extract_record_types(wit: &MITInterfaces<'_>) -> RecordTypes { fn extract_record_types(wit: &MITInterfaces<'_>) -> MRecordTypes {
let (record_types_by_id, _) = wit.types().fold( let (record_types_by_id, _) = wit.types().fold(
(HashMap::new(), 0u64), (HashMap::new(), 0u64),
|(mut record_types_by_id, id), ty| { |(mut record_types_by_id, id), ty| {

View File

@ -1,7 +1,7 @@
[package] [package]
name = "marine" name = "marine"
description = "Fluence Marine command line tool" description = "Fluence Marine command line tool"
version = "0.6.2" version = "0.6.3"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
repository = "https://github.com/fluencelabs/marine/tools/cli" repository = "https://github.com/fluencelabs/marine/tools/cli"
license = "Apache-2.0" license = "Apache-2.0"
@ -13,11 +13,12 @@ path = "src/main.rs"
[dependencies] [dependencies]
marine-it-generator = { path = "../../crates/it-generator", version = "0.5.1" } marine-it-generator = { path = "../../crates/it-generator", version = "0.5.1" }
marine-it-parser = { path = "../../crates/it-parser", version = "0.6.0" } marine-it-parser = { path = "../../crates/it-parser", version = "0.6.1" }
marine-module-info-parser = { path = "../../crates/module-info-parser", version = "0.1.0" } marine-module-info-parser = { path = "../../crates/module-info-parser", version = "0.1.0" }
semver = "0.11.0" semver = "0.11.0"
walrus = "0.18.0" walrus = "0.18.0"
Inflector = "0.11.4"
thiserror = "1.0.24" thiserror = "1.0.24"
anyhow = "1.0.31" anyhow = "1.0.31"

View File

@ -23,9 +23,27 @@ pub const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
pub const IN_WASM_PATH: &str = "in-wasm-path"; pub const IN_WASM_PATH: &str = "in-wasm-path";
pub const IT_PATH: &str = "it-path"; pub const IT_PATH: &str = "it-path";
pub const OUT_WASM_PATH: &str = "out-wasm-path"; pub const OUT_WASM_PATH: &str = "out-wasm-path";
pub const SERVICE_NAME: &str = "service-name";
pub const SDK_VERSION: &str = "sdk-version"; pub const SDK_VERSION: &str = "sdk-version";
pub fn aqua<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("aqua")
.about("Shows data types of provided module in a format suitable for Aqua")
.args(&[
Arg::with_name(IN_WASM_PATH)
.required(true)
.takes_value(true)
.index(1)
.help("a path to a Wasm file"),
Arg::with_name(SERVICE_NAME)
.required(false)
.takes_value(true)
.short("s")
.help("optional service name"),
])
}
pub fn build<'a, 'b>() -> App<'a, 'b> { pub fn build<'a, 'b>() -> App<'a, 'b> {
SubCommand::with_name("build") SubCommand::with_name("build")
.about("Builds provided Rust project to Wasm") .about("Builds provided Rust project to Wasm")

View File

@ -25,13 +25,13 @@
unreachable_patterns unreachable_patterns
)] )]
use marine_module_info_parser::manifest;
use marine_module_info_parser::sdk_version;
mod args; mod args;
mod build; mod build;
mod errors; mod errors;
use marine_module_info_parser::manifest;
use marine_module_info_parser::sdk_version;
pub(crate) type CLIResult<T> = std::result::Result<T, crate::errors::CLIError>; pub(crate) type CLIResult<T> = std::result::Result<T, crate::errors::CLIError>;
pub fn main() -> Result<(), anyhow::Error> { pub fn main() -> Result<(), anyhow::Error> {
@ -39,6 +39,7 @@ pub fn main() -> Result<(), anyhow::Error> {
.version(args::VERSION) .version(args::VERSION)
.author(args::AUTHORS) .author(args::AUTHORS)
.setting(clap::AppSettings::ArgRequiredElseHelp) .setting(clap::AppSettings::ArgRequiredElseHelp)
.subcommand(args::aqua())
.subcommand(args::build()) .subcommand(args::build())
.subcommand(args::set()) .subcommand(args::set())
.subcommand(args::show_manifest()) .subcommand(args::show_manifest())
@ -47,6 +48,7 @@ pub fn main() -> Result<(), anyhow::Error> {
let arg_matches = app.get_matches(); let arg_matches = app.get_matches();
match arg_matches.subcommand() { match arg_matches.subcommand() {
("aqua", Some(args)) => aqua(args),
("build", Some(args)) => build(args), ("build", Some(args)) => build(args),
("set", Some(args)) => set(args), ("set", Some(args)) => set(args),
("it", Some(args)) => it(args), ("it", Some(args)) => it(args),
@ -76,6 +78,36 @@ pub fn main() -> Result<(), anyhow::Error> {
Ok(()) Ok(())
} }
fn aqua(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> {
use inflector::Inflector;
let wasm_path = args.value_of(args::IN_WASM_PATH).unwrap();
let wasm_path = std::path::Path::new(wasm_path);
let module_interface = marine_it_parser::module_interface(wasm_path)?;
for record in module_interface.record_types.iter() {
println!("{}", record);
}
match args.value_of(args::SERVICE_NAME) {
Some(service_name) => println!("service {}:", service_name.to_title_case()),
None => {
let service_name = wasm_path
.file_stem()
.ok_or(anyhow::Error::msg("provided path isn't a path to a file"))?;
let service_name = service_name.to_string_lossy().to_title_case();
println!("service {}:", service_name);
}
}
for sign in module_interface.function_signatures {
println!(" {}", sign);
}
Ok(())
}
fn build(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> { fn build(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> {
let trailing_args: Vec<&str> = args.values_of("optional").unwrap_or_default().collect(); let trailing_args: Vec<&str> = args.values_of("optional").unwrap_or_default().collect();

View File

@ -1,7 +1,7 @@
[package] [package]
name = "mrepl" name = "mrepl"
description = "Fluence Marine REPL intended for testing purposes" description = "Fluence Marine REPL intended for testing purposes"
version = "0.7.2" version = "0.7.3"
authors = ["Fluence Labs"] authors = ["Fluence Labs"]
repository = "https://github.com/fluencelabs/marine/tools/repl" repository = "https://github.com/fluencelabs/marine/tools/repl"
license = "Apache-2.0" license = "Apache-2.0"
@ -12,7 +12,7 @@ name = "mrepl"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
fluence-app-service = { path = "../../fluence-app-service", version = "0.7.1", features = ["raw-module-api"] } fluence-app-service = { path = "../../fluence-app-service", version = "0.7.2", features = ["raw-module-api"] }
fluence-sdk-main = { version = "0.6.9", features = ["logger"] } fluence-sdk-main = { version = "0.6.9", features = ["logger"] }
anyhow = "1.0.31" anyhow = "1.0.31"