207 lines
7.5 KiB
Rust
Raw Normal View History

2021-08-24 16:14:15 +03:00
/*
* 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 super::*;
use crate::execution_step::value_types::populate_tetraplet_with_lambda;
use crate::execution_step::value_types::IterableValue;
2021-12-21 11:37:35 +03:00
use crate::execution_step::CatchableError;
2022-09-06 10:53:33 +03:00
use crate::execution_step::PEEK_ALLOWED_ON_NON_EMPTY;
2021-08-24 16:14:15 +03:00
use crate::JValue;
use crate::LambdaAST;
2022-02-18 18:00:42 +03:00
use crate::SecurityTetraplet;
2021-08-24 16:14:15 +03:00
use air_interpreter_data::Provenance;
2021-08-24 16:14:15 +03:00
use air_parser::ast;
use std::ops::Deref;
2022-02-18 18:00:42 +03:00
use std::rc::Rc;
2021-08-24 16:14:15 +03:00
// TODO: refactor this file after switching to boxed value
pub(crate) enum FoldIterableScalar {
Empty,
2022-08-26 00:43:43 +03:00
ScalarBased(IterableValue),
2021-08-24 16:14:15 +03:00
}
/// Creates iterable value for given scalar iterable.
pub(crate) fn create_scalar_iterable(
exec_ctx: &ExecutionCtx<'_>,
variable_name: &str,
) -> ExecutionResult<FoldIterableScalar> {
match exec_ctx.scalars.get_value(variable_name)? {
ScalarRef::Value(call_result) => from_value(call_result.clone(), variable_name),
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().expect(PEEK_ALLOWED_ON_NON_EMPTY);
let call_result = iterable_value.into_resolved_result();
from_value(call_result, variable_name)
}
}
}
/// Creates iterable value for given scalar with lambda iterable.
pub(crate) fn create_scalar_wl_iterable<'ctx>(
scalar_iterable: &ast::ScalarWithLambda<'ctx>,
2021-08-24 16:14:15 +03:00
exec_ctx: &ExecutionCtx<'ctx>,
) -> ExecutionResult<FoldIterableScalar> {
use crate::execution_step::lambda_applier::select_by_lambda_from_scalar;
let scalar_name = scalar_iterable.name;
let lambda = &scalar_iterable.lambda;
match exec_ctx.scalars.get_value(scalar_name)? {
ScalarRef::Value(variable) => {
let jvalues = select_by_lambda_from_scalar(variable.get_result(), lambda, exec_ctx)?;
let tetraplet = variable.get_tetraplet().deref().clone();
from_jvalue(&jvalues, tetraplet, variable.get_provenance(), lambda)
}
ScalarRef::IterableValue(fold_state) => {
let iterable_value = fold_state.iterable.peek().unwrap();
let jvalue = iterable_value.apply_lambda(lambda, exec_ctx)?;
let tetraplet = to_tetraplet(&iterable_value);
let provenance = to_provenance(&iterable_value);
from_jvalue(&jvalue, tetraplet, provenance, lambda)
}
2021-08-24 16:14:15 +03:00
}
}
/// Creates iterable value for given canon stream.
pub(crate) fn create_canon_stream_iterable_value<'ctx>(
2022-08-26 00:43:43 +03:00
ast_canon_stream: &ast::CanonStream<'ctx>,
exec_ctx: &ExecutionCtx<'ctx>,
) -> ExecutionResult<FoldIterableScalar> {
let canon_stream = exec_ctx.scalars.get_canon_stream(ast_canon_stream.name)?;
2022-09-06 10:53:33 +03:00
if canon_stream.is_empty() {
return Ok(FoldIterableScalar::Empty);
}
2022-08-26 00:43:43 +03:00
// TODO: this one is a relatively long operation and will be refactored in Boxed Value
let iterable_ingredients = CanonStreamIterableIngredients::init((**canon_stream).clone());
2022-08-26 00:43:43 +03:00
let iterable = Box::new(iterable_ingredients);
Ok(FoldIterableScalar::ScalarBased(iterable))
}
/// Creates iterable value for a canon stream map.
pub(crate) fn create_canon_stream_map_iterable_value(
ast_canon_stream_map: &ast::CanonStreamMap<'_>,
exec_ctx: &ExecutionCtx<'_>,
) -> ExecutionResult<FoldIterableScalar> {
let canon_stream_map = exec_ctx.scalars.get_canon_map(ast_canon_stream_map.name)?;
if canon_stream_map.is_empty() {
return Ok(FoldIterableScalar::Empty);
}
// TODO: this one is a relatively long operation and will be refactored in Boxed Value
// Can not create iterable from existing CanonStreamMap b/c CSM contains a map with
// a limited lifetime but the boxed value needs static lifetime.
let values = canon_stream_map.iter().cloned().collect::<Vec<_>>();
let iterable_ingredients = CanonStreamMapIterableIngredients::init(values);
let iterable = Box::new(iterable_ingredients);
Ok(FoldIterableScalar::ScalarBased(iterable))
}
/// Creates iterable value for a canon stream map with a lens applied.
pub(crate) fn create_canon_stream_map_wl_iterable_value(
ast_canon_stream_map: &ast::CanonStreamMapWithLambda<'_>,
exec_ctx: &ExecutionCtx<'_>,
) -> ExecutionResult<FoldIterableScalar> {
let canon_stream_map = exec_ctx.scalars.get_canon_map(ast_canon_stream_map.name)?;
// Source canon map provenance is used here to mimic the semantics used for scalar.
let provenance = Provenance::canon(canon_stream_map.cid.clone());
if canon_stream_map.is_empty() {
return Ok(FoldIterableScalar::Empty);
}
let canon_stream_map = &canon_stream_map.canon_stream_map;
let tetraplet = canon_stream_map.tetraplet().deref().clone();
let lambda = &ast_canon_stream_map.lambda;
// Source canon map tetraplet is used here similar with a scalar with lens processing path.
let jvalues = JValuable::apply_lambda(&canon_stream_map, lambda, exec_ctx)?;
from_jvalue(&jvalues, tetraplet, provenance, lambda)
}
2021-08-24 16:14:15 +03:00
/// Constructs iterable value from resolved call result.
2022-08-26 00:43:43 +03:00
fn from_value(call_result: ValueAggregate, variable_name: &str) -> ExecutionResult<FoldIterableScalar> {
let len = match call_result.get_result() {
2021-08-24 16:14:15 +03:00
JValue::Array(array) => {
if array.is_empty() {
// skip fold if array is empty
return Ok(FoldIterableScalar::Empty);
}
array.len()
}
v => {
return Err(CatchableError::FoldIteratesOverNonArray((*v).clone(), variable_name.to_string()).into());
}
2021-08-24 16:14:15 +03:00
};
let foldable = IterableResolvedCall::init(call_result, len);
let foldable = Box::new(foldable);
2022-08-26 00:43:43 +03:00
let iterable = FoldIterableScalar::ScalarBased(foldable);
2021-08-24 16:14:15 +03:00
Ok(iterable)
}
/// Construct IterableValue from the result and given triplet.
fn from_jvalue(
jvalue: &JValue,
2022-09-08 16:58:04 +03:00
tetraplet: SecurityTetraplet,
provenance: Provenance,
lambda: &LambdaAST<'_>,
2021-08-24 16:14:15 +03:00
) -> ExecutionResult<FoldIterableScalar> {
2022-09-08 16:58:04 +03:00
let tetraplet = populate_tetraplet_with_lambda(tetraplet, lambda);
2022-02-18 18:00:42 +03:00
let tetraplet = Rc::new(tetraplet);
2021-08-24 16:14:15 +03:00
let iterable = match jvalue {
JValue::Array(array) => array,
_ => {
return Err(CatchableError::FoldIteratesOverNonArray(jvalue.clone(), lambda.to_string()).into());
}
};
if iterable.is_empty() {
2021-08-24 16:14:15 +03:00
return Ok(FoldIterableScalar::Empty);
}
let iterable = iterable.to_vec();
let foldable = IterableLambdaResult::init(iterable, tetraplet, provenance);
2022-08-26 00:43:43 +03:00
let iterable = FoldIterableScalar::ScalarBased(Box::new(foldable));
2021-08-24 16:14:15 +03:00
Ok(iterable)
}
2022-02-18 18:00:42 +03:00
fn to_tetraplet(iterable: &IterableItem<'_>) -> SecurityTetraplet {
2021-08-24 16:14:15 +03:00
use IterableItem::*;
let tetraplet = match iterable {
RefValue((_, tetraplet, _, _)) => tetraplet,
RcValue((_, tetraplet, _, _)) => tetraplet,
2021-08-24 16:14:15 +03:00
};
2022-02-18 18:00:42 +03:00
(*tetraplet).deref().clone()
2021-08-24 16:14:15 +03:00
}
fn to_provenance(iterable: &IterableItem<'_>) -> Provenance {
use IterableItem::*;
let provenance = match iterable {
RefValue((_, _, _, provenance)) => provenance,
RcValue((_, _, _, provenance)) => provenance,
};
provenance.clone()
}