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::*;
|
2022-09-08 16:58:04 +03:00
|
|
|
use crate::execution_step::boxed_value::populate_tetraplet_with_lambda;
|
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;
|
2021-10-18 23:23:30 +03:00
|
|
|
use crate::LambdaAST;
|
2022-02-18 18:00:42 +03:00
|
|
|
use crate::SecurityTetraplet;
|
2021-08-24 16:14:15 +03:00
|
|
|
|
|
|
|
use air_parser::ast;
|
|
|
|
|
2022-09-08 16:58:04 +03:00
|
|
|
use std::borrow::Cow;
|
2021-08-24 16:14:15 +03:00
|
|
|
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) type IterableValue = Box<dyn for<'ctx> Iterable<'ctx, Item = IterableItem<'ctx>>>;
|
|
|
|
|
|
|
|
pub(crate) enum FoldIterableScalar {
|
|
|
|
Empty,
|
2022-08-26 00:43:43 +03:00
|
|
|
ScalarBased(IterableValue),
|
2021-08-24 16:14:15 +03:00
|
|
|
}
|
|
|
|
|
2022-11-30 17:38:32 +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> {
|
2022-11-30 17:38:32 +03:00
|
|
|
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.result, lambda, exec_ctx)?;
|
|
|
|
let tetraplet = variable.tetraplet.deref().clone();
|
|
|
|
from_jvalue(jvalues, tetraplet, 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);
|
|
|
|
|
|
|
|
from_jvalue(jvalue, tetraplet, lambda)
|
|
|
|
}
|
2021-08-24 16:14:15 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-30 17:38:32 +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());
|
|
|
|
let iterable = Box::new(iterable_ingredients);
|
|
|
|
Ok(FoldIterableScalar::ScalarBased(iterable))
|
|
|
|
}
|
|
|
|
|
2021-08-24 16:14:15 +03:00
|
|
|
/// Constructs iterable value for given stream iterable.
|
2022-02-25 23:55:40 +03:00
|
|
|
pub(crate) fn construct_stream_iterable_values(
|
2022-03-03 19:09:48 +03:00
|
|
|
stream: &Stream,
|
2022-02-25 23:55:40 +03:00
|
|
|
start: Generation,
|
|
|
|
end: Generation,
|
|
|
|
) -> Vec<IterableValue> {
|
|
|
|
let stream_iter = match stream.slice_iter(start, end) {
|
|
|
|
Some(stream_iter) => stream_iter,
|
|
|
|
None => return vec![],
|
|
|
|
};
|
2021-08-24 16:14:15 +03:00
|
|
|
|
2022-02-25 23:55:40 +03:00
|
|
|
stream_iter
|
|
|
|
.filter(|iterable| !iterable.is_empty())
|
|
|
|
.map(|iterable| {
|
|
|
|
let call_results = iterable.to_vec();
|
|
|
|
let foldable = IterableVecResolvedCall::init(call_results);
|
|
|
|
let foldable: IterableValue = Box::new(foldable);
|
|
|
|
foldable
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>()
|
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> {
|
2021-08-24 16:14:15 +03:00
|
|
|
let len = match &call_result.result.deref() {
|
|
|
|
JValue::Array(array) => {
|
|
|
|
if array.is_empty() {
|
|
|
|
// skip fold if array is empty
|
|
|
|
return Ok(FoldIterableScalar::Empty);
|
|
|
|
}
|
|
|
|
array.len()
|
|
|
|
}
|
2021-12-15 17:39:26 +03:00
|
|
|
v => {
|
2023-03-09 14:37:39 +03:00
|
|
|
return Err(CatchableError::FoldIteratesOverNonArray((*v).clone(), variable_name.to_string()).into());
|
2021-12-15 17:39:26 +03:00
|
|
|
}
|
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)
|
|
|
|
}
|
|
|
|
|
2021-10-18 23:23:30 +03:00
|
|
|
/// Construct IterableValue from the result and given triplet.
|
|
|
|
fn from_jvalue(
|
2022-09-08 16:58:04 +03:00
|
|
|
jvalue: Cow<'_, JValue>,
|
|
|
|
tetraplet: SecurityTetraplet,
|
2021-10-18 23:23:30 +03:00
|
|
|
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
|
|
|
|
2022-09-08 16:58:04 +03:00
|
|
|
let iterable = match jvalue.as_ref() {
|
2021-10-18 23:23:30 +03:00
|
|
|
JValue::Array(array) => array,
|
|
|
|
_ => {
|
2022-09-08 16:58:04 +03:00
|
|
|
return Err(CatchableError::FoldIteratesOverNonArray(jvalue.into_owned(), lambda.to_string()).into());
|
2021-10-18 23:23:30 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if iterable.is_empty() {
|
2021-08-24 16:14:15 +03:00
|
|
|
return Ok(FoldIterableScalar::Empty);
|
|
|
|
}
|
|
|
|
|
2021-10-18 23:23:30 +03:00
|
|
|
let iterable = iterable.to_vec();
|
|
|
|
let foldable = IterableLambdaResult::init(iterable, tetraplet);
|
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 {
|
|
|
|
RefRef((_, tetraplet, _)) => tetraplet,
|
|
|
|
RefValue((_, tetraplet, _)) => tetraplet,
|
|
|
|
RcValue((_, tetraplet, _)) => tetraplet,
|
|
|
|
};
|
|
|
|
|
2022-02-18 18:00:42 +03:00
|
|
|
(*tetraplet).deref().clone()
|
2021-08-24 16:14:15 +03:00
|
|
|
}
|