diff --git a/Cargo.toml b/Cargo.toml index a6d8d2a..7841011 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence" -version = "0.4.2" # remember to update html_root_url +version = "0.4.3" # remember to update html_root_url description = "Fluence backend SDK for developing backend applications for the Fluence network" documentation = "https://docs.rs/fluence/" repository = "https://github.com/fluencelabs/rust-sdk" @@ -18,8 +18,8 @@ all-features = true path = "src/lib.rs" [dependencies] -fluence-sdk-macro = { path = "crates/macro", version = "=0.4.2" } -fluence-sdk-main = { path = "crates/main", version = "=0.4.2" } +fluence-sdk-macro = { path = "crates/macro", version = "=0.4.3" } +fluence-sdk-main = { path = "crates/main", version = "=0.4.3" } [features] # Print some internal logs by log_utf8_string diff --git a/crates/macro/Cargo.toml b/crates/macro/Cargo.toml index 615b031..65c9efb 100644 --- a/crates/macro/Cargo.toml +++ b/crates/macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence-sdk-macro" -version = "0.4.2" # remember to update html_root_url +version = "0.4.3" # remember to update html_root_url edition = "2018" description = "Definition of `#[invoke_handler]` attribute" documentation = "https://docs.rs/fluence/fluence-sdk-macro" @@ -17,4 +17,4 @@ all-features = true proc-macro = true [dependencies] -fluence-sdk-wit = { path = "../wit", version = "=0.4.2" } +fluence-sdk-wit = { path = "../wit", version = "=0.4.3" } diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs index 68e3075..b512682 100644 --- a/crates/macro/src/lib.rs +++ b/crates/macro/src/lib.rs @@ -54,7 +54,7 @@ //! //! ``` -#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.2")] +#![doc(html_root_url = "https://docs.rs/fluence-sdk-macro/0.4.3")] #![deny( dead_code, nonstandard_style, diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index 10b00ef..e328d25 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence-sdk-main" -version = "0.4.2" # remember to update html_root_url +version = "0.4.3" # remember to update html_root_url edition = "2018" description = "Rust SDK for applications for the Fluence network" documentation = "https://docs.rs/fluence/fluence-sdk-macro" @@ -18,7 +18,7 @@ path = "src/lib.rs" crate-type = ["rlib"] [dependencies] -fluence-sdk-macro = { path = "../macro", version = "=0.4.2" } +fluence-sdk-macro = { path = "../macro", version = "=0.4.3" } log = { version = "0.4.8", features = ["std"] } serde = "=1.0.118" diff --git a/crates/main/src/lib.rs b/crates/main/src/lib.rs index 41ce22e..c21cba0 100644 --- a/crates/main/src/lib.rs +++ b/crates/main/src/lib.rs @@ -19,7 +19,7 @@ #![allow(clippy::missing_safety_doc)] #![allow(clippy::needless_doctest_main)] -#![doc(html_root_url = "https://docs.rs/fluence-sdk-main/0.4.2")] +#![doc(html_root_url = "https://docs.rs/fluence-sdk-main/0.4.3")] #![deny( dead_code, nonstandard_style, @@ -35,7 +35,8 @@ mod call_parameters; mod export_allocator; #[cfg(any(feature = "debug", feature = "logger"))] mod logger; -pub mod mounted_binary; +mod mounted_binary; + mod result; pub use call_parameters::CallParameters; @@ -58,6 +59,11 @@ pub use result::get_result_size; pub use result::set_result_ptr; pub use result::set_result_size; +pub use mounted_binary::MountedBinaryResult; +pub use mounted_binary::MountedBinaryStringResult; +pub use mounted_binary::BINARY_SUCCESS_CODE; +pub use mounted_binary::RawMountedBinaryResult; + #[allow(unused_variables)] pub(crate) fn log>(msg: S) { // logs will be printed only if debug feature is enabled diff --git a/crates/main/src/mounted_binary.rs b/crates/main/src/mounted_binary.rs index 8fbe3d3..85e3834 100644 --- a/crates/main/src/mounted_binary.rs +++ b/crates/main/src/mounted_binary.rs @@ -19,18 +19,14 @@ use fluence_sdk_macro::fce; use serde::Serialize; use serde::Deserialize; -pub const SUCCESS_CODE: i32 = 0; +pub const BINARY_SUCCESS_CODE: i32 = 0; -/// Describes result of calling a CLI service. -#[fce] +/// Describes the result of calling a CLI service. #[derive(Clone, PartialEq, Default, Eq, Debug, Serialize, Deserialize)] -pub struct Result { +pub struct MountedBinaryResult { /// Return process exit code or host execution error code, where SUCCESS_CODE means success. pub ret_code: i32, - /// Contains the string representation of an error, if ret_code != SUCCESS_CODE. - pub error: String, - /// The data that the process wrote to stdout. pub stdout: Vec, @@ -38,16 +34,19 @@ pub struct Result { pub stderr: Vec, } +/// Describes the error of calling a CLI service. +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub enum MountedBinaryError { + KilledBySignal, + LaunchError(String), +} + /// The same as the Result, but stdout and stderr are utf8 strings. -#[fce] #[derive(Clone, PartialEq, Default, Eq, Debug, Serialize, Deserialize)] -pub struct StringResult { +pub struct MountedBinaryStringResult { /// Return process exit code or host execution error code, where SUCCESS_CODE means success. pub ret_code: i32, - /// Contains the string representation of an error, if ret_code != SUCCESS_CODE. - pub error: String, - /// The data that the process wrote to stdout. pub stdout: String, @@ -55,20 +54,19 @@ pub struct StringResult { pub stderr: String, } -impl Result { - /// Create a new failure MountedBinaryResult from the provided ret_code. - pub fn from_error(ret_code: i32, error: impl Into) -> Self { +impl MountedBinaryResult { + /// Create a new MountedBinaryResult from the provided ret_code. + pub fn new(ret_code: i32, stdout: Vec, stderr: Vec) -> Self { Self { ret_code, - error: error.into(), - stdout: Vec::new(), - stderr: Vec::new(), + stdout, + stderr, } } /// Return true, if this Result represents a success result, otherwise false. pub fn is_success(&self) -> bool { - self.ret_code == SUCCESS_CODE + self.ret_code == BINARY_SUCCESS_CODE } /// This function tries to transform a result to the string representation. @@ -76,12 +74,12 @@ impl Result { /// or Some(Err(error)) otherwise. None is returned if stdout or stderr contains non valid /// UTF8 string. pub fn into_std(self) -> Option> { - if self.ret_code == SUCCESS_CODE { + if self.ret_code == BINARY_SUCCESS_CODE { let stdout = String::from_utf8(self.stdout).ok()?; Some(Ok(stdout)) } else { - let stderr = std::str::from_utf8(&self.stderr).ok()?; - Some(Ok(format!("error: {}, stderr: {}", self.error, stderr))) + let stderr = String::from_utf8(self.stderr).ok()?; + Some(Ok(stderr)) } } @@ -90,13 +88,7 @@ impl Result { /// or Some(Err(error)) otherwise. None is returned if stdout or stderr contains non valid /// UTF8 string. pub fn as_std(&self) -> Option> { - if self.ret_code == SUCCESS_CODE { - let stdout = String::from_utf8(self.stdout.clone()).ok()?; - Some(Ok(stdout)) - } else { - let stderr = std::str::from_utf8(&self.stderr).ok()?; - Some(Ok(format!("error: {}, stderr: {}", self.error, stderr))) - } + self.clone().into_std() } pub fn stringify(&self) -> Option { @@ -105,7 +97,6 @@ impl Result { let string_result = StringResult { ret_code: self.ret_code, - error: self.error.clone(), stdout, stderr, }; @@ -113,3 +104,28 @@ impl Result { Some(string_result) } } + +/// This structure is intended for internal usage only. It passed from FCE to sdk and then converts +/// to handy Result. +pub struct RawMountedBinaryResult { + pub ret_code: i32, + pub stdout: Vec, + pub stderr: Vec, + pub killed_by_signal: bool, + pub error: String, +} + +impl From for Result { + fn from(result: RawMountedBinaryResult) -> Self { + if !result.error.is_empty() { + return Err(MountedBinaryError::LaunchError(result.error)); + } + + if result.killed_by_signal { + return Err(MountedBinaryError::KilledBySignal); + } + + let ok_result = MountedBinaryResult::new(result.ret_code, result.stdout, result.stderr); + Ok(ok_result) + } +} diff --git a/crates/wit/Cargo.toml b/crates/wit/Cargo.toml index 9bef5a1..cc14774 100644 --- a/crates/wit/Cargo.toml +++ b/crates/wit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fluence-sdk-wit" -version = "0.4.2" # remember to update html_root_url +version = "0.4.3" # remember to update html_root_url edition = "2018" description = "Webassembly interface-types generator" documentation = "https://docs.rs/fluence/fluence-sdk-macro" diff --git a/crates/wit/src/fce_ast_types.rs b/crates/wit/src/fce_ast_types.rs index 6b32376..3087a29 100644 --- a/crates/wit/src/fce_ast_types.rs +++ b/crates/wit/src/fce_ast_types.rs @@ -76,10 +76,21 @@ pub struct AstFunctionItem { pub original: Option, } +pub struct AstExternHostItem { + // only imports are possible here + pub imports: Vec, + + // Option is needed only for skipping serialization/deserialization of syn::ItemFn + #[serde(skip)] + pub original: Option, +} + +// TODO: introduce special "export" version of Ast types without Option #[derive(Clone, Serialize, Deserialize)] #[serde(tag = "ast_type")] pub enum FCEAst { Function(AstFunctionItem), ExternMod(AstExternModItem), + ExternHostMod(AstExternHostItem), Record(AstRecordItem), } diff --git a/crates/wit/src/lib.rs b/crates/wit/src/lib.rs index 22e193a..64ab040 100644 --- a/crates/wit/src/lib.rs +++ b/crates/wit/src/lib.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -#![doc(html_root_url = "https://docs.rs/wit-support/0.4.2")] +#![doc(html_root_url = "https://docs.rs/wit-support/0.4.3")] #![deny( dead_code, nonstandard_style, diff --git a/crates/wit/src/parse_macro_input/item_foreign_mod.rs b/crates/wit/src/parse_macro_input/item_foreign_mod.rs index c07b4c5..d567a0b 100644 --- a/crates/wit/src/parse_macro_input/item_foreign_mod.rs +++ b/crates/wit/src/parse_macro_input/item_foreign_mod.rs @@ -16,6 +16,7 @@ use super::ParseMacroInput; use crate::fce_ast_types; +use crate::ParsedType; use crate::fce_ast_types::FCEAst; use syn::Error; @@ -73,6 +74,15 @@ impl ParseMacroInput for syn::ItemForeignMod { self_span, "import module name should be defined by 'wasm_import_module' directive", )), + Some(namespace) if namespace == "host" => { + check_host_item(&imports)?; + let imports = imports.into_iter().map(|i| i.signature.name).collect::>(); + let extern_mod_item = fce_ast_types::AstExternHostItem { + imports, + original: Some(self), + }; + Ok(FCEAst::ExternHostMod(extern_mod_item)) + } Some(namespace) => { let extern_mod_item = fce_ast_types::AstExternModItem { namespace, @@ -135,3 +145,30 @@ fn extract_value(nested_meta: syn::Meta) -> Option { _ => None, } } + +fn check_host_item(imports: &[fce_ast_types::AstExternFnItem], span: proc_macro2::Span) -> Result<()> { + for import in imports { + check_host_arguments(&import.signature.arguments)?; + check_host_output(&import.signature.output_type)?; + } + + Ok(()) +} + +fn check_host_arguments(args: &Vec<(String, ParsedType)>, span: proc_macro2::Span) -> Result<()> { + if args.len() != 1 || args[0].1 != ParsedType::Vector(Box::new(ParsedType::String)) { + return Err(Error::new( + span(), + "functions from the host namespace must have only one argument of Vec type", + )) + } + + Ok(()) +} + +fn check_host_output(output: &Option, span: proc_macro2::Span) -> Result<()> { + match output { + Some(output) => if + } +} + diff --git a/src/lib.rs b/src/lib.rs index 6d5250b..ffdfd59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ //! pub fn curl_get(url: String) -> String; //! } //! ``` -#![doc(html_root_url = "https://docs.rs/fluence/0.4.2")] +#![doc(html_root_url = "https://docs.rs/fluence/0.4.3")] #![deny( dead_code, nonstandard_style, @@ -79,15 +79,17 @@ pub use fluence_sdk_main::WasmLoggerBuilder; #[cfg(feature = "logger")] pub use fluence_sdk_main::TargetMap; -pub use fluence_sdk_main::mounted_binary::Result as MountedBinaryResult; -pub use fluence_sdk_main::mounted_binary::StringResult as MountedBinaryStringResult; -pub use fluence_sdk_main::mounted_binary::SUCCESS_CODE as BINARY_SUCCESS_CODE; +pub use fluence_sdk_main::MountedBinaryResult; +pub use fluence_sdk_main::MountedBinaryError; +pub use fluence_sdk_main::MountedBinaryStringResult; +pub use fluence_sdk_main::BINARY_SUCCESS_CODE; -/// These API functions are intended for internal usage in generated code. +/// These API functions and structures are intended for internal usage in generated code. /// Normally, you shouldn't use them. pub mod internal { pub use fluence_sdk_main::get_result_ptr; pub use fluence_sdk_main::get_result_size; pub use fluence_sdk_main::set_result_ptr; pub use fluence_sdk_main::set_result_size; + pub use fluence_sdk_main::RawMountedBinaryResult; }