diff --git a/Cargo.lock b/Cargo.lock index 2eb04d28..df973240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,6 +103,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "arcstr" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" + [[package]] name = "autocfg" version = "1.5.1" @@ -1218,6 +1224,7 @@ dependencies = [ name = "wirefilter-engine" version = "0.7.0" dependencies = [ + "arcstr", "backtrace", "cfg-if", "cidr", diff --git a/Cargo.toml b/Cargo.toml index 1f13d21d..1d8b2591 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ edition = "2024" publish = true [workspace.dependencies] +arcstr = "1.2.0" backtrace = "0.3.76" cbindgen = "0.29.4" cfg-if = "1.0.4" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 616e86c2..2add20fa 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -20,6 +20,7 @@ harness = false name = "bench" [dependencies] +arcstr.workspace = true backtrace.workspace = true cfg-if.workspace = true cidr.workspace = true diff --git a/engine/benches/bench.rs b/engine/benches/bench.rs index 33a351ec..e79d04db 100644 --- a/engine/benches/bench.rs +++ b/engine/benches/bench.rs @@ -210,11 +210,11 @@ fn bench_string_function_comparison(c: &mut Criterion) { ( "lowercase", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(lowercase), }, @@ -222,11 +222,11 @@ fn bench_string_function_comparison(c: &mut Criterion) { ( "uppercase", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(uppercase), }, diff --git a/engine/examples/cli.rs b/engine/examples/cli.rs index 287ca368..5ff643c9 100644 --- a/engine/examples/cli.rs +++ b/engine/examples/cli.rs @@ -27,14 +27,14 @@ fn main() { .add_function( "panic", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![SimpleFunctionOptParam { + }]), + opt_params: Box::new([SimpleFunctionOptParam { arg_kind: SimpleFunctionArgKind::Literal, default_value: "".into(), - }], + }]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(panic_function), }, diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 4570bebc..6b45ef65 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -1401,11 +1401,11 @@ mod tests { .add_function( "echo", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(echo_function), }, @@ -1415,11 +1415,11 @@ mod tests { .add_function( "echo_ip", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Ip, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Ip, implementation: SimpleFunctionImpl::new(echo_function), }, @@ -1429,11 +1429,11 @@ mod tests { .add_function( "lowercase", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(lowercase_function), }, @@ -1443,8 +1443,8 @@ mod tests { .add_function( "concat", SimpleFunctionDefinition { - params: vec![], - opt_params: vec![ + params: Box::new([]), + opt_params: Box::new([ SimpleFunctionOptParam { arg_kind: SimpleFunctionArgKind::Field, default_value: "".into(), @@ -1453,7 +1453,7 @@ mod tests { arg_kind: SimpleFunctionArgKind::Literal, default_value: "".into(), }, - ], + ]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(concat_function), }, @@ -1463,7 +1463,7 @@ mod tests { .add_function( "concat_fields", SimpleFunctionDefinition { - params: vec![ + params: Box::new([ SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, @@ -1472,8 +1472,8 @@ mod tests { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, }, - ], - opt_params: vec![], + ]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(concat_function), }, @@ -1486,11 +1486,11 @@ mod tests { .add_function( "len", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Int, implementation: SimpleFunctionImpl::new(len_function), }, @@ -1500,8 +1500,8 @@ mod tests { .add_function( "counting_limit", SimpleFunctionDefinition { - params: vec![], - opt_params: vec![], + params: Box::new([]), + opt_params: Box::new([]), return_type: Type::Int, implementation: SimpleFunctionImpl::new(counting_limit_function), }, @@ -1522,7 +1522,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("ssl").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::IsTrue } @@ -1559,7 +1559,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("ip.addr").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::LessThanEqual, @@ -1626,7 +1626,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::GreaterThanEqual, @@ -1664,7 +1664,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::LessThan, @@ -1688,7 +1688,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -1727,7 +1727,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("tcp.port").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Int { op: IntOp::BitwiseAnd, @@ -1762,7 +1762,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("tcp.port").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::OneOf(LiteralSet::Int(vec![ 80.into(), @@ -1817,7 +1817,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::OneOf(LiteralSet::Bytes( ["example.org", "example.com",] @@ -1864,7 +1864,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("ip.addr").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::OneOf(LiteralSet::Ip(vec![ IpRange::Cidr(IpCidr::new([127, 0, 0, 0].into(), 8).unwrap()), @@ -1920,7 +1920,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Contains("abc".to_owned().into()) } @@ -1954,7 +1954,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Contains(vec![0x6F, 0x72, 0x67].into()), } @@ -1988,7 +1988,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("tcp.port").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::LessThan, @@ -2023,13 +2023,13 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("tcp.port").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::LessThan, rhs: ComparisonRhs::Index(ScalarExpr(IndexExpr { identifier: IdentifierExpr::Field(field("_tcp_limit").to_owned()), - indexes: vec![], + indexes: Box::new([]), })), }, } @@ -2382,7 +2382,7 @@ mod tests { fn test_scalar_expr_validation_and_conversion() { let index = IndexExpr { identifier: IdentifierExpr::Field(field("tcp.limit").to_owned()), - indexes: vec![], + indexes: Box::new([]), }; let scalar = ScalarExpr::try_from(index.clone()).unwrap(); assert_eq!(scalar.as_index_expr(), &index); @@ -2398,7 +2398,7 @@ mod tests { let bytes = IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }; let scalar_bytes = ScalarExpr::try_from(bytes.clone()).unwrap(); assert_eq!(scalar_bytes.get_type(), Type::Bytes); @@ -2417,7 +2417,7 @@ mod tests { let ip = IndexExpr { identifier: IdentifierExpr::Field(field("ip.addr").to_owned()), - indexes: vec![], + indexes: Box::new([]), }; let scalar_ip = ScalarExpr::try_from(ip.clone()).unwrap(); assert_eq!(scalar_ip.get_type(), Type::Ip); @@ -2432,7 +2432,7 @@ mod tests { let bool_expr = IndexExpr { identifier: IdentifierExpr::Field(field("ssl").to_owned()), - indexes: vec![], + indexes: Box::new([]), }; assert_eq!( ScalarExpr::try_from(bool_expr), @@ -2444,7 +2444,7 @@ mod tests { let mapped = IndexExpr { identifier: IdentifierExpr::Field(field("tcp.ports").to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }; assert_eq!( ScalarExpr::try_from(mapped), @@ -2461,13 +2461,15 @@ mod tests { impl<'a> VisitorMut<'a> for AddMapEach { fn visit_index_expr(&mut self, expr: &'a mut IndexExpr) { - expr.indexes.push(FieldIndex::MapEach); + let mut indexes = std::mem::take(&mut expr.indexes).into_vec(); + indexes.push(FieldIndex::MapEach); + expr.indexes = indexes.into_boxed_slice(); } } let index = IndexExpr { identifier: IdentifierExpr::Field(field("tcp.limit").to_owned()), - indexes: vec![], + indexes: Box::new([]), }; let mut scalar = ScalarExpr::try_from(index.clone()).unwrap(); AddMapEach.visit_scalar_expr(&mut scalar); @@ -2805,7 +2807,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![FieldIndex::ArrayIndex(0)], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), }, op: ComparisonOpExpr::Contains("abc".to_owned().into()), } @@ -2832,7 +2834,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.headers").to_owned()), - indexes: vec![FieldIndex::MapKey("host".to_string())], + indexes: Box::new([FieldIndex::MapKey("host".into())]), }, op: ComparisonOpExpr::Contains("abc".to_owned().into()), } @@ -2880,13 +2882,13 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("echo").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], - })], + indexes: Box::new([]), + })]), context: None, }), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -2938,13 +2940,13 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("lowercase").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], - })], + indexes: Box::new([]), + })]), context: None, }), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -2995,7 +2997,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![FieldIndex::ArrayIndex(0)], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3033,7 +3035,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![FieldIndex::ArrayIndex(0)], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::NotEqual, @@ -3071,7 +3073,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.headers").to_owned()), - indexes: vec![FieldIndex::MapKey("missing".into())], + indexes: Box::new([FieldIndex::MapKey("missing".into())]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3109,7 +3111,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.headers").to_owned()), - indexes: vec![FieldIndex::MapKey("missing".into())], + indexes: Box::new([FieldIndex::MapKey("missing".into())]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::NotEqual, @@ -3148,13 +3150,13 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("concat").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], - })], + indexes: Box::new([]), + })]), context: None, }), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3203,18 +3205,18 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("concat").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::from( ".org".to_owned() ))), - ], + ]), context: None, }), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3270,21 +3272,21 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("filter").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![], + indexes: Box::new([]), }), FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( field("array.of.bool").to_owned() ), - indexes: vec![], + indexes: Box::new([]), }), - ], + ]), context: None, }), - indexes: vec![FieldIndex::ArrayIndex(0)], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3345,18 +3347,18 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("concat").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::from( "-cf".to_owned() ))), - ], + ]), context: None, }), - indexes: vec![FieldIndex::ArrayIndex(2)], + indexes: Box::new([FieldIndex::ArrayIndex(2)]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3414,18 +3416,18 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("concat").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.headers").to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::from( "-cf".to_owned() ))), - ], + ]), context: None, }), - indexes: vec![FieldIndex::ArrayIndex(2)], + indexes: Box::new([FieldIndex::ArrayIndex(2)]), }, op: ComparisonOpExpr::OneOf(LiteralSet::Bytes(vec![ "one-cf".to_owned().into(), @@ -3568,7 +3570,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3602,7 +3604,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.headers").to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3660,18 +3662,18 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("concat").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::from( "-cf".to_owned() ))), - ], + ]), context: None, }), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -3728,13 +3730,13 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("len").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), - indexes: vec![FieldIndex::MapEach], - }),], + indexes: Box::new([FieldIndex::MapEach]), + }),]), context: None, }), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::GreaterThan, @@ -3860,7 +3862,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("tcp.port").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::InList { list: list.to_owned(), @@ -3894,7 +3896,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("tcp.port").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::InList { list: list.to_owned(), @@ -3929,7 +3931,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("tcp.ports").to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::InList { list: list.to_owned(), @@ -4009,7 +4011,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.parts").to_owned()), - indexes: vec![FieldIndex::MapEach, FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach, FieldIndex::MapEach]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -4036,7 +4038,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.parts").to_owned()), - indexes: vec![FieldIndex::ArrayIndex(5), FieldIndex::MapEach], + indexes: Box::new([FieldIndex::ArrayIndex(5), FieldIndex::MapEach]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -4063,7 +4065,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.parts").to_owned()), - indexes: vec![FieldIndex::MapEach, FieldIndex::ArrayIndex(5)], + indexes: Box::new([FieldIndex::MapEach, FieldIndex::ArrayIndex(5)]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -4140,7 +4142,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -4178,7 +4180,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Matches(r), } @@ -4213,7 +4215,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Wildcard(wildcard), } @@ -4258,7 +4260,7 @@ mod tests { ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::StrictWildcard(wildcard), } @@ -4298,19 +4300,19 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("concat").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(field("http.host").to_owned()), - indexes: vec![], + indexes: Box::new([]), }), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::new( "cd".as_bytes(), BytesFormat::Raw(1) ))) - ], + ]), context: None, }), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index 4f3b17d9..33cf1a88 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -228,7 +228,7 @@ impl<'a> From<&'a FunctionCallArgExpr> for FunctionParam<'a> { pub struct FunctionCallExpr { #[serde(rename = "name")] pub(crate) function: Function, - pub(crate) args: Vec, + pub(crate) args: Box<[FunctionCallArgExpr]>, #[serde(skip)] pub(crate) context: Option, } @@ -297,6 +297,7 @@ impl ValueExpr for FunctionCallExpr { if map_each_count > 0 { let first = args.remove(0); + let args = args.into_boxed_slice(); #[inline(always)] fn compute<'a, I: ExactSizeIterator>>( @@ -381,6 +382,7 @@ impl ValueExpr for FunctionCallExpr { }) } } else { + let args = args.into_boxed_slice(); CompiledValueExpr::new(move |ctx| { match call(&mut args.iter().map(|arg| arg.execute(ctx))) { Some(value) => { @@ -397,7 +399,7 @@ impl ValueExpr for FunctionCallExpr { impl FunctionCallExpr { pub(crate) fn new( function: Function, - args: Vec, + args: Box<[FunctionCallArgExpr]>, context: Option, ) -> Self { Self { @@ -500,7 +502,8 @@ impl FunctionCallExpr { input = expect(input, ")")?; - let function_call = FunctionCallExpr::new(function.to_owned(), args, ctx); + let function_call = + FunctionCallExpr::new(function.to_owned(), args.into_boxed_slice(), ctx); Ok((function_call, input)) } @@ -670,11 +673,11 @@ mod tests { .add_function( "echo", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![ + }]), + opt_params: Box::new([ SimpleFunctionOptParam { arg_kind: SimpleFunctionArgKind::Literal, default_value: LhsValue::Int(10), @@ -683,7 +686,7 @@ mod tests { arg_kind: SimpleFunctionArgKind::Literal, default_value: LhsValue::Int(1), }, - ], + ]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(echo_function), }, @@ -693,11 +696,11 @@ mod tests { .add_function( "lower", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(lower_function), }, @@ -707,7 +710,7 @@ mod tests { .add_function( "regex_replace", SimpleFunctionDefinition { - params: vec![ + params: Box::new([ SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, @@ -720,8 +723,8 @@ mod tests { arg_kind: SimpleFunctionArgKind::Literal, val_type: Type::Bytes, }, - ], - opt_params: vec![], + ]), + opt_params: Box::new([]), return_type: Type::Bool, implementation: SimpleFunctionImpl::new(regex_replace), }, @@ -731,11 +734,11 @@ mod tests { .add_function( "len", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Int, implementation: SimpleFunctionImpl::new(len_function), }, @@ -751,16 +754,16 @@ mod tests { FilterParser::new(&SCHEME).lex_as(r#"echo ( http.host, 1, 2 );"#), FunctionCallExpr { function: SCHEME.get_function("echo").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("http.host").unwrap().to_owned() ), - indexes: vec![], + indexes: Box::new([]), }), FunctionCallArgExpr::Literal(LiteralValue::Int(1)), FunctionCallArgExpr::Literal(LiteralValue::Int(2)), - ], + ]), context: None, }, ";" @@ -794,12 +797,12 @@ mod tests { FilterParser::new(&SCHEME).lex_as("echo ( http.host );"), FunctionCallExpr { function: SCHEME.get_function("echo").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("http.host").unwrap().to_owned() ), - indexes: vec![], - })], + indexes: Box::new([]), + })]), context: None, }, ";" @@ -826,16 +829,16 @@ mod tests { FilterParser::new(&SCHEME).lex_as(r#"echo (http.host,1,2);"#), FunctionCallExpr { function: SCHEME.get_function("echo").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("http.host").unwrap().to_owned() ), - indexes: vec![], + indexes: Box::new([]), }), FunctionCallArgExpr::Literal(LiteralValue::Int(1)), FunctionCallArgExpr::Literal(LiteralValue::Int(2)), - ], + ]), context: None, }, ";" @@ -894,17 +897,18 @@ mod tests { args: [FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("echo").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("http.host").unwrap().to_owned() ), - indexes: vec![], - })], + indexes: Box::new([]), + })]), context: None, }), - indexes: vec![], + indexes: Box::new([]), })] - .to_vec(), + .to_vec() + .into_boxed_slice(), context: None, }, ";" @@ -953,7 +957,7 @@ mod tests { .unwrap() .to_owned() ), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::IsTrue, }), @@ -965,7 +969,7 @@ mod tests { .unwrap() .to_owned() ), - indexes: vec![], + indexes: Box::new([]), }, op: ComparisonOpExpr::IsTrue, }) @@ -1006,15 +1010,15 @@ mod tests { FilterParser::new(&SCHEME).lex_as("echo ( http.request.headers.names[*] );"), FunctionCallExpr { function: SCHEME.get_function("echo").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME .get_field("http.request.headers.names") .unwrap() .to_owned() ), - indexes: vec![FieldIndex::MapEach], - })], + indexes: Box::new([FieldIndex::MapEach]), + })]), context: None, }, ";" @@ -1040,12 +1044,12 @@ mod tests { FilterParser::new(&SCHEME).lex_as("echo ( http.headers[*] );"), FunctionCallExpr { function: SCHEME.get_function("echo").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("http.headers").unwrap().to_owned() ), - indexes: vec![FieldIndex::MapEach], - })], + indexes: Box::new([FieldIndex::MapEach]), + })]), context: None, }, ";" @@ -1077,7 +1081,7 @@ mod tests { .unwrap() .to_owned() ), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, @@ -1097,18 +1101,18 @@ mod tests { lhs: IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("lower").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME .get_field("http.request.headers.names") .unwrap() .to_owned() ), - indexes: vec![FieldIndex::MapEach], - })], + indexes: Box::new([FieldIndex::MapEach]), + })]), context: None, }), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::Contains("c".to_string().into(),) } @@ -1156,15 +1160,15 @@ mod tests { FilterParser::new(&SCHEME).lex_as("len(http.request.headers.names[*])"), FunctionCallExpr { function: SCHEME.get_function("len").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME .get_field("http.request.headers.names") .unwrap() .to_owned() ), - indexes: vec![FieldIndex::MapEach], - })], + indexes: Box::new([FieldIndex::MapEach]), + })]), context: None, }, "" @@ -1193,7 +1197,7 @@ mod tests { .unwrap() .to_owned() ), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::OneOf(LiteralSet::Bytes(vec![ "Cookie".to_owned().into(), @@ -1250,7 +1254,7 @@ mod tests { .unwrap() .to_owned() ), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::OneOf(LiteralSet::Bytes(vec![ "Cookie".to_owned().into(), @@ -1298,14 +1302,14 @@ mod tests { FilterParser::new(&SCHEME).lex_as("regex_replace(http.host, r\"this is a r##raw## string\", r\"this is a new r##raw## string\") eq \"test\""), FunctionCallExpr { function: SCHEME.get_function("regex_replace").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("http.host").unwrap().to_owned()), - indexes: vec![], + indexes: Box::new([]), }), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::new("this is a r##raw## string".as_bytes(), BytesFormat::Raw(0)))), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::new("this is a new r##raw## string".as_bytes(), BytesFormat::Raw(0)))) - ], + ]), context: None, }, " eq \"test\"" @@ -1339,14 +1343,14 @@ mod tests { FilterParser::new(&SCHEME).lex_as("regex_replace(http.host, r###\"this is a r##\"raw\"## string\"###, r###\"this is a new r##\"raw\"## string\"###) eq \"test\""), FunctionCallExpr { function: SCHEME.get_function("regex_replace").unwrap().to_owned(), - args: vec![ + args: Box::new([ FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("http.host").unwrap().to_owned()), - indexes: vec![], + indexes: Box::new([]), }), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::new("this is a r##\"raw\"## string".as_bytes(), BytesFormat::Raw(3)))), FunctionCallArgExpr::Literal(LiteralValue::Bytes(BytesExpr::new("this is a new r##\"raw\"## string".as_bytes(), BytesFormat::Raw(3)))) - ], + ]), context: None, }, " eq \"test\"" @@ -1491,7 +1495,7 @@ mod tests { FilterParser::new(&SCHEME) .lex_as::("echo ( http.headers[*][\"host\"] );"), LexErrorKind::InvalidIndexAccess(IndexAccessError { - index: FieldIndex::MapKey("host".to_string()), + index: FieldIndex::MapKey("host".into()), actual: Type::Bytes, }), "[\"host\"]" diff --git a/engine/src/ast/index_expr.rs b/engine/src/ast/index_expr.rs index 63468e2c..7c35e56a 100644 --- a/engine/src/ast/index_expr.rs +++ b/engine/src/ast/index_expr.rs @@ -25,7 +25,7 @@ pub struct IndexExpr { /// The accessed identifier. pub identifier: IdentifierExpr, /// The list of indexes access. - pub indexes: Vec, + pub indexes: Box<[FieldIndex]>, } #[allow(clippy::manual_ok_err)] @@ -127,11 +127,14 @@ impl ValueExpr for IndexExpr { } } -fn simplify_indexes(mut indexes: Vec) -> Box<[FieldIndex]> { +fn simplify_indexes(indexes: Box<[FieldIndex]>) -> Box<[FieldIndex]> { if Some(&FieldIndex::MapEach) == indexes.last() { + let mut indexes = indexes.into_vec(); indexes.pop(); + indexes.into_boxed_slice() + } else { + indexes } - indexes.into_boxed_slice() } /// Interface used to implement comparison against a value. @@ -403,7 +406,7 @@ impl<'i, 's> LexWith<'i, &FilterParser<'s>> for IndexExpr { Ok(( IndexExpr { identifier, - indexes, + indexes: indexes.into_boxed_slice(), }, input, )) @@ -582,11 +585,11 @@ mod tests { .add_function( "array", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Array(Type::Bytes.into()), implementation: SimpleFunctionImpl::new(array_function), }, @@ -596,11 +599,11 @@ mod tests { .add_function( "array2", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Array(Type::Array(Type::Bytes.into()).into()), implementation: SimpleFunctionImpl::new(array2_function), }, @@ -617,7 +620,7 @@ mod tests { FilterParser::new(&SCHEME).lex_as(&filter), IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("test").unwrap().to_owned()), - indexes: vec![FieldIndex::ArrayIndex(i)], + indexes: Box::new([FieldIndex::ArrayIndex(i)]), } ); } @@ -642,7 +645,7 @@ mod tests { FilterParser::new(&SCHEME).lex_as(r#"map["a"]"#), IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("map").unwrap().to_owned()), - indexes: vec![FieldIndex::MapKey("a".to_string())], + indexes: Box::new([FieldIndex::MapKey("a".into())]), } ); @@ -650,7 +653,7 @@ mod tests { FilterParser::new(&SCHEME).lex_as(r#"map["😍"]"#), IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("map").unwrap().to_owned()), - indexes: vec![FieldIndex::MapKey("😍".to_string())], + indexes: Box::new([FieldIndex::MapKey("😍".into())]), } ); } @@ -677,15 +680,15 @@ mod tests { IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("array").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("test").unwrap().to_owned() ), - indexes: vec![FieldIndex::ArrayIndex(0)], - })], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), + })]), context: None }), - indexes: vec![FieldIndex::ArrayIndex(0)], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), } ); @@ -707,15 +710,15 @@ mod tests { IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("array").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("test").unwrap().to_owned() ), - indexes: vec![FieldIndex::ArrayIndex(0)], - })], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), + })]), context: None }), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), } ); @@ -740,15 +743,15 @@ mod tests { IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("array2").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("test").unwrap().to_owned() ), - indexes: vec![FieldIndex::ArrayIndex(0)], - })], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), + })]), context: None }), - indexes: vec![FieldIndex::MapEach, FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach, FieldIndex::MapEach]), } ); @@ -776,15 +779,15 @@ mod tests { IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("array2").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("test").unwrap().to_owned() ), - indexes: vec![FieldIndex::ArrayIndex(0)], - })], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), + })]), context: None }), - indexes: vec![FieldIndex::MapEach, FieldIndex::ArrayIndex(0)], + indexes: Box::new([FieldIndex::MapEach, FieldIndex::ArrayIndex(0)]), } ); @@ -812,15 +815,15 @@ mod tests { IndexExpr { identifier: IdentifierExpr::FunctionCallExpr(FunctionCallExpr { function: SCHEME.get_function("array2").unwrap().to_owned(), - args: vec![FunctionCallArgExpr::IndexExpr(IndexExpr { + args: Box::new([FunctionCallArgExpr::IndexExpr(IndexExpr { identifier: IdentifierExpr::Field( SCHEME.get_field("test").unwrap().to_owned() ), - indexes: vec![FieldIndex::ArrayIndex(0)], - })], + indexes: Box::new([FieldIndex::ArrayIndex(0)]), + })]), context: None }), - indexes: vec![FieldIndex::ArrayIndex(0), FieldIndex::MapEach], + indexes: Box::new([FieldIndex::ArrayIndex(0), FieldIndex::MapEach]), } ); @@ -852,7 +855,7 @@ mod tests { FilterParser::new(&SCHEME).lex_as(&filter), IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("test2").unwrap().to_owned()), - indexes: vec![FieldIndex::ArrayIndex(0), FieldIndex::MapEach], + indexes: Box::new([FieldIndex::ArrayIndex(0), FieldIndex::MapEach]), } ); @@ -866,7 +869,7 @@ mod tests { FilterParser::new(&SCHEME).lex_as(&filter), IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("test2").unwrap().to_owned()), - indexes: vec![FieldIndex::MapEach, FieldIndex::ArrayIndex(0)], + indexes: Box::new([FieldIndex::MapEach, FieldIndex::ArrayIndex(0)]), } ); @@ -880,7 +883,7 @@ mod tests { FilterParser::new(&SCHEME).lex_as(&filter), IndexExpr { identifier: IdentifierExpr::Field(SCHEME.get_field("test2").unwrap().to_owned()), - indexes: vec![FieldIndex::MapEach, FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach, FieldIndex::MapEach]), } ); diff --git a/engine/src/ast/logical_expr.rs b/engine/src/ast/logical_expr.rs index 7c535174..7eaef361 100644 --- a/engine/src/ast/logical_expr.rs +++ b/engine/src/ast/logical_expr.rs @@ -925,7 +925,7 @@ fn test() { LogicalExpr::Comparison(ComparisonExpr { lhs: IndexExpr { identifier: IdentifierExpr::Field(scheme.get_field("at").unwrap().to_owned()), - indexes: vec![FieldIndex::MapEach], + indexes: Box::new([FieldIndex::MapEach]), }, op: ComparisonOpExpr::IsTrue }) diff --git a/engine/src/ast/visitor.rs b/engine/src/ast/visitor.rs index e4435ce2..98860ed5 100644 --- a/engine/src/ast/visitor.rs +++ b/engine/src/ast/visitor.rs @@ -260,11 +260,11 @@ mod tests { .add_function( "echo", SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Bytes, - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(|args| args.next()?.ok()), }, diff --git a/engine/src/execution_context.rs b/engine/src/execution_context.rs index 58b0e8ce..fdb9eb05 100644 --- a/engine/src/execution_context.rs +++ b/engine/src/execution_context.rs @@ -29,8 +29,8 @@ pub enum SetFieldValueError { #[derive(Debug, PartialEq, Eq, Error)] #[error("Invalid list matcher {matcher} for list {list}")] pub struct InvalidListMatcherError { - matcher: String, - list: String, + matcher: Box, + list: Box, } /// An execution context stores an associated [`struct@crate::Scheme`] and a diff --git a/engine/src/functions/mod.rs b/engine/src/functions/mod.rs index 851b3eb7..d180b214 100644 --- a/engine/src/functions/mod.rs +++ b/engine/src/functions/mod.rs @@ -117,13 +117,13 @@ pub struct FunctionArgKindMismatchError { #[derive(Debug, PartialEq, Eq, Error)] #[error("invalid argument: {msg:?}")] pub struct FunctionArgInvalidConstantError { - msg: String, + msg: Box, } impl FunctionArgInvalidConstantError { /// Returns a new invalid constant error. #[inline] - pub fn new(msg: String) -> Self { + pub fn new(msg: Box) -> Self { Self { msg } } } @@ -131,7 +131,7 @@ impl FunctionArgInvalidConstantError { impl From for FunctionArgInvalidConstantError { #[inline] fn from(msg: String) -> Self { - Self::new(msg) + Self::new(msg.into_boxed_str()) } } @@ -264,7 +264,9 @@ impl<'a> FunctionParam<'a> { match self { Self::Constant(value) => { op(U::try_from(value).map_err(FunctionParamError::TypeMismatch)?).map_err(|msg| { - FunctionParamError::InvalidConstant(FunctionArgInvalidConstantError { msg }) + FunctionParamError::InvalidConstant(FunctionArgInvalidConstantError { + msg: msg.into_boxed_str(), + }) }) } Self::Variable(_) => Err(FunctionParamError::KindMismatch( @@ -484,9 +486,9 @@ pub struct SimpleFunctionOptParam { #[derive(Debug, PartialEq, Eq, Clone)] pub struct SimpleFunctionDefinition { /// List of mandatory arguments. - pub params: Vec, + pub params: Box<[SimpleFunctionParam]>, /// List of optional arguments that can be specified after manatory ones. - pub opt_params: Vec, + pub opt_params: Box<[SimpleFunctionOptParam]>, /// Function return type. pub return_type: Type, /// Actual implementation that will be called at runtime. @@ -543,7 +545,7 @@ impl FunctionDefinition for SimpleFunctionDefinition { (implementation.0)(args) }) } else { - let opt_args: Vec, Type>> = opt_params + let opt_args: Box<[Result, Type>]> = opt_params .iter() .map(|opt_param| Ok(opt_param.default_value.clone())) .collect(); diff --git a/engine/src/lex.rs b/engine/src/lex.rs index d6cdcf0d..669ec181 100644 --- a/engine/src/lex.rs +++ b/engine/src/lex.rs @@ -148,7 +148,7 @@ pub enum LexErrorKind { #[error("invalid list name {name:?}")] InvalidListName { /// Name of the list - name: String, + name: Box, }, /// Maximum nesting depth exceeded while parsing. diff --git a/engine/src/range_set.rs b/engine/src/range_set.rs index e024f787..c89c7029 100644 --- a/engine/src/range_set.rs +++ b/engine/src/range_set.rs @@ -6,7 +6,7 @@ use std::ops::RangeInclusive; /// RangeSet provides a set-like interface that allows to search for items while /// being constructed from and storing inclusive ranges in a compact fashion. pub struct RangeSet { - ranges: Vec>, + ranges: Box<[RangeInclusive]>, } impl From>> for RangeSet { @@ -26,7 +26,9 @@ impl From>> for RangeSet { false } }); - RangeSet { ranges } + RangeSet { + ranges: ranges.into_boxed_slice(), + } } } diff --git a/engine/src/rhs_types/list.rs b/engine/src/rhs_types/list.rs index def7bf95..e98b9024 100644 --- a/engine/src/rhs_types/list.rs +++ b/engine/src/rhs_types/list.rs @@ -26,7 +26,7 @@ impl Lex<'_> for ListName { if res.is_empty() { return Err(( LexErrorKind::InvalidListName { - name: c.to_string(), + name: c.to_string().into_boxed_str(), }, input, )); @@ -37,7 +37,12 @@ impl Lex<'_> for ListName { }, None => { if res.is_empty() { - return Err((LexErrorKind::InvalidListName { name: res }, input)); + return Err(( + LexErrorKind::InvalidListName { + name: res.into_boxed_str(), + }, + input, + )); } else { break; } @@ -46,7 +51,12 @@ impl Lex<'_> for ListName { } if res.as_bytes().first() == Some(&b'.') || res.as_bytes().last() == Some(&b'.') { - return Err((LexErrorKind::InvalidListName { name: res }, input)); + return Err(( + LexErrorKind::InvalidListName { + name: res.into_boxed_str(), + }, + input, + )); } Ok((res.into(), rest)) @@ -100,9 +110,7 @@ mod test { fn invalid_char() { assert_err!( ListName::lex("$;"), - LexErrorKind::InvalidListName { - name: ";".to_string(), - }, + LexErrorKind::InvalidListName { name: ";".into() }, ";" ); } @@ -111,9 +119,7 @@ mod test { fn eof_after_dollar() { assert_err!( ListName::lex("$"), - LexErrorKind::InvalidListName { - name: "".to_string(), - }, + LexErrorKind::InvalidListName { name: "".into() }, "" ); } @@ -131,16 +137,14 @@ mod test { fn special_char_at_start() { assert_err!( ListName::lex("$."), - LexErrorKind::InvalidListName { - name: ".".to_string(), - }, + LexErrorKind::InvalidListName { name: ".".into() }, "." ); assert_err!( ListName::lex("$.abc"), LexErrorKind::InvalidListName { - name: ".abc".to_string(), + name: ".abc".into(), }, ".abc" ); @@ -150,16 +154,14 @@ mod test { fn special_char_at_end() { assert_err!( ListName::lex("$."), - LexErrorKind::InvalidListName { - name: ".".to_string(), - }, + LexErrorKind::InvalidListName { name: ".".into() }, "." ); assert_err!( ListName::lex("$abc."), LexErrorKind::InvalidListName { - name: "abc.".to_string(), + name: "abc.".into(), }, "abc." ); diff --git a/engine/src/rhs_types/regex/imp_real.rs b/engine/src/rhs_types/regex/imp_real.rs index 8ac0d294..637539bc 100644 --- a/engine/src/rhs_types/regex/imp_real.rs +++ b/engine/src/rhs_types/regex/imp_real.rs @@ -1,13 +1,13 @@ use super::Error; use crate::{ParserSettings, RegexFormat}; +use arcstr::ArcStr; use regex_automata::MatchKind; use regex_automata::nfa::thompson::WhichCaptures; -use std::sync::Arc; /// Wrapper around [`regex_automata::meta::Regex`] #[derive(Clone)] pub struct Regex { - pattern: Arc, + pattern: ArcStr, regex: regex_automata::meta::Regex, format: RegexFormat, } @@ -37,16 +37,17 @@ impl Regex { /// Compiles a regular expression. pub fn new( - pattern: &str, + pattern: impl Into, format: RegexFormat, settings: &ParserSettings, ) -> Result { + let pattern = pattern.into(); ::regex_automata::meta::Builder::new() .configure(Self::meta_config(settings)) .syntax(Self::syntax_config()) - .build(pattern) + .build(&pattern) .map(|regex| Regex { - pattern: Arc::from(pattern), + pattern, regex, format, }) @@ -54,9 +55,9 @@ impl Regex { if let Some(limit) = err.size_limit() { Error::CompiledTooBig(limit) } else if let Some(syntax) = err.syntax_error() { - Error::Syntax(syntax.to_string()) + Error::Syntax(syntax.to_string().into_boxed_str()) } else { - Error::Other(err.to_string()) + Error::Other(err.to_string().into_boxed_str()) } }) } @@ -67,6 +68,12 @@ impl Regex { &self.pattern } + /// Returns the shared pattern of this regex. + #[inline] + pub fn pattern(&self) -> &ArcStr { + &self.pattern + } + /// Returns the format used by the pattern. #[inline] pub fn format(&self) -> RegexFormat { diff --git a/engine/src/rhs_types/regex/imp_stub.rs b/engine/src/rhs_types/regex/imp_stub.rs index 00e03d0f..117b4036 100644 --- a/engine/src/rhs_types/regex/imp_stub.rs +++ b/engine/src/rhs_types/regex/imp_stub.rs @@ -1,23 +1,24 @@ -use crate::{FilterParser, RegexFormat}; -use thiserror::Error; - -/// Dummy regex error. -#[derive(Debug, PartialEq, Error)] -pub enum Error {} +use super::Error; +use crate::{ParserSettings, RegexFormat}; +use arcstr::ArcStr; /// Dummy regex wrapper that can only store a pattern /// but not actually be used for matching. #[derive(Clone)] pub struct Regex { - pattern: String, + pattern: ArcStr, format: RegexFormat, } impl Regex { /// Creates a new dummy regex. - pub fn new(pattern: &str, format: RegexFormat, _: &FilterParser<'_>) -> Result { + pub fn new( + pattern: impl Into, + format: RegexFormat, + _: &ParserSettings, + ) -> Result { Ok(Self { - pattern: pattern.to_string(), + pattern: pattern.into(), format, }) } @@ -29,7 +30,13 @@ impl Regex { /// Returns the original string of this dummy regex wrapper. pub fn as_str(&self) -> &str { - self.pattern.as_str() + &self.pattern + } + + /// Returns the shared pattern of this dummy regex wrapper. + #[inline] + pub fn pattern(&self) -> &ArcStr { + &self.pattern } /// Returns the format behind the regex diff --git a/engine/src/rhs_types/regex/mod.rs b/engine/src/rhs_types/regex/mod.rs index 3ed5b096..67b1918a 100644 --- a/engine/src/rhs_types/regex/mod.rs +++ b/engine/src/rhs_types/regex/mod.rs @@ -136,14 +136,14 @@ impl Serialize for Regex { pub enum Error { /// A syntax error. #[error("{0}")] - Syntax(String), + Syntax(Box), /// The compiled regex exceeded the configured /// regex compiled size limit. #[error("Compiled regex exceeds size limit of {0} bytes.")] CompiledTooBig(usize), /// An uncategorized error. #[error("{0}")] - Other(String), + Other(Box), } impl Compare for Regex { diff --git a/engine/src/scheme.rs b/engine/src/scheme.rs index 05f3b075..3e6b0343 100644 --- a/engine/src/scheme.rs +++ b/engine/src/scheme.rs @@ -41,7 +41,7 @@ pub enum FieldIndex { ArrayIndex(u32), /// Key into a Map - MapKey(String), + MapKey(Box), /// Map each element by applying a function or a comparison MapEach, @@ -77,7 +77,7 @@ impl<'i> Lex<'i> for FieldIndex { )), }, LiteralValue::Bytes(b) => match String::from_utf8(b.into()) { - Ok(s) => Ok((FieldIndex::MapKey(s), rest)), + Ok(s) => Ok((FieldIndex::MapKey(s.into_boxed_str()), rest)), Err(_) => Err((LexErrorKind::ExpectedLiteral("expected utf8 string"), input)), }, _ => unreachable!(), @@ -471,12 +471,12 @@ pub struct UnknownFunctionError; /// An error that occurs when previously defined field gets redefined. #[derive(Debug, PartialEq, Eq, Error)] #[error("attempt to redefine field {0}")] -pub struct FieldRedefinitionError(String); +pub struct FieldRedefinitionError(Box); /// An error that occurs when previously defined function gets redefined. #[derive(Debug, PartialEq, Eq, Error)] #[error("attempt to redefine function {0}")] -pub struct FunctionRedefinitionError(String); +pub struct FunctionRedefinitionError(Box); /// An error that occurs when trying to redefine a field or function. #[derive(Debug, PartialEq, Eq, Error)] @@ -495,7 +495,7 @@ pub enum IdentifierRedefinitionError { pub enum IdentifierRegistrationError { /// The identifier does not follow the syntax accepted for registration. #[error("invalid identifier {0}")] - InvalidIdentifier(String), + InvalidIdentifier(Box), /// The identifier is already registered as a field or function. #[error("{0}")] @@ -675,18 +675,18 @@ impl SchemeBuilder { optional: bool, ) -> Result<(), IdentifierRegistrationError> { if !is_valid_identifier(&name) { - return Err(IdentifierRegistrationError::InvalidIdentifier( - name.to_string(), - )); + return Err(IdentifierRegistrationError::InvalidIdentifier(Box::from( + name.as_ref(), + ))); } match self.items.entry(name) { Entry::Occupied(entry) => Err(match entry.get() { SchemeItem::Field(_) => IdentifierRedefinitionError::Field(FieldRedefinitionError( - entry.key().to_string(), + Box::from(entry.key().as_ref()), )), SchemeItem::Function(_) => IdentifierRedefinitionError::Function( - FunctionRedefinitionError(entry.key().to_string()), + FunctionRedefinitionError(Box::from(entry.key().as_ref())), ), } .into()), @@ -729,18 +729,18 @@ impl SchemeBuilder { ) -> Result<(), IdentifierRegistrationError> { let name = name.as_ref(); if !is_valid_identifier(name) { - return Err(IdentifierRegistrationError::InvalidIdentifier( - name.to_string(), - )); + return Err(IdentifierRegistrationError::InvalidIdentifier(Box::from( + name, + ))); } match self.items.entry(name.into()) { Entry::Occupied(entry) => Err(match entry.get() { SchemeItem::Field(_) => IdentifierRedefinitionError::Field(FieldRedefinitionError( - entry.key().to_string(), + Box::from(entry.key().as_ref()), )), SchemeItem::Function(_) => IdentifierRedefinitionError::Function( - FunctionRedefinitionError(entry.key().to_string()), + FunctionRedefinitionError(Box::from(entry.key().as_ref())), ), } .into()), @@ -782,8 +782,23 @@ impl SchemeBuilder { /// Build a new [`Scheme`] from this builder. pub fn build(self) -> Scheme { + let Self { + fields, + functions, + items, + list_types, + lists, + nil_not_equal_is_false, + } = self; Scheme { - inner: Arc::new(self), + inner: Arc::new(SchemeData { + fields: fields.into_boxed_slice(), + functions: functions.into_boxed_slice(), + items, + list_types, + lists: lists.into_boxed_slice(), + nil_not_equal_is_false, + }), } } } @@ -808,7 +823,17 @@ impl> FromIterator<(N, Type)> for SchemeBuilder { /// in ambiguous contexts. #[derive(Clone, Debug)] pub struct Scheme { - inner: Arc, + inner: Arc, +} + +#[derive(Debug)] +struct SchemeData { + fields: Box<[FieldDefinition]>, + functions: Box<[(IdentifierName, Box)]>, + items: HashMap, + list_types: HashMap, + lists: Box<[(Type, Box)]>, + nil_not_equal_is_false: bool, } impl PartialEq for Scheme { diff --git a/fuzz/map-keys/src/main.rs b/fuzz/map-keys/src/main.rs index 80b2c36b..f2e8b2ab 100644 --- a/fuzz/map-keys/src/main.rs +++ b/fuzz/map-keys/src/main.rs @@ -56,11 +56,11 @@ fn first_impl<'a>(args: FunctionArgs<'_, 'a>) -> Option> { // function are true. pub static FIRST_FN: LazyLock = LazyLock::new(|| SimpleFunctionDefinition { - params: vec![SimpleFunctionParam { + params: Box::new([SimpleFunctionParam { arg_kind: SimpleFunctionArgKind::Field, val_type: Type::Map(Type::Bytes.into()), - }], - opt_params: vec![], + }]), + opt_params: Box::new([]), return_type: Type::Bytes, implementation: SimpleFunctionImpl::new(first_impl), });