|
1 | | -use std::convert::TryInto; |
| 1 | +use std::{convert::TryInto, collections::BTreeMap}; |
2 | 2 |
|
3 | 3 | use serde_cbor::value::{from_value, Value}; |
| 4 | +use witnet_data_structures::radon_report::ReportContext; |
4 | 5 |
|
5 | 6 | use crate::{ |
6 | 7 | error::RadError, |
7 | 8 | operators::string, |
8 | | - types::{array::RadonArray, map::RadonMap, string::RadonString, RadonType, RadonTypes}, |
| 9 | + types::{array::RadonArray, map::RadonMap, string::RadonString, RadonType, RadonTypes}, |
| 10 | + script::{RadonScriptExecutionSettings, execute_radon_script, unpack_subscript, partial_results_extract}, |
9 | 11 | }; |
10 | 12 |
|
| 13 | +pub fn alter( |
| 14 | + input: &RadonMap, |
| 15 | + args: &[Value], |
| 16 | + context: &mut ReportContext<RadonTypes> |
| 17 | +) -> Result<RadonMap, RadError> { |
| 18 | + let wrong_args = || RadError::WrongArguments { |
| 19 | + input_type: RadonMap::radon_type_name(), |
| 20 | + operator: "Alter".to_string(), |
| 21 | + args: args.to_vec(), |
| 22 | + }; |
| 23 | + |
| 24 | + let first_arg = args.get(0).ok_or_else(wrong_args)?; |
| 25 | + let mut input_keys = vec![]; |
| 26 | + match first_arg { |
| 27 | + Value::Array(keys) => { |
| 28 | + for key in keys.iter() { |
| 29 | + let key_string = from_value::<String>(key.to_owned()).map_err(|_| wrong_args())?; |
| 30 | + input_keys.push(key_string); |
| 31 | + } |
| 32 | + } |
| 33 | + Value::Text(key) => { |
| 34 | + input_keys.push(key.clone()); |
| 35 | + } |
| 36 | + _ => return Err(wrong_args()) |
| 37 | + }; |
| 38 | + |
| 39 | + let subscript = args.get(1).ok_or_else(wrong_args)?; |
| 40 | + match subscript { |
| 41 | + Value::Array(_arg) => { |
| 42 | + let subscript_err = |e| RadError::Subscript { |
| 43 | + input_type: "RadonMap".to_string(), |
| 44 | + operator: "Alter".to_string(), |
| 45 | + inner: Box::new(e), |
| 46 | + }; |
| 47 | + let subscript = unpack_subscript(subscript).map_err(subscript_err)?; |
| 48 | + |
| 49 | + let not_found = |key_str: &str| RadError::MapKeyNotFound { key: String::from(key_str) }; |
| 50 | + |
| 51 | + let input_map = input.value(); |
| 52 | + let mut output_map = input.value().clone(); |
| 53 | + let mut reports = vec![]; |
| 54 | + |
| 55 | + let settings = RadonScriptExecutionSettings::tailored_to_stage(&context.stage); |
| 56 | + for key in input_keys { |
| 57 | + let value = input_map |
| 58 | + .get(key.as_str()) |
| 59 | + .ok_or_else(|| not_found(key.as_str()))?; |
| 60 | + let report = execute_radon_script( |
| 61 | + value.clone(), |
| 62 | + subscript.as_slice(), |
| 63 | + context, |
| 64 | + settings |
| 65 | + )?; |
| 66 | + // If there is an error while altering value, short-circuit and bubble up the error as it comes |
| 67 | + // from the radon script execution |
| 68 | + if let RadonTypes::RadonError(error) = &report.result { |
| 69 | + return Err(error.clone().into_inner()); |
| 70 | + } else { |
| 71 | + output_map.insert(key, report.result.clone()); |
| 72 | + } |
| 73 | + reports.push(report); |
| 74 | + } |
| 75 | + |
| 76 | + // Extract the partial results from the reports and put them in the execution context if needed |
| 77 | + partial_results_extract(&subscript, &reports, context); |
| 78 | + |
| 79 | + Ok(RadonMap::from(output_map)) |
| 80 | + } |
| 81 | + _ => Err(wrong_args()) |
| 82 | + } |
| 83 | +} |
| 84 | + |
11 | 85 | fn inner_get(input: &RadonMap, args: &[Value]) -> Result<RadonTypes, RadError> { |
12 | 86 | let wrong_args = || RadError::WrongArguments { |
13 | 87 | input_type: RadonMap::radon_type_name(), |
|
0 commit comments