diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 44e4e87a..147b4362 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -799,9 +799,9 @@ mod tests { use crate::ast::logical_expr::LogicalExpr; use crate::execution_context::ExecutionContext; use crate::functions::{ - FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, - FunctionParam, FunctionParamError, SimpleFunctionDefinition, SimpleFunctionImpl, - SimpleFunctionOptParam, SimpleFunctionParam, + CompiledFunction, FunctionArgKind, FunctionArgs, FunctionDefinition, + FunctionDefinitionContext, FunctionParam, FunctionParamError, SimpleFunctionDefinition, + SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, }; use crate::lhs_types::{Array, Map}; use crate::list_matcher::{ListDefinition, ListMatcher}; @@ -908,12 +908,7 @@ mod tests { &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box< - dyn for<'i, 'a> Fn(FunctionArgs<'i, 'a>) -> Option> - + Sync - + Send - + 'static, - > { + ) -> CompiledFunction { Box::new(|args| { let value_array = Array::try_from(args.next().unwrap().unwrap()).unwrap(); let keep_array = Array::try_from(args.next().unwrap().unwrap()).unwrap(); diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index ef6deab7..c0656c91 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -8,7 +8,7 @@ use crate::ast::logical_expr::{LogicalExpr, UnaryOp}; use crate::compiler::Compiler; use crate::filter::{CompiledExpr, CompiledValueExpr, CompiledValueResult}; use crate::functions::{ - ExactSizeChain, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, + CompiledFunction, ExactSizeChain, FunctionDefinition, FunctionDefinitionContext, FunctionParam, FunctionParamError, }; use crate::lex::{Lex, LexError, LexErrorKind, LexResult, LexWith, expect, skip_space, span}; @@ -272,11 +272,9 @@ impl ValueExpr for FunctionCallExpr { let first = args.remove(0); #[inline(always)] - fn compute<'s, 'a, I: ExactSizeIterator>>( + fn compute<'a, I: ExactSizeIterator>>( first: CompiledValueResult<'a>, - call: &( - dyn for<'b> Fn(FunctionArgs<'_, 'b>) -> Option> + Sync + Send + 's - ), + call: &CompiledFunction, return_type: Type, f: impl Fn(LhsValue<'a>) -> I, ) -> CompiledValueResult<'a> { diff --git a/engine/src/functions/all.rs b/engine/src/functions/all.rs index b78cb8e8..152aed41 100644 --- a/engine/src/functions/all.rs +++ b/engine/src/functions/all.rs @@ -1,10 +1,9 @@ use crate::{ - FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, - FunctionParamError, GetType, LhsValue, ParserSettings, Type, + CompiledFunction, FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, + FunctionParam, FunctionParamError, GetType, LhsValue, ParserSettings, Type, }; use std::iter::once; -#[inline] fn all_impl<'a>(args: FunctionArgs<'_, 'a>) -> Option> { let arg = args.next().expect("expected 1 argument, got 0"); if args.next().is_some() { @@ -58,12 +57,11 @@ impl FunctionDefinition for AllFunction { (1, Some(0)) } - fn compile<'s>( - &'s self, + fn compile( + &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { + ) -> CompiledFunction { Box::new(all_impl) } } diff --git a/engine/src/functions/any.rs b/engine/src/functions/any.rs index a9f90b76..66199d33 100644 --- a/engine/src/functions/any.rs +++ b/engine/src/functions/any.rs @@ -1,10 +1,9 @@ use crate::{ - FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, - FunctionParamError, GetType, LhsValue, ParserSettings, Type, + CompiledFunction, FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, + FunctionParam, FunctionParamError, GetType, LhsValue, ParserSettings, Type, }; use std::iter::once; -#[inline] fn any_impl<'a>(args: FunctionArgs<'_, 'a>) -> Option> { let arg = args.next().expect("expected 1 argument, got 0"); if args.next().is_some() { @@ -58,12 +57,11 @@ impl FunctionDefinition for AnyFunction { (1, Some(0)) } - fn compile<'s>( - &'s self, + fn compile( + &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { + ) -> CompiledFunction { Box::new(any_impl) } } diff --git a/engine/src/functions/concat.rs b/engine/src/functions/concat.rs index 1d493d93..681b099e 100644 --- a/engine/src/functions/concat.rs +++ b/engine/src/functions/concat.rs @@ -1,6 +1,7 @@ use crate::{ - Array, Bytes, ExpectedType, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, - FunctionParam, FunctionParamError, GetType, LhsValue, ParserSettings, Type, + Array, Bytes, CompiledFunction, ExpectedType, FunctionArgs, FunctionDefinition, + FunctionDefinitionContext, FunctionParam, FunctionParamError, GetType, LhsValue, + ParserSettings, Type, }; use std::iter::once; @@ -19,6 +20,7 @@ impl ConcatFunction { } } +#[inline] fn concat_array<'a>(accumulator: Array<'a>, args: FunctionArgs<'_, 'a>) -> Array<'a> { let mut args = args.flat_map(|arg| arg.ok()); let Some(first) = args.next() else { @@ -43,6 +45,7 @@ fn concat_array<'a>(accumulator: Array<'a>, args: FunctionArgs<'_, 'a>) -> Array Array::try_from_vec(val_type, vec).unwrap() } +#[inline] fn concat_bytes<'a>(mut accumulator: Vec, args: FunctionArgs<'_, 'a>) -> Bytes<'a> { for arg in args { match arg { @@ -54,6 +57,25 @@ fn concat_bytes<'a>(mut accumulator: Vec, args: FunctionArgs<'_, 'a>) -> Byt accumulator.into() } +fn concat_impl<'a>(args: FunctionArgs<'_, 'a>) -> Option> { + while let Some(arg) = args.next() { + match arg { + Ok(LhsValue::Array(array)) => { + return Some(LhsValue::Array(concat_array(array, args))); + } + Ok(LhsValue::Bytes(bytes)) => { + return Some(LhsValue::Bytes(concat_bytes( + bytes.into_owned().into(), + args, + ))); + } + Err(_) => (), + _ => unreachable!(), + } + } + None +} + pub(crate) const EXPECTED_TYPES: [ExpectedType; 2] = [ExpectedType::Array, ExpectedType::Type(Type::Bytes)]; @@ -90,30 +112,12 @@ impl FunctionDefinition for ConcatFunction { (2, None) } - fn compile<'s>( - &'s self, + fn compile( + &self, _: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { - Box::new(|args| { - while let Some(arg) = args.next() { - match arg { - Ok(LhsValue::Array(array)) => { - return Some(LhsValue::Array(concat_array(array, args))); - } - Ok(LhsValue::Bytes(bytes)) => { - return Some(LhsValue::Bytes(concat_bytes( - bytes.into_owned().into(), - args, - ))); - } - Err(_) => (), - _ => unreachable!(), - } - } - None - }) + ) -> CompiledFunction { + Box::new(concat_impl) } } @@ -133,7 +137,7 @@ mod tests { .into_iter(); assert_eq!( Some(LhsValue::Bytes(Bytes::Borrowed(b"helloworld"))), - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) + concat_impl(&mut args) ); } @@ -148,7 +152,7 @@ mod tests { .into_iter(); assert_eq!( Some(LhsValue::Bytes(Bytes::Borrowed(b"helloworldhello2world2"))), - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) + concat_impl(&mut args) ); } @@ -159,7 +163,7 @@ mod tests { let mut args = vec![Ok(arg1), Ok(arg2)].into_iter(); assert_eq!( Some(LhsValue::Array(Array::from_iter([1, 2, 3, 4, 5, 6]))), - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) + concat_impl(&mut args) ); } @@ -167,7 +171,7 @@ mod tests { #[should_panic] fn test_concat_function_bad_arg_type() { let mut args = vec![Ok(LhsValue::from(2))].into_iter(); - CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args); + concat_impl(&mut args); } #[test] diff --git a/engine/src/functions/mod.rs b/engine/src/functions/mod.rs index 5129791a..2af36b10 100644 --- a/engine/src/functions/mod.rs +++ b/engine/src/functions/mod.rs @@ -373,6 +373,13 @@ impl std::fmt::Debug for FunctionDefinitionContext { } } +/// A compiled function that can be called during filter execution. +/// +/// Returned by [`FunctionDefinition::compile`] after a function call expression +/// has been validated and compiled. +pub type CompiledFunction = + Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static>; + /// Trait to implement function pub trait FunctionDefinition: Debug + Send + Sync { /// Custom context to store information during parsing @@ -404,7 +411,7 @@ pub trait FunctionDefinition: Debug + Send + Sync { &self, params: &mut dyn ExactSizeIterator>, ctx: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static>; + ) -> CompiledFunction; } // Simple function APIs @@ -530,8 +537,7 @@ impl FunctionDefinition for SimpleFunctionDefinition { &self, params: &mut dyn ExactSizeIterator>, _: Option, - ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static> - { + ) -> CompiledFunction { let params_count = params.len(); let opt_params = &self.opt_params[(params_count - self.params.len())..]; let implementation = self.implementation; diff --git a/engine/src/lib.rs b/engine/src/lib.rs index e9953d1d..e003eb9b 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -96,10 +96,10 @@ pub use self::filter::{ CompiledExpr, CompiledOneExpr, CompiledValueExpr, CompiledVecExpr, Filter, FilterValue, }; pub use self::functions::{ - AllFunction, AnyFunction, ConcatFunction, FunctionArgInvalidConstantError, FunctionArgKind, - FunctionArgKindMismatchError, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, - FunctionParam, FunctionParamError, SimpleFunctionArgKind, SimpleFunctionDefinition, - SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, + AllFunction, AnyFunction, CompiledFunction, ConcatFunction, FunctionArgInvalidConstantError, + FunctionArgKind, FunctionArgKindMismatchError, FunctionArgs, FunctionDefinition, + FunctionDefinitionContext, FunctionParam, FunctionParamError, SimpleFunctionArgKind, + SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, }; pub use self::lex::LexErrorKind; pub use self::lhs_types::{Array, Bytes, Map, MapIter, TypedArray, TypedMap};