mirror of
https://github.com/fluencelabs/marine.git
synced 2025-06-27 13:41:36 +00:00
Introduce module interface cache (#40)
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -652,6 +652,7 @@ version = "0.1.10"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"boolinator",
|
"boolinator",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"fce-utils",
|
||||||
"fce-wit-interfaces",
|
"fce-wit-interfaces",
|
||||||
"fce-wit-parser",
|
"fce-wit-parser",
|
||||||
"log",
|
"log",
|
||||||
@ -679,6 +680,10 @@ dependencies = [
|
|||||||
"fluence 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fluence 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fce-utils"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fce-wit-generator"
|
name = "fce-wit-generator"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
@ -764,6 +769,7 @@ dependencies = [
|
|||||||
"cmd_lib",
|
"cmd_lib",
|
||||||
"env_logger 0.7.1",
|
"env_logger 0.7.1",
|
||||||
"fce",
|
"fce",
|
||||||
|
"fce-utils",
|
||||||
"fluence-sdk-main 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fluence-sdk-main 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools",
|
"itertools",
|
||||||
"log",
|
"log",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"aquamarine-vm",
|
"aquamarine-vm",
|
||||||
|
"crates/utils",
|
||||||
"crates/wit-generator",
|
"crates/wit-generator",
|
||||||
"crates/wit-interfaces",
|
"crates/wit-interfaces",
|
||||||
"crates/wit-parser",
|
"crates/wit-parser",
|
||||||
|
11
crates/utils/Cargo.toml
Normal file
11
crates/utils/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "fce-utils"
|
||||||
|
description = "Fluence FCE utils crate"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Fluence Labs"]
|
||||||
|
license = "Apache-2.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "fce_utils"
|
||||||
|
path = "src/lib.rs"
|
36
crates/utils/src/lib.rs
Normal file
36
crates/utils/src/lib.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Fluence Labs Limited
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#![warn(rust_2018_idioms)]
|
||||||
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
nonstandard_style,
|
||||||
|
unused_imports,
|
||||||
|
unused_mut,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
|
||||||
|
pub struct SharedString(pub Rc<String>);
|
||||||
|
|
||||||
|
impl std::borrow::Borrow<str> for SharedString {
|
||||||
|
fn borrow(&self) -> &str {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
}
|
@ -24,7 +24,7 @@ use fluence_sdk_wit::RustType;
|
|||||||
// return error if there is no record with such name
|
// return error if there is no record with such name
|
||||||
pub(crate) fn ptype_to_itype_checked(
|
pub(crate) fn ptype_to_itype_checked(
|
||||||
pty: &ParsedType,
|
pty: &ParsedType,
|
||||||
wit_resolver: &mut WITResolver,
|
wit_resolver: &mut WITResolver<'_>,
|
||||||
) -> Result<IType> {
|
) -> Result<IType> {
|
||||||
match pty {
|
match pty {
|
||||||
ParsedType::I8 => Ok(IType::S8),
|
ParsedType::I8 => Ok(IType::S8),
|
||||||
@ -50,7 +50,10 @@ pub(crate) fn ptype_to_itype_checked(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn ptype_to_itype_unchecked(pty: &ParsedType, wit_resolver: &mut WITResolver) -> IType {
|
pub(crate) fn ptype_to_itype_unchecked(
|
||||||
|
pty: &ParsedType,
|
||||||
|
wit_resolver: &mut WITResolver<'_>,
|
||||||
|
) -> IType {
|
||||||
match pty {
|
match pty {
|
||||||
ParsedType::I8 => IType::S8,
|
ParsedType::I8 => IType::S8,
|
||||||
ParsedType::I16 => IType::S16,
|
ParsedType::I16 => IType::S16,
|
||||||
|
@ -96,7 +96,7 @@ fn generate_interfaces(module_ast: &ModuleAST) -> Result<Interfaces<'_>> {
|
|||||||
Ok(wit_resolver.interfaces)
|
Ok(wit_resolver.interfaces)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_default_export_api(interfaces: &mut Interfaces) {
|
fn generate_default_export_api(interfaces: &mut Interfaces<'_>) {
|
||||||
// TODO: the order is matter
|
// TODO: the order is matter
|
||||||
ALLOCATE_FUNC.update_interfaces(interfaces);
|
ALLOCATE_FUNC.update_interfaces(interfaces);
|
||||||
DEALLOCATE_FUNC.update_interfaces(interfaces);
|
DEALLOCATE_FUNC.update_interfaces(interfaces);
|
||||||
@ -106,13 +106,13 @@ fn generate_default_export_api(interfaces: &mut Interfaces) {
|
|||||||
SET_RESULT_PTR_FUNC.update_interfaces(interfaces);
|
SET_RESULT_PTR_FUNC.update_interfaces(interfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_records(wit_resolver: &WITResolver) -> Result<()> {
|
fn validate_records(wit_resolver: &WITResolver<'_>) -> Result<()> {
|
||||||
const TYPE_RESOLVE_RECURSION_LIMIT: u32 = 1024;
|
const TYPE_RESOLVE_RECURSION_LIMIT: u32 = 1024;
|
||||||
|
|
||||||
fn validate_record_type(
|
fn validate_record_type(
|
||||||
record_type: &wasmer_wit::types::RecordType,
|
record_type: &wasmer_wit::types::RecordType,
|
||||||
recursion_level: u32,
|
recursion_level: u32,
|
||||||
wit_resolver: &WITResolver,
|
wit_resolver: &WITResolver<'_>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if recursion_level >= TYPE_RESOLVE_RECURSION_LIMIT {
|
if recursion_level >= TYPE_RESOLVE_RECURSION_LIMIT {
|
||||||
return Err(WITGeneratorError::CorruptedRecord(String::from(
|
return Err(WITGeneratorError::CorruptedRecord(String::from(
|
||||||
|
@ -14,6 +14,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#![warn(rust_2018_idioms)]
|
||||||
|
#![deny(
|
||||||
|
dead_code,
|
||||||
|
nonstandard_style,
|
||||||
|
unused_imports,
|
||||||
|
unused_mut,
|
||||||
|
unused_variables,
|
||||||
|
unused_unsafe,
|
||||||
|
unreachable_patterns
|
||||||
|
)]
|
||||||
|
|
||||||
mod default_export_api_config;
|
mod default_export_api_config;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod instructions_generator;
|
mod instructions_generator;
|
||||||
|
@ -13,6 +13,7 @@ path = "src/lib.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
fce-wit-interfaces = { path = "../crates/wit-interfaces", version = "0.1.7" }
|
fce-wit-interfaces = { path = "../crates/wit-interfaces", version = "0.1.7" }
|
||||||
fce-wit-parser = { path = "../crates/wit-parser", version = "0.1.9" }
|
fce-wit-parser = { path = "../crates/wit-parser", version = "0.1.9" }
|
||||||
|
fce-utils = { path = "../crates/utils", version = "0.1.0" }
|
||||||
|
|
||||||
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }
|
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }
|
||||||
# dynamicfunc-fat-closures allows using state inside DynamicFunc
|
# dynamicfunc-fat-closures allows using state inside DynamicFunc
|
||||||
|
@ -22,6 +22,7 @@ use crate::FCEModuleConfig;
|
|||||||
|
|
||||||
use fce_wit_interfaces::FCEWITInterfaces;
|
use fce_wit_interfaces::FCEWITInterfaces;
|
||||||
use fce_wit_parser::extract_wit;
|
use fce_wit_parser::extract_wit;
|
||||||
|
use fce_utils::SharedString;
|
||||||
use wasmer_core::Instance as WasmerInstance;
|
use wasmer_core::Instance as WasmerInstance;
|
||||||
use wasmer_core::import::Namespace;
|
use wasmer_core::import::Namespace;
|
||||||
use wasmer_runtime::compile;
|
use wasmer_runtime::compile;
|
||||||
@ -73,15 +74,6 @@ impl Callable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
|
|
||||||
struct SharedString(pub Rc<String>);
|
|
||||||
|
|
||||||
impl std::borrow::Borrow<str> for SharedString {
|
|
||||||
fn borrow(&self) -> &str {
|
|
||||||
self.0.as_str()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExportFunctions = HashMap<SharedString, Rc<Callable>>;
|
type ExportFunctions = HashMap<SharedString, Rc<Callable>>;
|
||||||
|
|
||||||
pub(crate) struct FCEModule {
|
pub(crate) struct FCEModule {
|
||||||
|
@ -8,6 +8,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fce = { path = "../engine", version = "0.1.10" }
|
fce = { path = "../engine", version = "0.1.10" }
|
||||||
|
fce-utils = { path = "../crates/utils", version = "0.1.0" }
|
||||||
fluence-sdk-main = "=0.2.8"
|
fluence-sdk-main = "=0.2.8"
|
||||||
|
|
||||||
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }
|
wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" }
|
||||||
|
@ -19,10 +19,14 @@ use crate::faas_interface::FaaSInterface;
|
|||||||
use crate::FaaSError;
|
use crate::FaaSError;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::IValue;
|
use crate::IValue;
|
||||||
|
use crate::IType;
|
||||||
use crate::misc::load_modules_from_fs;
|
use crate::misc::load_modules_from_fs;
|
||||||
use crate::misc::ModulesLoadStrategy;
|
use crate::misc::ModulesLoadStrategy;
|
||||||
|
|
||||||
use fce::FCE;
|
use fce::FCE;
|
||||||
|
use fce::IFunctionArg;
|
||||||
|
use fce_utils::SharedString;
|
||||||
|
use fce::RecordTypes;
|
||||||
use fluence_sdk_main::CallParameters;
|
use fluence_sdk_main::CallParameters;
|
||||||
|
|
||||||
use serde_json::Value as JValue;
|
use serde_json::Value as JValue;
|
||||||
@ -33,6 +37,11 @@ use std::collections::HashMap;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
struct ModuleInterface {
|
||||||
|
function_signatures: HashMap<SharedString, (Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>)>,
|
||||||
|
record_types: Rc<RecordTypes>,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: remove and use mutex instead
|
// TODO: remove and use mutex instead
|
||||||
unsafe impl Send for FluenceFaaS {}
|
unsafe impl Send for FluenceFaaS {}
|
||||||
|
|
||||||
@ -42,6 +51,9 @@ pub struct FluenceFaaS {
|
|||||||
|
|
||||||
/// Parameters of call accessible by Wasm modules.
|
/// Parameters of call accessible by Wasm modules.
|
||||||
call_parameters: Rc<RefCell<CallParameters>>,
|
call_parameters: Rc<RefCell<CallParameters>>,
|
||||||
|
|
||||||
|
/// Cached module interfaces by names.
|
||||||
|
module_interfaces_cache: HashMap<String, ModuleInterface>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FluenceFaaS {
|
impl FluenceFaaS {
|
||||||
@ -99,6 +111,7 @@ impl FluenceFaaS {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
fce,
|
fce,
|
||||||
call_parameters,
|
call_parameters,
|
||||||
|
module_interfaces_cache: HashMap::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,27 +161,18 @@ impl FluenceFaaS {
|
|||||||
let module_name = module_name.as_ref();
|
let module_name = module_name.as_ref();
|
||||||
let func_name = func_name.as_ref();
|
let func_name = func_name.as_ref();
|
||||||
|
|
||||||
// TODO: cache module interface
|
let (func_signature, output_types, record_types) =
|
||||||
let module_interface = self
|
self.lookup_module_interface(module_name, func_name)?;
|
||||||
.fce
|
let iargs = json_to_ivalues(
|
||||||
.module_interface(module_name)
|
json_args,
|
||||||
.ok_or_else(|| FaaSError::NoSuchModule(module_name.to_string()))?;
|
func_signature.iter().map(|arg| (&arg.name, &arg.ty)),
|
||||||
|
&record_types,
|
||||||
let func_signature = module_interface
|
)?;
|
||||||
.function_signatures
|
|
||||||
.iter()
|
|
||||||
.find(|sign| sign.name.as_str() == func_name)
|
|
||||||
.ok_or_else(|| FaaSError::MissingFunctionError(func_name.to_string()))?;
|
|
||||||
|
|
||||||
let record_types = module_interface.record_types.clone();
|
|
||||||
|
|
||||||
let iargs = json_to_ivalues(json_args, func_signature, &record_types)?;
|
|
||||||
let outputs = func_signature.outputs.clone();
|
|
||||||
|
|
||||||
self.call_parameters.replace(call_parameters);
|
self.call_parameters.replace(call_parameters);
|
||||||
let result = self.fce.call(module_name, func_name, &iargs)?;
|
let result = self.fce.call(module_name, func_name, &iargs)?;
|
||||||
|
|
||||||
ivalues_to_json(result, &outputs, &record_types)
|
ivalues_to_json(result, &output_types, &record_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return all export functions (name and signatures) of loaded modules.
|
/// Return all export functions (name and signatures) of loaded modules.
|
||||||
@ -177,6 +181,59 @@ impl FluenceFaaS {
|
|||||||
|
|
||||||
FaaSInterface { modules }
|
FaaSInterface { modules }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// At first, tries to find function signature and record types in module_interface_cache,
|
||||||
|
/// if there is no them, tries to look
|
||||||
|
fn lookup_module_interface<'faas>(
|
||||||
|
&'faas mut self,
|
||||||
|
module_name: &str,
|
||||||
|
func_name: &str,
|
||||||
|
) -> Result<(Rc<Vec<IFunctionArg>>, Rc<Vec<IType>>, Rc<RecordTypes>)> {
|
||||||
|
use FaaSError::NoSuchModule;
|
||||||
|
use FaaSError::MissingFunctionError;
|
||||||
|
|
||||||
|
if let Some(module_interface) = self.module_interfaces_cache.get(module_name) {
|
||||||
|
if let Some(function) = module_interface.function_signatures.get(func_name) {
|
||||||
|
return Ok((
|
||||||
|
function.0.clone(),
|
||||||
|
function.1.clone(),
|
||||||
|
module_interface.record_types.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(MissingFunctionError(func_name.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let module_interface = self
|
||||||
|
.fce
|
||||||
|
.module_interface(module_name)
|
||||||
|
.ok_or_else(|| NoSuchModule(module_name.to_string()))?;
|
||||||
|
|
||||||
|
let function_signatures = module_interface
|
||||||
|
.function_signatures
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|f| (SharedString(f.name), (f.arguments, f.outputs)))
|
||||||
|
.collect::<HashMap<_, _>>();
|
||||||
|
|
||||||
|
let (arg_types, output_types) = function_signatures
|
||||||
|
.get(func_name)
|
||||||
|
.ok_or_else(|| MissingFunctionError(func_name.to_string()))?;
|
||||||
|
|
||||||
|
let arg_types = arg_types.clone();
|
||||||
|
let output_types = output_types.clone();
|
||||||
|
let record_types = Rc::new(module_interface.record_types.clone());
|
||||||
|
|
||||||
|
let module_interface = ModuleInterface {
|
||||||
|
function_signatures,
|
||||||
|
record_types: record_types.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.module_interfaces_cache
|
||||||
|
.insert(func_name.to_string(), module_interface);
|
||||||
|
|
||||||
|
Ok((arg_types, output_types, record_types))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This API is intended for testing purposes (mostly in FCE REPL)
|
// This API is intended for testing purposes (mostly in FCE REPL)
|
||||||
|
@ -24,47 +24,39 @@ use serde_json::Value as JValue;
|
|||||||
use wasmer_wit::vec1::Vec1;
|
use wasmer_wit::vec1::Vec1;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::iter::ExactSizeIterator;
|
||||||
|
|
||||||
pub(crate) fn json_to_ivalues(
|
/// Convert json to an array of ivalues according to the supplied argument types.
|
||||||
|
pub(crate) fn json_to_ivalues<'a, 'b>(
|
||||||
json_args: JValue,
|
json_args: JValue,
|
||||||
func_signature: &crate::FaaSFunctionSignature,
|
arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
|
||||||
record_types: &RecordTypes,
|
record_types: &'b RecordTypes,
|
||||||
) -> Result<Vec<IValue>> {
|
) -> Result<Vec<IValue>> {
|
||||||
let ivalues = match json_args {
|
let ivalues = match json_args {
|
||||||
JValue::Object(json_map) => json_map_to_ivalues(
|
JValue::Object(json_map) => json_map_to_ivalues(json_map, arg_types, &record_types)?,
|
||||||
json_map,
|
JValue::Array(json_array) => {
|
||||||
func_signature
|
json_array_to_ivalues(json_array, arg_types.map(|arg| arg.1), &record_types)?
|
||||||
.arguments
|
}
|
||||||
.iter()
|
JValue::Null => json_null_to_ivalue(arg_types)?,
|
||||||
.map(|arg| (&arg.name, &arg.ty)),
|
json_value => json_value_to_ivalue(json_value, arg_types)?,
|
||||||
&record_types,
|
|
||||||
)?,
|
|
||||||
JValue::Array(json_array) => json_array_to_ivalues(
|
|
||||||
json_array,
|
|
||||||
func_signature.arguments.iter().map(|arg| &arg.ty),
|
|
||||||
&record_types,
|
|
||||||
)?,
|
|
||||||
JValue::String(json_string) => json_string_to_ivalue(json_string, func_signature)?,
|
|
||||||
json_bool @ JValue::Bool(_) => json_bool_to_ivalue(json_bool, func_signature)?,
|
|
||||||
json_number @ JValue::Number(_) => json_number_to_ivalue(json_number, func_signature)?,
|
|
||||||
JValue::Null => json_null_to_ivalue(func_signature)?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ivalues)
|
Ok(ivalues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert json map to an array of ivalues according to the supplied argument types.
|
||||||
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>,
|
||||||
signature: impl Iterator<Item = (&'a String, &'a IType)>,
|
arg_types: impl Iterator<Item = (&'a String, &'a IType)>,
|
||||||
record_types: &'b RecordTypes,
|
record_types: &'b RecordTypes,
|
||||||
) -> Result<Vec<IValue>> {
|
) -> Result<Vec<IValue>> {
|
||||||
let mut iargs = Vec::new();
|
let mut iargs = Vec::new();
|
||||||
|
|
||||||
for (arg_name, arg_type) in signature {
|
for (arg_name, arg_type) in arg_types {
|
||||||
let json_value = json_map
|
let json_value = json_map
|
||||||
.remove(arg_name)
|
.remove(arg_name)
|
||||||
.ok_or_else(|| ArgDeError(format!("missing argument with name {}", arg_name)))?;
|
.ok_or_else(|| ArgDeError(format!("missing argument with name {}", arg_name)))?;
|
||||||
let iarg = json_value_to_ivalue(json_value, arg_type, record_types)?;
|
let iarg = jvalue_to_ivalue(json_value, arg_type, record_types)?;
|
||||||
iargs.push(iarg);
|
iargs.push(iarg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,97 +71,61 @@ fn json_map_to_ivalues<'a, 'b>(
|
|||||||
Ok(iargs)
|
Ok(iargs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert json array to an array of ivalues according to the supplied argument types.
|
||||||
fn json_array_to_ivalues<'a, 'b>(
|
fn json_array_to_ivalues<'a, 'b>(
|
||||||
mut json_array: Vec<JValue>,
|
json_array: Vec<JValue>,
|
||||||
signature: impl Iterator<Item = &'a IType> + std::iter::ExactSizeIterator,
|
arg_types: impl Iterator<Item = &'a IType> + ExactSizeIterator,
|
||||||
record_types: &'b RecordTypes,
|
record_types: &'b RecordTypes,
|
||||||
) -> Result<Vec<IValue>> {
|
) -> Result<Vec<IValue>> {
|
||||||
if json_array.len() != signature.len() {
|
if json_array.len() != arg_types.len() {
|
||||||
return Err(ArgDeError(format!(
|
return Err(ArgDeError(format!(
|
||||||
"function requires {} arguments, {} provided",
|
"function requires {} arguments, {} provided",
|
||||||
signature.len(),
|
arg_types.len(),
|
||||||
json_array.len()
|
json_array.len()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut iargs = Vec::with_capacity(signature.len());
|
let iargs = json_array
|
||||||
|
.into_iter()
|
||||||
for arg_type in signature {
|
.zip(arg_types)
|
||||||
// remove here is safe because we've already checked sizes
|
.map(|(json_value, arg_type)| jvalue_to_ivalue(json_value, arg_type, record_types))
|
||||||
let json_value = json_array.remove(0);
|
.collect::<Result<Vec<_>>>()?;
|
||||||
let iarg = json_value_to_ivalue(json_value, arg_type, record_types)?;
|
|
||||||
iargs.push(iarg);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(iargs)
|
Ok(iargs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_string_to_ivalue(
|
/// Convert json value (Number, String or Bool) to an array of ivalues according to the supplied argument types.
|
||||||
json_string: String,
|
fn json_value_to_ivalue<'a>(
|
||||||
func_signature: &fce::FCEFunctionSignature,
|
json_value: JValue,
|
||||||
|
mut arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
|
||||||
) -> Result<Vec<IValue>> {
|
) -> Result<Vec<IValue>> {
|
||||||
if func_signature.arguments.len() != 1 || func_signature.arguments[0].ty != IType::String {
|
if arg_types.len() != 1 {
|
||||||
return Err(ArgDeError(format!(
|
return Err(ArgDeError(format!(
|
||||||
"the called function has the following signature: {:?}, but only one string argument is provided",
|
"the called function has the following signature: {:?}, but only one string argument is provided",
|
||||||
func_signature
|
arg_types.collect::<Vec<_>>()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(vec![IValue::String(json_string)])
|
let ivalue = jvalue_to_ivalue(json_value, arg_types.next().unwrap().1, &HashMap::new())?;
|
||||||
|
Ok(vec![ivalue])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_bool_to_ivalue(
|
/// Convert json Null to an empty array of ivalues.
|
||||||
json_bool: JValue,
|
fn json_null_to_ivalue<'a>(
|
||||||
func_signature: &fce::FCEFunctionSignature,
|
arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
|
||||||
) -> Result<Vec<IValue>> {
|
) -> Result<Vec<IValue>> {
|
||||||
if func_signature.arguments.len() != 1 {
|
if arg_types.len() != 0 {
|
||||||
return Err(ArgDeError(format!(
|
|
||||||
"the called function has the following signature: {:?}, but only one bool argument is provided",
|
|
||||||
func_signature
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(vec![json_value_to_ivalue(
|
|
||||||
json_bool,
|
|
||||||
&func_signature.arguments[0].ty,
|
|
||||||
&HashMap::new(),
|
|
||||||
)?])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_number_to_ivalue(
|
|
||||||
json_number: JValue,
|
|
||||||
func_signature: &fce::FCEFunctionSignature,
|
|
||||||
) -> Result<Vec<IValue>> {
|
|
||||||
if func_signature.arguments.len() != 1 {
|
|
||||||
return Err(ArgDeError(format!(
|
|
||||||
"the called function has the following signature: {:?}, but only one number argument is provided",
|
|
||||||
func_signature
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(vec![json_value_to_ivalue(
|
|
||||||
json_number,
|
|
||||||
&func_signature.arguments[0].ty,
|
|
||||||
&HashMap::new(),
|
|
||||||
)?])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn json_null_to_ivalue(func_signature: &fce::FCEFunctionSignature) -> Result<Vec<IValue>> {
|
|
||||||
if !func_signature.arguments.is_empty() {
|
|
||||||
return Err(ArgDeError(format!(
|
return Err(ArgDeError(format!(
|
||||||
"the called function has the following signature: {:?}, but no arguments is provided",
|
"the called function has the following signature: {:?}, but no arguments is provided",
|
||||||
func_signature
|
arg_types.collect::<Vec<_>>()
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_value_to_ivalue(
|
/// Convert one JValue to an array of ivalues according to the supplied argument type.
|
||||||
json_value: JValue,
|
fn jvalue_to_ivalue(jvalue: JValue, ty: &IType, record_types: &RecordTypes) -> Result<IValue> {
|
||||||
ty: &IType,
|
|
||||||
record_types: &RecordTypes,
|
|
||||||
) -> Result<IValue> {
|
|
||||||
macro_rules! to_ivalue(
|
macro_rules! to_ivalue(
|
||||||
($json_value:expr, $ty:ident) => {
|
($json_value:expr, $ty:ident) => {
|
||||||
{
|
{
|
||||||
@ -186,41 +142,39 @@ fn json_value_to_ivalue(
|
|||||||
);
|
);
|
||||||
|
|
||||||
match ty {
|
match ty {
|
||||||
IType::S8 => to_ivalue!(json_value, S8),
|
IType::S8 => to_ivalue!(jvalue, S8),
|
||||||
IType::S16 => to_ivalue!(json_value, S16),
|
IType::S16 => to_ivalue!(jvalue, S16),
|
||||||
IType::S32 => to_ivalue!(json_value, S32),
|
IType::S32 => to_ivalue!(jvalue, S32),
|
||||||
IType::S64 => to_ivalue!(json_value, S64),
|
IType::S64 => to_ivalue!(jvalue, S64),
|
||||||
IType::U8 => to_ivalue!(json_value, U8),
|
IType::U8 => to_ivalue!(jvalue, U8),
|
||||||
IType::U16 => to_ivalue!(json_value, U16),
|
IType::U16 => to_ivalue!(jvalue, U16),
|
||||||
IType::U32 => to_ivalue!(json_value, U32),
|
IType::U32 => to_ivalue!(jvalue, U32),
|
||||||
IType::U64 => to_ivalue!(json_value, U64),
|
IType::U64 => to_ivalue!(jvalue, U64),
|
||||||
IType::F32 => to_ivalue!(json_value, F32),
|
IType::F32 => to_ivalue!(jvalue, F32),
|
||||||
IType::F64 => to_ivalue!(json_value, F64),
|
IType::F64 => to_ivalue!(jvalue, F64),
|
||||||
IType::String => to_ivalue!(json_value, String),
|
IType::String => to_ivalue!(jvalue, String),
|
||||||
IType::Array(value_type) => {
|
IType::Array(value_type) => {
|
||||||
let value = match json_value {
|
let value = match jvalue {
|
||||||
JValue::Array(json_array) => {
|
JValue::Array(json_array) => {
|
||||||
let iargs: Result<Vec<_>> = json_array
|
let iargs = json_array
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|json_value| {
|
.map(|json_value| jvalue_to_ivalue(json_value, value_type, record_types))
|
||||||
json_value_to_ivalue(json_value, value_type, record_types)
|
.collect::<Result<Vec<_>>>()?;
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(iargs?)
|
Ok(iargs)
|
||||||
}
|
}
|
||||||
_ => Err(ArgDeError(format!(
|
_ => Err(ArgDeError(format!(
|
||||||
"expected array of {:?} types, got {:?}",
|
"expected array of {:?} types, got {:?}",
|
||||||
value_type, json_value
|
value_type, jvalue
|
||||||
))),
|
))),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
Ok(IValue::Array(value))
|
Ok(IValue::Array(value))
|
||||||
}
|
}
|
||||||
IType::I32 => to_ivalue!(json_value, I32),
|
IType::I32 => to_ivalue!(jvalue, I32),
|
||||||
IType::I64 => to_ivalue!(json_value, I64),
|
IType::I64 => to_ivalue!(jvalue, I64),
|
||||||
IType::Record(record_type_id) => {
|
IType::Record(record_type_id) => {
|
||||||
let value = json_record_type_to_ivalue(json_value, record_type_id, &record_types)?;
|
let value = json_record_type_to_ivalue(jvalue, record_type_id, &record_types)?;
|
||||||
Ok(IValue::Record(value))
|
Ok(IValue::Record(value))
|
||||||
}
|
}
|
||||||
IType::Anyref => Err(ArgDeError(String::from("anyrefs aren't supported now"))),
|
IType::Anyref => Err(ArgDeError(String::from("anyrefs aren't supported now"))),
|
||||||
@ -228,6 +182,8 @@ fn json_value_to_ivalue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::ptr_arg)]
|
#[allow(clippy::ptr_arg)]
|
||||||
|
/// Convert JValue of array or object types to an IValue record type.
|
||||||
|
// TODO: after introducing new Record type wrapper change the result type
|
||||||
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,
|
||||||
|
Reference in New Issue
Block a user