/* * 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::contexts::execution::AValue; use crate::contexts::execution::ExecutionCtx; use crate::execution::boxed_value::JValuable; use crate::execution::ExecutionError; use crate::execution::ExecutionResult; use crate::JValue; use crate::SecurityTetraplet; use air_parser::ast::CallInstrArgValue; /// Resolve value to called function arguments. pub(crate) fn resolve_to_args<'i>( value: &CallInstrArgValue<'i>, ctx: &ExecutionCtx<'i>, ) -> ExecutionResult<(JValue, Vec)> { match value { CallInstrArgValue::InitPeerId => prepare_consts(ctx.init_peer_id.clone(), ctx), CallInstrArgValue::LastError => prepare_last_error(ctx), CallInstrArgValue::Literal(value) => prepare_consts(value.to_string(), ctx), CallInstrArgValue::Boolean(value) => prepare_consts(*value, ctx), CallInstrArgValue::Number(value) => prepare_consts(value, ctx), CallInstrArgValue::Variable(name) => prepare_variable(name, ctx), CallInstrArgValue::JsonPath { variable, path } => prepare_json_path(variable, path, ctx), } } fn prepare_consts<'i>( arg: impl Into, ctx: &ExecutionCtx<'i>, ) -> ExecutionResult<(JValue, Vec)> { let jvalue = arg.into(); let tetraplet = SecurityTetraplet::literal_tetraplet(ctx.init_peer_id.clone()); Ok((jvalue, vec![tetraplet])) } fn prepare_last_error<'i>(ctx: &ExecutionCtx<'i>) -> ExecutionResult<(JValue, Vec)> { let result = match &ctx.last_error { Some(error) => { let serialized_error = error.serialize(); let jvalue = JValue::String(serialized_error); let tetraplets = error .tetraplet .clone() .unwrap_or_else(|| SecurityTetraplet::literal_tetraplet(ctx.init_peer_id.clone())); (jvalue, vec![tetraplets]) } None => { let jvalue = JValue::String(String::new()); let tetraplets = vec![]; (jvalue, tetraplets) } }; Ok(result) } fn prepare_variable<'i>(name: &str, ctx: &ExecutionCtx<'i>) -> ExecutionResult<(JValue, Vec)> { let resolved = resolve_to_jvaluable(name, ctx)?; let tetraplets = resolved.as_tetraplets(); let jvalue = resolved.into_jvalue(); Ok((jvalue, tetraplets)) } fn prepare_json_path<'i>( name: &str, json_path: &str, ctx: &ExecutionCtx<'i>, ) -> ExecutionResult<(JValue, Vec)> { let resolved = resolve_to_jvaluable(name, ctx)?; let (jvalue, tetraplets) = resolved.apply_json_path_with_tetraplets(json_path)?; let jvalue = jvalue.into_iter().cloned().collect::>(); let jvalue = JValue::Array(jvalue); Ok((jvalue, tetraplets)) } /// Constructs jvaluable result from `ExecutionCtx::data_cache` by name. pub(crate) fn resolve_to_jvaluable<'name, 'i, 'ctx>( name: &'name str, ctx: &'ctx ExecutionCtx<'i>, ) -> ExecutionResult> { use ExecutionError::VariableNotFound; let value = ctx .data_cache .get(name) .ok_or_else(|| VariableNotFound(name.to_string()))?; match value { AValue::JValueRef(value) => Ok(Box::new(value.clone())), AValue::JValueAccumulatorRef(acc) => Ok(Box::new(acc.borrow())), AValue::JValueFoldCursor(fold_state) => { let peeked_value = fold_state.iterable.peek().unwrap(); Ok(Box::new(peeked_value)) } } }