Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 41 additions & 83 deletions engine/src/ast/index_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ use super::{
use crate::{
compiler::Compiler,
execution_context::ExecutionContext,
filter::{
CompiledExpr, CompiledOneExpr, CompiledValueExpr, CompiledVecExpr, CompiledVecExprResult,
},
filter::{CompiledExpr, CompiledOneExpr, CompiledValueExpr, CompiledVecExpr},
lex::{Lex, LexErrorKind, LexResult, LexWith, expect, skip_space, span},
lhs_types::{Array, Map, TypedArray},
scheme::{FieldIndex, IndexAccessError},
types::{GetType, IntoIter, LhsValue, Type},
};
use serde::{Serialize, Serializer, ser::SerializeSeq};

const BOOL_ARRAY: TypedArray<'_, bool> = TypedArray::new();

/// IndexExpr is an expr that destructures an index into an IdentifierExpr.
///
/// For example, given a scheme which declares a field `http.request.headers`,
Expand All @@ -31,45 +31,13 @@ pub struct IndexExpr {
pub indexes: Vec<FieldIndex>,
}

fn index_access_one<'s, 'e, U, F>(
indexes: &[FieldIndex],
first: Option<&'e LhsValue<'e>>,
default: bool,
ctx: &'e ExecutionContext<'e, U>,
func: F,
) -> bool
where
F: Fn(&LhsValue<'_>, &ExecutionContext<'_, U>) -> bool + Sync + Send + 's,
{
indexes
.iter()
.fold(first, |value, idx| {
value.and_then(|val| val.get(idx).unwrap())
})
.map_or_else(
|| default,
#[inline]
|val| func(val, ctx),
)
}

fn index_access_vec<'s, 'e, U, F>(
indexes: &[FieldIndex],
first: Option<&'e LhsValue<'e>>,
ctx: &'e ExecutionContext<'e, U>,
func: F,
) -> CompiledVecExprResult
where
F: Fn(&LhsValue<'_>, &ExecutionContext<'_, U>) -> bool + Sync + Send + 's,
{
indexes
.iter()
.fold(first, |value, idx| {
value.and_then(|val| val.get(idx).unwrap())
})
.map_or(const { TypedArray::new() }, move |val: &LhsValue<'_>| {
TypedArray::from_iter(val.iter().unwrap().map(|item| func(item, ctx)))
})
#[allow(clippy::manual_ok_err)]
#[inline]
pub fn ok_ref<T, E>(result: &Result<T, E>) -> Option<&T> {
match result {
Ok(x) => Some(x),
Err(_) => None,
}
}

impl ValueExpr for IndexExpr {
Expand Down Expand Up @@ -119,23 +87,17 @@ impl ValueExpr for IndexExpr {
// Average path
match identifier {
IdentifierExpr::Field(f) => CompiledValueExpr::new(move |ctx| {
indexes[..last]
.iter()
.try_fold(ctx.get_field_value_unchecked(&f), |value, index| {
value.get(index).unwrap()
})
ctx.get_field_value_unchecked(&f)
.get_nested(&indexes[..last])
.map(LhsValue::as_ref)
.ok_or(ty)
}),
IdentifierExpr::FunctionCallExpr(call) => {
let call = compiler.compile_function_call_expr(call);
CompiledValueExpr::new(move |ctx| {
let result = call.execute(ctx).ok();
indexes[..last]
.iter()
.fold(result, |value, index| {
value.and_then(|val| val.extract(index).unwrap())
})
call.execute(ctx)
.ok()
.and_then(|val| val.extract_nested(&indexes[..last]))
.ok_or(ty)
})
}
Expand Down Expand Up @@ -192,14 +154,13 @@ impl IndexExpr {
})
} else {
CompiledOneExpr::new(move |ctx| {
index_access_one(
&indexes,
call.execute(ctx).as_ref().ok(),
default,
ctx,
#[inline]
|val, ctx| func(val, ctx),
)
ok_ref(&call.execute(ctx))
.and_then(|val| val.get_nested(&indexes))
.map_or(
default,
#[inline]
|val| func(val, ctx),
)
})
}
}
Expand All @@ -208,14 +169,13 @@ impl IndexExpr {
CompiledOneExpr::new(move |ctx| func(ctx.get_field_value_unchecked(&f), ctx))
} else {
CompiledOneExpr::new(move |ctx| {
index_access_one(
&indexes,
Some(ctx.get_field_value_unchecked(&f)),
default,
ctx,
#[inline]
|val, ctx| func(val, ctx),
)
ctx.get_field_value_unchecked(&f)
.get_nested(&indexes)
.map_or(
default,
#[inline]
|val| func(val, ctx),
)
})
}
}
Expand All @@ -239,23 +199,21 @@ impl IndexExpr {
IdentifierExpr::FunctionCallExpr(call) => {
let call = compiler.compile_function_call_expr(call);
CompiledVecExpr::new(move |ctx| {
index_access_vec(
&indexes,
call.execute(ctx).as_ref().ok(),
ctx,
#[inline]
|val, ctx| func(val, ctx),
)
let func = &func;
ok_ref(&call.execute(ctx))
.and_then(|val| val.get_nested(&indexes))
.map_or(BOOL_ARRAY, move |val: &LhsValue<'_>| {
TypedArray::from_iter(val.iter().unwrap().map(|item| func(item, ctx)))
})
})
}
IdentifierExpr::Field(f) => CompiledVecExpr::new(move |ctx| {
index_access_vec(
&indexes,
Some(ctx.get_field_value_unchecked(&f)),
ctx,
#[inline]
|val, ctx| func(val, ctx),
)
let func = &func;
ctx.get_field_value_unchecked(&f)
.get_nested(&indexes)
.map_or(BOOL_ARRAY, move |val: &LhsValue<'_>| {
TypedArray::from_iter(val.iter().unwrap().map(|item| func(item, ctx)))
})
}),
}
}
Expand Down
14 changes: 14 additions & 0 deletions engine/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,13 @@ impl<'a> LhsValue<'a> {
}
}

#[inline]
pub(crate) fn get_nested(&'a self, indexes: &[FieldIndex]) -> Option<&'a LhsValue<'a>> {
indexes
.iter()
.try_fold(self, |value, idx| value.get(idx).unwrap())
}

pub(crate) fn extract(
self,
item: &FieldIndex,
Expand All @@ -839,6 +846,13 @@ impl<'a> LhsValue<'a> {
}
}

#[inline]
pub(crate) fn extract_nested(self, indexes: &[FieldIndex]) -> Option<LhsValue<'a>> {
indexes
.iter()
.try_fold(self, |value, idx| value.extract(idx).unwrap())
}

/// Set an element in an LhsValue given a path item and a specified value.
/// Returns a TypeMismatchError error if current type does not support
/// nested element or if value type is invalid.
Expand Down
Loading