diff --git a/aquamarine-vm/src/args.rs b/aquamarine-vm/src/args.rs new file mode 100644 index 00000000..ea3f937a --- /dev/null +++ b/aquamarine-vm/src/args.rs @@ -0,0 +1,106 @@ +/* + * Copyright 2020 Fluence Labs Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +use crate::IValue; +use crate::args_error::ArgsError; +use crate::args_error::ArgsError::{MissingField, SerdeJson}; + +use fluence_faas::SecurityTetraplet; + +use serde::Deserialize; +use serde_json::Value as JValue; + +#[derive(Debug)] +/// Arguments passed by VM to host on call_service +pub struct CallServiceArgs { + pub service_id: String, + pub function_name: String, + pub function_args: Vec, + pub tetraplets: Vec>, +} + +impl CallServiceArgs { + /// Construct Args from `Vec` + pub fn parse(call_args: Vec) -> Result { + let mut call_args = call_args.into_iter(); + let service_id = call_args + .next() + .and_then(into_string) + .ok_or(MissingField("service_id"))?; + + let fname = call_args + .next() + .and_then(into_string) + .ok_or(MissingField("fname"))?; + + let function_args = call_args + .next() + .as_ref() + .and_then(as_str) + .ok_or(MissingField("args")) + .and_then(|v| { + serde_json::from_str(v).map_err(|err| SerdeJson { field: "args", err }) + })?; + + let tetraplets: Vec> = call_args + .next() + .as_ref() + .and_then(as_str) + .ok_or(MissingField("tetraplets")) + .and_then(|v| { + serde_json::from_str(v).map_err(|err| SerdeJson { + field: "tetraplets", + err, + }) + })?; + + Ok(Self { + service_id, + function_name: fname, + function_args, + tetraplets, + }) + } + + /// Retrieves next json value from iterator, parse it to T + pub fn next Deserialize<'de>>( + field: &'static str, + args: &mut impl Iterator, + ) -> Result { + let value = args.next().ok_or(MissingField(field))?; + let value: T = Self::deserialize(field, value)?; + + Ok(value) + } + + /// Retrieves a json value from iterator if it's not empty, and parses it to T + pub fn maybe_next Deserialize<'de>>( + field: &'static str, + args: &mut impl Iterator, + ) -> Result, ArgsError> { + let value = ok_get!(args.next()); + let value: T = Self::deserialize(field, value)?; + + Ok(Some(value)) + } + + fn deserialize Deserialize<'de>>( + field: &'static str, + v: JValue, + ) -> Result { + serde_json::from_value(v).map_err(|err| SerdeJson { err, field }) + } +} diff --git a/aquamarine-vm/src/args_error.rs b/aquamarine-vm/src/args_error.rs new file mode 100644 index 00000000..fdd671a9 --- /dev/null +++ b/aquamarine-vm/src/args_error.rs @@ -0,0 +1,57 @@ +/* + * 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 serde_json::Value as JValue; +use std::borrow::Cow; +use std::error::Error; +use std::fmt::{Display, Formatter}; + +#[derive(Debug)] +pub enum ArgsError { + MissingField(&'static str), + SerdeJson { + field: &'static str, + err: serde_json::Error, + }, + InvalidFormat { + field: &'static str, + err: Cow<'static, str>, + }, +} + +impl From for JValue { + fn from(err: ArgsError) -> Self { + JValue::String(format!("ArgsError: {}", err)) + } +} + +impl Error for ArgsError {} + +impl Display for ArgsError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + ArgsError::MissingField(field) => { + write!(f, "Field {} is missing from args to call_service", field) + } + ArgsError::SerdeJson { err, field } => { + write!(f, "Error while deserializing field {}: {:?}", field, err) + } + ArgsError::InvalidFormat { field, err } => { + write!(f, "Error while deserializing field {}: {:?}", field, err) + } + } + } +} diff --git a/aquamarine-vm/src/lib.rs b/aquamarine-vm/src/lib.rs index 866b933d..e588ef00 100644 --- a/aquamarine-vm/src/lib.rs +++ b/aquamarine-vm/src/lib.rs @@ -27,6 +27,8 @@ mod aquamarine_stepper_vm; mod config; mod errors; +mod args; +mod args_error; pub use aquamarine_stepper_vm::AquamarineVM; pub use aquamarine_stepper_vm::ParticleParameters;