mirror of
https://github.com/fluencelabs/marine.git
synced 2025-06-05 11:01:32 +00:00
245 lines
8.4 KiB
Rust
245 lines
8.4 KiB
Rust
/*
|
|
* Copyright 2022 Fluence Labs Limited
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
use crate::IValue;
|
|
use crate::IType;
|
|
use super::ITJsonSeDeError::De;
|
|
use super::JsonResult;
|
|
use crate::MRecordTypes;
|
|
|
|
use serde_json::Value as JValue;
|
|
use wasmer_it::NEVec;
|
|
|
|
use std::collections::HashMap;
|
|
use std::iter::ExactSizeIterator;
|
|
|
|
/// Convert json to an array of ivalues according to the supplied argument types.
|
|
pub fn json_to_ivalues<'a, 'b>(
|
|
json_args: JValue,
|
|
arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
|
|
record_types: &'b MRecordTypes,
|
|
) -> JsonResult<Vec<IValue>> {
|
|
let ivalues = match json_args {
|
|
JValue::Object(json_map) => json_map_to_ivalues(json_map, arg_types, record_types)?,
|
|
JValue::Array(json_array) => {
|
|
json_array_to_ivalues(json_array, arg_types.map(|arg| arg.1), record_types)?
|
|
}
|
|
JValue::Null => json_null_to_ivalues(arg_types)?,
|
|
json_value => json_value_to_ivalues(json_value, arg_types)?,
|
|
};
|
|
|
|
Ok(ivalues)
|
|
}
|
|
|
|
/// Convert json map to an array of ivalues according to the supplied argument types.
|
|
fn json_map_to_ivalues<'a, 'b>(
|
|
mut json_map: serde_json::Map<String, JValue>,
|
|
arg_types: impl Iterator<Item = (&'a String, &'a IType)>,
|
|
record_types: &'b MRecordTypes,
|
|
) -> JsonResult<Vec<IValue>> {
|
|
let mut iargs = Vec::new();
|
|
|
|
for (arg_name, arg_type) in arg_types {
|
|
let json_value = json_map
|
|
.remove(arg_name)
|
|
.ok_or_else(|| De(format!("missing argument with name {}", arg_name)))?;
|
|
let iarg = jvalue_to_ivalue(json_value, arg_type, record_types)?;
|
|
iargs.push(iarg);
|
|
}
|
|
|
|
if !json_map.is_empty() {
|
|
return Err(De(format!(
|
|
"function requires {} arguments, {} provided",
|
|
iargs.len(),
|
|
iargs.len() + json_map.len()
|
|
)));
|
|
}
|
|
|
|
Ok(iargs)
|
|
}
|
|
|
|
/// Convert json array to an array of ivalues according to the supplied argument types.
|
|
fn json_array_to_ivalues<'a, 'b>(
|
|
json_array: Vec<JValue>,
|
|
arg_types: impl Iterator<Item = &'a IType> + ExactSizeIterator,
|
|
record_types: &'b MRecordTypes,
|
|
) -> JsonResult<Vec<IValue>> {
|
|
if json_array.len() != arg_types.len() {
|
|
return Err(De(format!(
|
|
"function requires {} arguments, {} provided",
|
|
arg_types.len(),
|
|
json_array.len()
|
|
)));
|
|
}
|
|
|
|
let iargs = json_array
|
|
.into_iter()
|
|
.zip(arg_types)
|
|
.map(|(json_value, arg_type)| jvalue_to_ivalue(json_value, arg_type, record_types))
|
|
.collect::<JsonResult<Vec<_>>>()?;
|
|
|
|
Ok(iargs)
|
|
}
|
|
|
|
/// Convert json value (Number, String or Bool) to an array of ivalues according to the supplied argument types.
|
|
fn json_value_to_ivalues<'a>(
|
|
json_value: JValue,
|
|
mut arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
|
|
) -> JsonResult<Vec<IValue>> {
|
|
if arg_types.len() != 1 {
|
|
return Err(De(format!(
|
|
"called function has the following signature: '{:?}', and it isn't suitable for an argument '{:?}' provided",
|
|
arg_types.collect::<Vec<_>>(),
|
|
json_value,
|
|
)));
|
|
}
|
|
|
|
// unwrap is safe here because iterator size's been checked
|
|
let arg_type = arg_types.next().unwrap().1;
|
|
let ivalue = jvalue_to_ivalue(json_value, arg_type, &HashMap::new())?;
|
|
|
|
Ok(vec![ivalue])
|
|
}
|
|
|
|
/// Convert json Null to an empty array of ivalues.
|
|
fn json_null_to_ivalues<'a>(
|
|
arg_types: impl Iterator<Item = (&'a String, &'a IType)> + ExactSizeIterator,
|
|
) -> JsonResult<Vec<IValue>> {
|
|
if arg_types.len() != 0 {
|
|
return Err(De(format!(
|
|
"the called function has the following signature: {:?}, but no arguments is provided",
|
|
arg_types.collect::<Vec<_>>()
|
|
)));
|
|
}
|
|
|
|
Ok(vec![])
|
|
}
|
|
|
|
/// Convert one JValue to an array of ivalues according to the supplied argument type.
|
|
fn jvalue_to_ivalue(jvalue: JValue, ty: &IType, record_types: &MRecordTypes) -> JsonResult<IValue> {
|
|
macro_rules! to_ivalue(
|
|
($json_value:expr, $ty:ident) => {
|
|
{
|
|
let value = match $json_value {
|
|
// if there is an array with only one element try to implicitly flatten it,
|
|
// this is needed mostly because jsonpath lib returns Vec<&JValue> and
|
|
// could be changed in future
|
|
JValue::Array(mut json_array) if json_array.len() == 1 => {
|
|
serde_json::from_value(json_array.remove(0))
|
|
},
|
|
jvalue => serde_json::from_value(jvalue),
|
|
}.map_err(|e|
|
|
De(format!("error {:?} occurred while deserializing function arguments",e))
|
|
)?;
|
|
|
|
Ok(IValue::$ty(value))
|
|
}
|
|
}
|
|
);
|
|
|
|
match ty {
|
|
IType::Boolean => to_ivalue!(jvalue, Boolean),
|
|
IType::S8 => to_ivalue!(jvalue, S8),
|
|
IType::S16 => to_ivalue!(jvalue, S16),
|
|
IType::S32 => to_ivalue!(jvalue, S32),
|
|
IType::S64 => to_ivalue!(jvalue, S64),
|
|
IType::U8 => to_ivalue!(jvalue, U8),
|
|
IType::U16 => to_ivalue!(jvalue, U16),
|
|
IType::U32 => to_ivalue!(jvalue, U32),
|
|
IType::U64 => to_ivalue!(jvalue, U64),
|
|
IType::F32 => to_ivalue!(jvalue, F32),
|
|
IType::F64 => to_ivalue!(jvalue, F64),
|
|
IType::String => to_ivalue!(jvalue, String),
|
|
IType::ByteArray => {
|
|
let value = match jvalue {
|
|
JValue::Array(json_array) => {
|
|
let iargs = json_array
|
|
.into_iter()
|
|
.map(|json_value| jvalue_to_ivalue(json_value, &IType::U8, record_types))
|
|
.collect::<JsonResult<Vec<_>>>()?;
|
|
|
|
Ok(iargs)
|
|
}
|
|
_ => Err(De(format!("expected bytearray, got {:?}", jvalue))),
|
|
}?;
|
|
|
|
Ok(IValue::Array(value))
|
|
}
|
|
IType::Array(value_type) => {
|
|
let value = match jvalue {
|
|
JValue::Array(json_array) => {
|
|
let iargs = json_array
|
|
.into_iter()
|
|
.map(|json_value| jvalue_to_ivalue(json_value, value_type, record_types))
|
|
.collect::<JsonResult<Vec<_>>>()?;
|
|
|
|
Ok(iargs)
|
|
}
|
|
_ => Err(De(format!(
|
|
"expected array of {:?} types, got {:?}",
|
|
value_type, jvalue
|
|
))),
|
|
}?;
|
|
|
|
Ok(IValue::Array(value))
|
|
}
|
|
IType::I32 => to_ivalue!(jvalue, I32),
|
|
IType::I64 => to_ivalue!(jvalue, I64),
|
|
IType::Record(record_type_id) => {
|
|
let value = json_record_type_to_ivalue(jvalue, record_type_id, record_types)?;
|
|
Ok(IValue::Record(value))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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(
|
|
json_value: JValue,
|
|
record_type_id: &u64,
|
|
record_types: &MRecordTypes,
|
|
) -> JsonResult<NEVec<IValue>> {
|
|
let record_type = record_types.get(record_type_id).ok_or_else(|| {
|
|
De(format!(
|
|
"record with type id `{}` wasn't found",
|
|
record_type_id
|
|
))
|
|
})?;
|
|
|
|
match json_value {
|
|
JValue::Object(json_map) => Ok(NEVec::new(json_map_to_ivalues(
|
|
json_map,
|
|
record_type
|
|
.fields
|
|
.iter()
|
|
.map(|field| (&field.name, &field.ty)),
|
|
record_types,
|
|
)?)
|
|
.unwrap()),
|
|
JValue::Array(json_array) => Ok(NEVec::new(json_array_to_ivalues(
|
|
json_array,
|
|
record_type.fields.iter().map(|field| (&field.ty)),
|
|
record_types,
|
|
)?)
|
|
.unwrap()),
|
|
_ => Err(De(format!(
|
|
"record with type id `{}` should be encoded as array or map of fields",
|
|
record_type_id
|
|
))),
|
|
}
|
|
}
|