From bcc69c10741ca80dbb16751bd7e597f89c23015d Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Thu, 9 Oct 2025 11:04:51 +0200 Subject: [PATCH 01/30] regex: only enable implicit capture groups --- engine/src/rhs_types/regex/imp_real.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/src/rhs_types/regex/imp_real.rs b/engine/src/rhs_types/regex/imp_real.rs index 7171828a..2b5a6480 100644 --- a/engine/src/rhs_types/regex/imp_real.rs +++ b/engine/src/rhs_types/regex/imp_real.rs @@ -1,4 +1,5 @@ use regex_automata::MatchKind; +use regex_automata::nfa::thompson::WhichCaptures; use super::Error; use crate::{ParserSettings, RegexFormat}; @@ -33,6 +34,7 @@ impl Regex { .onepass(false) .dfa_size_limit(Some(settings.regex_compiled_size_limit)) .hybrid_cache_capacity(settings.regex_dfa_size_limit) + .which_captures(WhichCaptures::Implicit) } /// Compiles a regular expression. From 21d5f1253be56ffe3dfc44b6745d86d03dbb7219 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Fri, 7 Nov 2025 18:07:58 +0100 Subject: [PATCH 02/30] Fix `FieldIndex` documentation --- engine/src/scheme.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/src/scheme.rs b/engine/src/scheme.rs index 48e55a15..c23066ad 100644 --- a/engine/src/scheme.rs +++ b/engine/src/scheme.rs @@ -29,11 +29,9 @@ use thiserror::Error; #[error("underlying schemes do not match")] pub struct SchemeMismatchError; -#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize)] -#[serde(tag = "kind", content = "value")] -/// FieldIndex is an enum with variants [`ArrayIndex(usize)`], -/// representing an index into an Array, or `[MapKey(String)`], -/// representing a key into a Map. +/// Enum representing either: +/// * An array index with [`FieldIndex::ArrayIndex`] +/// * A map key with [`FieldIndex::MapKey`] /// /// ``` /// #[allow(dead_code)] @@ -42,6 +40,8 @@ pub struct SchemeMismatchError; /// MapKey(String), /// } /// ``` +#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize)] +#[serde(tag = "kind", content = "value")] pub enum FieldIndex { /// Index into an Array ArrayIndex(u32), From 3e6ec6c18fafb9a32f43d68bc0b47b46ae5161b3 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Fri, 7 Nov 2025 18:28:12 +0100 Subject: [PATCH 03/30] Fix miri --- engine/src/types.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/engine/src/types.rs b/engine/src/types.rs index 84853485..4d5e7b00 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -331,7 +331,10 @@ macro_rules! declare_types { impl From for RhsValues { fn from(rhs: RhsValue) -> Self { match rhs { - $(RhsValue::$name(rhs) => RhsValues::$name(vec![rhs.into()]),)* + $(RhsValue::$name(rhs) => { + #[allow(unreachable_code)] + RhsValues::$name(vec![rhs.into()]) + })* } } } @@ -341,7 +344,10 @@ macro_rules! declare_types { pub fn push(&mut self, rhs: RhsValue) -> Result<(), TypeMismatchError> { match self { $(RhsValues::$name(vec) => match rhs { - RhsValue::$name(rhs) => Ok(vec.push(rhs.into())), + RhsValue::$name(rhs) => { + #[allow(unreachable_code)] + Ok(vec.push(rhs.into())) + } _ => Err(TypeMismatchError { expected: self.get_type().into(), actual: rhs.get_type(), From 8bab3eda942b1b0a8b96d75fa961c175987a4c98 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Fri, 7 Nov 2025 17:55:41 +0100 Subject: [PATCH 04/30] Call specialized `serialize_bytes` method instead of serializing a slice This can be leverage by some serialization format like messagepack to use a more optimized encoding. Relying on the slice serialization instead require serializing an entire array of integer instead which can take substantially more space and time. --- engine/src/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/src/types.rs b/engine/src/types.rs index 4d5e7b00..9d96424a 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -880,9 +880,9 @@ impl Serialize for LhsValue<'_> { LhsValue::Ip(ip) => ip.serialize(serializer), LhsValue::Bytes(bytes) => { if let Ok(s) = std::str::from_utf8(bytes) { - s.serialize(serializer) + serializer.serialize_str(s) } else { - bytes.serialize(serializer) + serializer.serialize_bytes(bytes) } } LhsValue::Int(num) => num.serialize(serializer), From afa956869f305be19ef08e2e76939a47540ee414 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Tue, 23 Dec 2025 10:42:14 +0100 Subject: [PATCH 05/30] Rename rhs `Bytes` to `BytesExpr` In the future `RhsValue` will also likely be renamed to `LiteralExpr`. --- engine/src/ast/field_expr.rs | 32 ++--- engine/src/ast/function_expr.rs | 10 +- engine/src/lib.rs | 2 +- engine/src/rhs_types/bytes.rs | 215 +++++++++++++++++-------------- engine/src/rhs_types/mod.rs | 2 +- engine/src/rhs_types/wildcard.rs | 24 ++-- engine/src/types.rs | 4 +- 7 files changed, 152 insertions(+), 137 deletions(-) diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 338b7d6b..986f8207 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -11,7 +11,7 @@ use crate::{ filter::CompiledExpr, lex::{Lex, LexErrorKind, LexResult, LexWith, expect, skip_space, span}, range_set::RangeSet, - rhs_types::{Bytes, ExplicitIpRange, ListName, Regex, Wildcard}, + rhs_types::{BytesExpr, ExplicitIpRange, ListName, Regex, Wildcard}, scheme::{Field, Identifier, List}, searcher::{EmptySearcher, TwoWaySearcher}, strict_partial_ord::StrictPartialOrd, @@ -148,7 +148,7 @@ pub enum ComparisonOpExpr { /// "contains" comparison #[serde(serialize_with = "serialize_contains")] - Contains(Bytes), + Contains(BytesExpr), /// "matches / ~" comparison #[serde(serialize_with = "serialize_matches")] @@ -168,7 +168,7 @@ pub enum ComparisonOpExpr { /// "contains {...}" comparison #[serde(serialize_with = "serialize_contains_one_of")] - ContainsOneOf(Vec), + ContainsOneOf(Vec), /// "in $..." comparison #[serde(serialize_with = "serialize_list")] @@ -201,7 +201,7 @@ fn serialize_is_true(ser: S) -> Result { out.end() } -fn serialize_contains(rhs: &Bytes, ser: S) -> Result { +fn serialize_contains(rhs: &BytesExpr, ser: S) -> Result { serialize_op_rhs("Contains", rhs, ser) } @@ -224,7 +224,7 @@ fn serialize_one_of(rhs: &RhsValues, ser: S) -> Result(rhs: &[Bytes], ser: S) -> Result { +fn serialize_contains_one_of(rhs: &[BytesExpr], ser: S) -> Result { serialize_op_rhs("ContainsOneOf", rhs, ser) } @@ -372,7 +372,7 @@ impl ComparisonExpr { } (Type::Bytes, ComparisonOp::Bytes(op)) => match op { BytesOp::Contains => { - let (bytes, input) = Bytes::lex(input)?; + let (bytes, input) = BytesExpr::lex(input)?; (ComparisonOpExpr::Contains(bytes), input) } BytesOp::Matches => { @@ -472,7 +472,7 @@ impl Expr for ComparisonExpr { ($op:tt, $def:ident) => { match rhs { RhsValue::Bytes(bytes) => { - struct BytesOp(Bytes); + struct BytesOp(BytesExpr); impl Compare for BytesOp { #[inline] @@ -1939,7 +1939,7 @@ mod tests { identifier: IdentifierExpr::Field(field("http.host").to_owned()), indexes: vec![], }), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::from( + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::from( ".org".to_owned() ))), ], @@ -2079,7 +2079,7 @@ mod tests { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), indexes: vec![FieldIndex::MapEach], }), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::from( + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::from( "-cf".to_owned() ))), ], @@ -2148,7 +2148,7 @@ mod tests { identifier: IdentifierExpr::Field(field("http.headers").to_owned()), indexes: vec![FieldIndex::MapEach], }), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::from( + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::from( "-cf".to_owned() ))), ], @@ -2314,7 +2314,7 @@ mod tests { identifier: IdentifierExpr::Field(field("http.cookies").to_owned()), indexes: vec![FieldIndex::MapEach], }), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::from( + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::from( "-cf".to_owned() ))), ], @@ -2782,7 +2782,7 @@ mod tests { }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, - rhs: RhsValue::Bytes(Bytes::new("ab".as_bytes(), BytesFormat::Raw(3))), + rhs: RhsValue::Bytes(BytesExpr::new("ab".as_bytes(), BytesFormat::Raw(3))), }, } ); @@ -2839,7 +2839,7 @@ mod tests { // Wildcard operator let wildcard = Wildcard::new( - Bytes::new(r"foo*\*\\".as_bytes(), BytesFormat::Raw(2)), + BytesExpr::new(r"foo*\*\\".as_bytes(), BytesFormat::Raw(2)), usize::MAX, ) .unwrap(); @@ -2883,7 +2883,7 @@ mod tests { // Strict wildcard operator let wildcard = Wildcard::new( - Bytes::new(r"foo*\*\\".as_bytes(), BytesFormat::Raw(2)), + BytesExpr::new(r"foo*\*\\".as_bytes(), BytesFormat::Raw(2)), usize::MAX, ) .unwrap(); @@ -2938,7 +2938,7 @@ mod tests { identifier: IdentifierExpr::Field(field("http.host").to_owned()), indexes: vec![], }), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::new( + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::new( "cd".as_bytes(), BytesFormat::Raw(1) ))) @@ -2949,7 +2949,7 @@ mod tests { }, op: ComparisonOpExpr::Ordering { op: OrderingOp::Equal, - rhs: RhsValue::Bytes(Bytes::new("abcd".as_bytes(), BytesFormat::Raw(2))) + rhs: RhsValue::Bytes(BytesExpr::new("abcd".as_bytes(), BytesFormat::Raw(2))) } } ); diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index 037d9ae9..72babe64 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -537,7 +537,7 @@ mod tests { FunctionArgKind, FunctionArgKindMismatchError, FunctionArgs, SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, }, - rhs_types::{Bytes, BytesFormat}, + rhs_types::{BytesExpr, BytesFormat}, scheme::{FieldIndex, IndexAccessError, Scheme}, types::{RhsValues, Type, TypeMismatchError}, }; @@ -1265,8 +1265,8 @@ mod tests { identifier: IdentifierExpr::Field(SCHEME.get_field("http.host").unwrap().to_owned()), indexes: vec![], }), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::new("this is a r##raw## string".as_bytes(), BytesFormat::Raw(0)))), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::new("this is a new r##raw## string".as_bytes(), BytesFormat::Raw(0)))) + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::new("this is a r##raw## string".as_bytes(), BytesFormat::Raw(0)))), + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::new("this is a new r##raw## string".as_bytes(), BytesFormat::Raw(0)))) ], context: None, }, @@ -1306,8 +1306,8 @@ mod tests { identifier: IdentifierExpr::Field(SCHEME.get_field("http.host").unwrap().to_owned()), indexes: vec![], }), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::new("this is a r##\"raw\"## string".as_bytes(), BytesFormat::Raw(3)))), - FunctionCallArgExpr::Literal(RhsValue::Bytes(Bytes::new("this is a new r##\"raw\"## string".as_bytes(), BytesFormat::Raw(3)))) + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::new("this is a r##\"raw\"## string".as_bytes(), BytesFormat::Raw(3)))), + FunctionCallArgExpr::Literal(RhsValue::Bytes(BytesExpr::new("this is a new r##\"raw\"## string".as_bytes(), BytesFormat::Raw(3)))) ], context: None, }, diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 27cc0d0e..af261e96 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -112,7 +112,7 @@ pub use self::{ panic_catcher_get_backtrace, panic_catcher_set_fallback_mode, panic_catcher_set_hook, }, rhs_types::{ - Bytes, BytesFormat, ExplicitIpRange, IntRange, IpCidr, IpRange, Regex, RegexError, + BytesExpr, BytesFormat, ExplicitIpRange, IntRange, IpCidr, IpRange, Regex, RegexError, RegexFormat, }, scheme::{ diff --git a/engine/src/rhs_types/bytes.rs b/engine/src/rhs_types/bytes.rs index ec71d590..b3ab6338 100644 --- a/engine/src/rhs_types/bytes.rs +++ b/engine/src/rhs_types/bytes.rs @@ -23,12 +23,12 @@ pub enum BytesFormat { /// Bytes literal represented either by a string, raw string or raw bytes. #[derive(PartialEq, Eq, Clone)] -pub struct Bytes { +pub struct BytesExpr { format: BytesFormat, data: Box<[u8]>, } -impl Bytes { +impl BytesExpr { /// Creates a new bytes literal. #[inline] pub fn new(data: impl Into>, format: BytesFormat) -> Self { @@ -45,7 +45,7 @@ impl Bytes { } } -impl Serialize for Bytes { +impl Serialize for BytesExpr { #[inline] fn serialize(&self, serializer: S) -> Result where @@ -66,48 +66,48 @@ impl Serialize for Bytes { // `Bytes == Bytes` to check enum tags but `Bytes == &[u8]` to ignore them, and // consistency of the latter is all that matters for `Borrow` consumers. #[allow(clippy::derived_hash_with_manual_eq)] -impl Hash for Bytes { +impl Hash for BytesExpr { #[inline] fn hash(&self, h: &mut H) { (self as &[u8]).hash(h); } } -impl From> for Bytes { +impl From> for BytesExpr { #[inline] fn from(src: Vec) -> Self { - Bytes { + Self { format: BytesFormat::Byte, data: src.into_boxed_slice(), } } } -impl From for Bytes { +impl From for BytesExpr { #[inline] fn from(src: String) -> Self { - Bytes { + Self { format: BytesFormat::Quoted, data: src.into_boxed_str().into_boxed_bytes(), } } } -impl From for Box<[u8]> { +impl From for Box<[u8]> { #[inline] - fn from(bytes: Bytes) -> Self { + fn from(bytes: BytesExpr) -> Self { bytes.data } } -impl From for Vec { +impl From for Vec { #[inline] - fn from(bytes: Bytes) -> Self { + fn from(bytes: BytesExpr) -> Self { bytes.data.into_vec() } } -impl Debug for Bytes { +impl Debug for BytesExpr { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt_raw(data: &[u8], f: &mut Formatter<'_>) -> fmt::Result { let mut iter = data.iter(); @@ -130,7 +130,7 @@ impl Debug for Bytes { } } -impl Deref for Bytes { +impl Deref for BytesExpr { type Target = [u8]; #[inline] @@ -139,14 +139,14 @@ impl Deref for Bytes { } } -impl AsRef<[u8]> for Bytes { +impl AsRef<[u8]> for BytesExpr { #[inline] fn as_ref(&self) -> &[u8] { self } } -impl<'a> IntoIterator for &'a Bytes { +impl<'a> IntoIterator for &'a BytesExpr { type Item = &'a u8; type IntoIter = std::slice::Iter<'a, u8>; @@ -236,9 +236,9 @@ pub(crate) fn lex_quoted_string_as_vec(input: &str) -> LexResult<'_, Vec> { } } -fn lex_quoted_string(input: &str) -> LexResult<'_, Bytes> { +fn lex_quoted_string(input: &str) -> LexResult<'_, BytesExpr> { lex_quoted_string_as_vec(input).map(|(vec, rest)| { - let bytes = Bytes { + let bytes = BytesExpr { format: BytesFormat::Quoted, data: vec.into_boxed_slice(), }; @@ -247,7 +247,7 @@ fn lex_quoted_string(input: &str) -> LexResult<'_, Bytes> { }) } -fn lex_byte_string(mut input: &str) -> LexResult<'_, Bytes> { +fn lex_byte_string(mut input: &str) -> LexResult<'_, BytesExpr> { let mut res = Vec::new(); let (b, rest) = hex_byte(input)?; res.push(b); @@ -309,10 +309,10 @@ pub(crate) fn lex_raw_string_as_str(input: &str) -> LexResult<'_, (&str, u8)> { } #[inline] -fn lex_raw_string(input: &str) -> LexResult<'_, Bytes> { +fn lex_raw_string(input: &str) -> LexResult<'_, BytesExpr> { let ((lexed, hash_count), rest) = lex_raw_string_as_str(input)?; Ok(( - Bytes { + BytesExpr { format: BytesFormat::Raw(hash_count), data: Box::from(lexed.as_bytes()), }, @@ -320,7 +320,7 @@ fn lex_raw_string(input: &str) -> LexResult<'_, Bytes> { )) } -pub(crate) fn lex_quoted_or_raw_string(input: &str) -> LexResult<'_, Bytes> { +pub(crate) fn lex_quoted_or_raw_string(input: &str) -> LexResult<'_, BytesExpr> { match input.as_bytes().first() { Some(b'"') => lex_quoted_string(&input[1..]), Some(b'r') => lex_raw_string(&input[1..]), @@ -329,7 +329,7 @@ pub(crate) fn lex_quoted_or_raw_string(input: &str) -> LexResult<'_, Bytes> { } } -impl Lex<'_> for Bytes { +impl Lex<'_> for BytesExpr { #[inline] fn lex(input: &str) -> LexResult<'_, Self> { match input.as_bytes().first() { @@ -349,18 +349,18 @@ mod test { #[test] fn test() { assert_ok!( - Bytes::lex("01:2e:f3-77.12;"), - Bytes::from(vec![0x01, 0x2E, 0xF3, 0x77, 0x12]), + BytesExpr::lex("01:2e:f3-77.12;"), + BytesExpr::from(vec![0x01, 0x2E, 0xF3, 0x77, 0x12]), ";" ); assert_ok!( - Bytes::lex(r#""s\\t\"r\x0A\000t""#), - Bytes::from("s\\t\"r\n\0t".to_owned()) + BytesExpr::lex(r#""s\\t\"r\x0A\000t""#), + BytesExpr::from("s\\t\"r\n\0t".to_owned()) ); assert_err!( - Bytes::lex("01:4x;"), + BytesExpr::lex("01:4x;"), LexErrorKind::ParseInt { err: u8::from_str_radix("4x", 16).unwrap_err(), radix: 16, @@ -369,13 +369,13 @@ mod test { ); assert_err!( - Bytes::lex("01;"), + BytesExpr::lex("01;"), LexErrorKind::ExpectedName("byte separator"), ";" ); assert_err!( - Bytes::lex("01:;"), + BytesExpr::lex("01:;"), LexErrorKind::CountMismatch { name: "character", actual: 1, @@ -384,24 +384,27 @@ mod test { ";" ); - assert_ok!(Bytes::lex("01:2f-34"), Bytes::from(vec![0x01, 0x2F, 0x34])); + assert_ok!( + BytesExpr::lex("01:2f-34"), + BytesExpr::from(vec![0x01, 0x2F, 0x34]) + ); - assert_err!(Bytes::lex("\"1"), LexErrorKind::MissingEndingQuote, "1"); + assert_err!(BytesExpr::lex("\"1"), LexErrorKind::MissingEndingQuote, "1"); assert_err!( - Bytes::lex(r#""\n""#), + BytesExpr::lex(r#""\n""#), LexErrorKind::InvalidCharacterEscape, "n" ); assert_err!( - Bytes::lex(r#""abcd\"#), + BytesExpr::lex(r#""abcd\"#), LexErrorKind::MissingEndingQuote, "abcd\\" ); assert_err!( - Bytes::lex(r#""\01😢""#), + BytesExpr::lex(r#""\01😢""#), LexErrorKind::ParseInt { err: u8::from_str_radix("01😢", 8).unwrap_err(), radix: 8, @@ -410,7 +413,7 @@ mod test { ); assert_err!( - Bytes::lex(r#""\x3😢""#), + BytesExpr::lex(r#""\x3😢""#), LexErrorKind::ParseInt { err: u8::from_str_radix("3😢", 16).unwrap_err(), radix: 16, @@ -419,7 +422,7 @@ mod test { ); assert_err!( - Bytes::lex("12:3😢"), + BytesExpr::lex("12:3😢"), LexErrorKind::ParseInt { err: u8::from_str_radix("3😢", 16).unwrap_err(), radix: 16, @@ -427,33 +430,39 @@ mod test { "3😢" ); - assert_ok!(Bytes::lex(r#""\x7F""#), Bytes::from("\x7F".to_owned())); + assert_ok!( + BytesExpr::lex(r#""\x7F""#), + BytesExpr::from("\x7F".to_owned()) + ); assert_ok!( - Bytes::lex(r#""\x80""#), - Bytes::new(vec![0x80], BytesFormat::Quoted) + BytesExpr::lex(r#""\x80""#), + BytesExpr::new(vec![0x80], BytesFormat::Quoted) ); assert_ok!( - Bytes::lex(r#""\xFF""#), - Bytes::new(vec![0xFF], BytesFormat::Quoted) + BytesExpr::lex(r#""\xFF""#), + BytesExpr::new(vec![0xFF], BytesFormat::Quoted) ); - assert_ok!(Bytes::lex(r#""\177""#), Bytes::from("\x7F".to_owned())); + assert_ok!( + BytesExpr::lex(r#""\177""#), + BytesExpr::from("\x7F".to_owned()) + ); assert_ok!( - Bytes::lex(r#""\200""#), - Bytes::new(vec![0x80], BytesFormat::Quoted) + BytesExpr::lex(r#""\200""#), + BytesExpr::new(vec![0x80], BytesFormat::Quoted) ); assert_ok!( - Bytes::lex(r#""\377""#), - Bytes::new(vec![0xFF], BytesFormat::Quoted) + BytesExpr::lex(r#""\377""#), + BytesExpr::new(vec![0xFF], BytesFormat::Quoted) ); assert_ok!( - Bytes::lex("c2:b4710c6888a5d47befe865c8e6fb19"), - Bytes::from(vec![0xC2, 0xb4]), + BytesExpr::lex("c2:b4710c6888a5d47befe865c8e6fb19"), + BytesExpr::from(vec![0xC2, 0xb4]), "710c6888a5d47befe865c8e6fb19" ); } @@ -462,87 +471,87 @@ mod test { fn test_raw_string() { // Valid empty strings assert_ok!( - Bytes::lex("r\"\""), - Bytes::new("".as_bytes(), BytesFormat::Raw(0)) + BytesExpr::lex("r\"\""), + BytesExpr::new("".as_bytes(), BytesFormat::Raw(0)) ); assert_ok!( - Bytes::lex("r#\"\"#"), - Bytes::new("".as_bytes(), BytesFormat::Raw(1)) + BytesExpr::lex("r#\"\"#"), + BytesExpr::new("".as_bytes(), BytesFormat::Raw(1)) ); assert_ok!( - Bytes::lex("r##\"\"##"), - Bytes::new("".as_bytes(), BytesFormat::Raw(2)) + BytesExpr::lex("r##\"\"##"), + BytesExpr::new("".as_bytes(), BytesFormat::Raw(2)) ); assert_ok!( - Bytes::lex("r###\"\"###"), - Bytes::new("".as_bytes(), BytesFormat::Raw(3)) + BytesExpr::lex("r###\"\"###"), + BytesExpr::new("".as_bytes(), BytesFormat::Raw(3)) ); // Valid raw strings assert_ok!( - Bytes::lex("r\"a\""), - Bytes::new("a".as_bytes(), BytesFormat::Raw(0)) + BytesExpr::lex("r\"a\""), + BytesExpr::new("a".as_bytes(), BytesFormat::Raw(0)) ); assert_ok!( - Bytes::lex("r#\"a\"#"), - Bytes::new("a".as_bytes(), BytesFormat::Raw(1)) + BytesExpr::lex("r#\"a\"#"), + BytesExpr::new("a".as_bytes(), BytesFormat::Raw(1)) ); assert_ok!( - Bytes::lex("r##\"a\"##"), - Bytes::new("a".as_bytes(), BytesFormat::Raw(2)) + BytesExpr::lex("r##\"a\"##"), + BytesExpr::new("a".as_bytes(), BytesFormat::Raw(2)) ); assert_ok!( - Bytes::lex("r###\"a\"###"), - Bytes::new("a".as_bytes(), BytesFormat::Raw(3)) + BytesExpr::lex("r###\"a\"###"), + BytesExpr::new("a".as_bytes(), BytesFormat::Raw(3)) ); // Quotes and hashes can be used inside the raw string assert_ok!( - Bytes::lex("r\"#\""), - Bytes::new("#".as_bytes(), BytesFormat::Raw(0)) + BytesExpr::lex("r\"#\""), + BytesExpr::new("#".as_bytes(), BytesFormat::Raw(0)) ); assert_ok!( - Bytes::lex("r\"a#\""), - Bytes::new("a#".as_bytes(), BytesFormat::Raw(0)) + BytesExpr::lex("r\"a#\""), + BytesExpr::new("a#".as_bytes(), BytesFormat::Raw(0)) ); assert_ok!( - Bytes::lex("r#\"\"a\"\"\"#"), - Bytes::new("\"a\"\"".as_bytes(), BytesFormat::Raw(1)) + BytesExpr::lex("r#\"\"a\"\"\"#"), + BytesExpr::new("\"a\"\"".as_bytes(), BytesFormat::Raw(1)) ); assert_ok!( - Bytes::lex("r##\"\"a\"#b\"##"), - Bytes::new("\"a\"#b".as_bytes(), BytesFormat::Raw(2)) + BytesExpr::lex("r##\"\"a\"#b\"##"), + BytesExpr::new("\"a\"#b".as_bytes(), BytesFormat::Raw(2)) ); assert_ok!( - Bytes::lex("r###\"a###\"##\"\"###"), - Bytes::new("a###\"##\"".as_bytes(), BytesFormat::Raw(3)) + BytesExpr::lex("r###\"a###\"##\"\"###"), + BytesExpr::new("a###\"##\"".as_bytes(), BytesFormat::Raw(3)) ); assert_ok!( - Bytes::lex("r#\"a\"\"\"#"), - Bytes::new("a\"\"".as_bytes(), BytesFormat::Raw(1)) + BytesExpr::lex("r#\"a\"\"\"#"), + BytesExpr::new("a\"\"".as_bytes(), BytesFormat::Raw(1)) ); assert_ok!( - Bytes::lex("r##\"a\"#\"##"), - Bytes::new("a\"#".as_bytes(), BytesFormat::Raw(2)) + BytesExpr::lex("r##\"a\"#\"##"), + BytesExpr::new("a\"#".as_bytes(), BytesFormat::Raw(2)) ); assert_ok!( - Bytes::lex("r###\"a###\"##\"###"), - Bytes::new("a###\"##".as_bytes(), BytesFormat::Raw(3)) + BytesExpr::lex("r###\"a###\"##\"###"), + BytesExpr::new("a###\"##".as_bytes(), BytesFormat::Raw(3)) ); // Expect an error if the number of '#' doesn't match assert_err!( - Bytes::lex("r#\"a\""), + BytesExpr::lex("r#\"a\""), LexErrorKind::MissingEndingQuote, "#\"a\"" ); assert_err!( - Bytes::lex("r##\"a\"#"), + BytesExpr::lex("r##\"a\"#"), LexErrorKind::MissingEndingQuote, "##\"a\"#" ); assert_err!( - Bytes::lex("r###\"a\"##"), + BytesExpr::lex("r###\"a\"##"), LexErrorKind::MissingEndingQuote, "###\"a\"##" ); @@ -550,54 +559,60 @@ mod test { // Expect an error when there are too many hashes being used let hashes = format!("r{}\"abc\"{}", "#".repeat(255), "#".repeat(255)); assert_ok!( - Bytes::lex(hashes.as_str()), - Bytes::new("abc".as_bytes(), BytesFormat::Raw(255)) + BytesExpr::lex(hashes.as_str()), + BytesExpr::new("abc".as_bytes(), BytesFormat::Raw(255)) ); let hashes = format!("r{}\"abc\"{}", "#".repeat(256), "#".repeat(256)); assert_err!( - Bytes::lex(hashes.as_str()), + BytesExpr::lex(hashes.as_str()), LexErrorKind::InvalidRawStringHashCount, &hashes.as_str()[1..] ); // Test regex escapes remain the same assert_ok!( - Bytes::lex(r#"r".\d\D\pA\p{Greek}\PA\P{Greek}[xyz][^xyz][a-z][[:alpha:]][[:^alpha:]][x[^xyz]][a-y&&xyz][0-9&&[^4]][0-9--4][a-g~~b-h][\[\]]""#), - Bytes::new(r#".\d\D\pA\p{Greek}\PA\P{Greek}[xyz][^xyz][a-z][[:alpha:]][[:^alpha:]][x[^xyz]][a-y&&xyz][0-9&&[^4]][0-9--4][a-g~~b-h][\[\]]"#.as_bytes(), BytesFormat::Raw(0)) + BytesExpr::lex(r#"r".\d\D\pA\p{Greek}\PA\P{Greek}[xyz][^xyz][a-z][[:alpha:]][[:^alpha:]][x[^xyz]][a-y&&xyz][0-9&&[^4]][0-9--4][a-g~~b-h][\[\]]""#), + BytesExpr::new(r#".\d\D\pA\p{Greek}\PA\P{Greek}[xyz][^xyz][a-z][[:alpha:]][[:^alpha:]][x[^xyz]][a-y&&xyz][0-9&&[^4]][0-9--4][a-g~~b-h][\[\]]"#.as_bytes(), BytesFormat::Raw(0)) ); assert_ok!( - Bytes::lex(r##"r#"\*\a\f\t\n\r\v\123\x7F\x{10FFFF}\u007F\u{7F}\U0000007F\U{7F}"#"##), - Bytes::new( + BytesExpr::lex( + r##"r#"\*\a\f\t\n\r\v\123\x7F\x{10FFFF}\u007F\u{7F}\U0000007F\U{7F}"#"## + ), + BytesExpr::new( r#"\*\a\f\t\n\r\v\123\x7F\x{10FFFF}\u007F\u{7F}\U0000007F\U{7F}"#.as_bytes(), BytesFormat::Raw(1) ) ); // Invalid character after 'r' or '#' - assert_err!(Bytes::lex("r"), LexErrorKind::ExpectedName("\" or #"), ""); assert_err!( - Bytes::lex("r#ab"), + BytesExpr::lex("r"), + LexErrorKind::ExpectedName("\" or #"), + "" + ); + assert_err!( + BytesExpr::lex("r#ab"), LexErrorKind::ExpectedName("\" or #"), "ab" ); assert_err!( - Bytes::lex("r##ab"), + BytesExpr::lex("r##ab"), LexErrorKind::ExpectedName("\" or #"), "ab" ); // Any characters after a raw string should get returned assert_eq!( - Bytes::lex("r#\"ab\"##"), - Ok((Bytes::new("ab".as_bytes(), BytesFormat::Raw(1)), "#")) + BytesExpr::lex("r#\"ab\"##"), + Ok((BytesExpr::new("ab".as_bytes(), BytesFormat::Raw(1)), "#")) ); assert_eq!( - Bytes::lex("r#\"ab\"#\""), - Ok((Bytes::new("ab".as_bytes(), BytesFormat::Raw(1)), "\"")) + BytesExpr::lex("r#\"ab\"#\""), + Ok((BytesExpr::new("ab".as_bytes(), BytesFormat::Raw(1)), "\"")) ); assert_eq!( - Bytes::lex("r#\"ab\"#a"), - Ok((Bytes::new("ab".as_bytes(), BytesFormat::Raw(1)), "a")) + BytesExpr::lex("r#\"ab\"#a"), + Ok((BytesExpr::new("ab".as_bytes(), BytesFormat::Raw(1)), "a")) ); } } diff --git a/engine/src/rhs_types/mod.rs b/engine/src/rhs_types/mod.rs index 18d805af..ac3801cd 100644 --- a/engine/src/rhs_types/mod.rs +++ b/engine/src/rhs_types/mod.rs @@ -11,7 +11,7 @@ mod wildcard; pub use self::{ array::UninhabitedArray, bool::UninhabitedBool, - bytes::{Bytes, BytesFormat}, + bytes::{BytesExpr, BytesFormat}, int::IntRange, ip::{ExplicitIpRange, IpCidr, IpRange}, list::ListName, diff --git a/engine/src/rhs_types/wildcard.rs b/engine/src/rhs_types/wildcard.rs index 54d56ff6..068e50f6 100644 --- a/engine/src/rhs_types/wildcard.rs +++ b/engine/src/rhs_types/wildcard.rs @@ -1,6 +1,6 @@ use crate::lex::{LexResult, LexWith}; -use crate::rhs_types::bytes::lex_quoted_or_raw_string; -use crate::{Bytes, FilterParser, LexErrorKind}; +use crate::rhs_types::bytes::{BytesExpr, lex_quoted_or_raw_string}; +use crate::{FilterParser, LexErrorKind}; use serde::{Serialize, Serializer}; use std::{ fmt::{self, Debug, Formatter}, @@ -65,12 +65,12 @@ pub struct Wildcard { compiled_wildcard: wildcard::Wildcard<'static>, /// The original pattern. We keep this to allow correct serialization of the wildcard pattern, /// since bytes are encoded differently depending on whether they are a valid UTF-8 sequence. - pattern: Bytes, + pattern: BytesExpr, } impl Wildcard { pub fn new( - pattern: Bytes, + pattern: BytesExpr, wildcard_star_limit: usize, ) -> Result, WildcardError> { let wildcard = wildcard::WildcardBuilder::from_owned(pattern.to_vec()) @@ -92,7 +92,7 @@ impl Wildcard { } /// Returns the pattern. - pub fn pattern(&self) -> &Bytes { + pub fn pattern(&self) -> &BytesExpr { &self.pattern } } @@ -144,12 +144,12 @@ mod test { fn t() { assert_eq!( Wildcard::::new( - Bytes::new("a quoted string".as_bytes(), BytesFormat::Quoted), + BytesExpr::new("a quoted string".as_bytes(), BytesFormat::Quoted), usize::MAX ) .unwrap(), Wildcard::::new( - Bytes::new("a quoted string".as_bytes(), BytesFormat::Quoted), + BytesExpr::new("a quoted string".as_bytes(), BytesFormat::Quoted), usize::MAX ) .unwrap(), @@ -159,12 +159,12 @@ mod test { // visual representation: assert_ne!( Wildcard::::new( - Bytes::new("a quoted string".as_bytes(), BytesFormat::Quoted), + BytesExpr::new("a quoted string".as_bytes(), BytesFormat::Quoted), usize::MAX ) .unwrap(), Wildcard::::new( - Bytes::new("a quoted string".as_bytes(), BytesFormat::Raw(0)), + BytesExpr::new("a quoted string".as_bytes(), BytesFormat::Raw(0)), usize::MAX ) .unwrap(), @@ -183,7 +183,7 @@ mod test { let expr = assert_ok!( Wildcard::::lex_with(r#""a quoted string";"#, &FilterParser::new(&scheme)), Wildcard::::new( - Bytes::new("a quoted string".as_bytes(), BytesFormat::Quoted), + BytesExpr::new("a quoted string".as_bytes(), BytesFormat::Quoted), usize::MAX ) .unwrap(), @@ -217,7 +217,7 @@ mod test { &FilterParser::new(&scheme) ), Wildcard::::new( - Bytes::new( + BytesExpr::new( r#####"a raw\\xaa r#""# string"#####.as_bytes(), BytesFormat::Raw(2), ), @@ -258,7 +258,7 @@ mod test { &FilterParser::new(&scheme) ), Wildcard::::new( - Bytes::new(bytes.into_boxed_slice(), BytesFormat::Quoted), + BytesExpr::new(bytes.into_boxed_slice(), BytesFormat::Quoted), usize::MAX ) .unwrap(), diff --git a/engine/src/types.rs b/engine/src/types.rs index 9d96424a..913d3298 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -1,7 +1,7 @@ use crate::{ lex::{Lex, LexResult, LexWith, expect, skip_space}, lhs_types::{Array, ArrayIterator, Map, MapIter, MapValuesIntoIter}, - rhs_types::{Bytes, IntRange, IpRange, UninhabitedArray, UninhabitedBool, UninhabitedMap}, + rhs_types::{BytesExpr, IntRange, IpRange, UninhabitedArray, UninhabitedBool, UninhabitedMap}, scheme::{FieldIndex, IndexAccessError}, strict_partial_ord::StrictPartialOrd, }; @@ -1148,7 +1148,7 @@ declare_types!( /// /// These are completely interchangeable in runtime and differ only in /// syntax representation, so we represent them as a single type. - Bytes(#[serde(borrow)] Cow<'a, [u8]> | Bytes | Bytes), + Bytes(#[serde(borrow)] Cow<'a, [u8]> | BytesExpr | BytesExpr), /// An Array of [`Type`]. Array[CompoundType](#[serde(skip_deserializing)] Array<'a> | UninhabitedArray | UninhabitedArray), From 15012094c82c356fd2036ecf19c5607b9bc9a4db Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Wed, 24 Dec 2025 13:45:51 +0100 Subject: [PATCH 06/30] Introduce custom `Bytes` type Instead of relying on `Cow<'_, [u8]>`. It makes the code easier to read but also allows us to implement the various traits we need the way we want them to. And it also makes experimenting with different represention more easier. --- engine/benches/bench.rs | 8 +- engine/src/ast/function_expr.rs | 7 +- engine/src/functions/concat.rs | 31 +-- engine/src/lhs_types/bytes.rs | 357 ++++++++++++++++++++++++++++++++ engine/src/lhs_types/map.rs | 14 +- engine/src/lhs_types/mod.rs | 2 + engine/src/lib.rs | 2 +- engine/src/types.rs | 67 +++--- 8 files changed, 416 insertions(+), 72 deletions(-) create mode 100644 engine/src/lhs_types/bytes.rs diff --git a/engine/benches/bench.rs b/engine/benches/bench.rs index 2763df9d..38a10e5b 100644 --- a/engine/benches/bench.rs +++ b/engine/benches/bench.rs @@ -6,9 +6,9 @@ use std::alloc::System; static A: System = System; use criterion::{Bencher, Criterion, criterion_group, criterion_main}; -use std::{borrow::Cow, clone::Clone, fmt::Debug, net::IpAddr}; +use std::{clone::Clone, fmt::Debug, net::IpAddr}; use wirefilter::{ - ExecutionContext, FilterAst, FunctionArgs, GetType, LhsValue, SchemeBuilder, + Bytes, ExecutionContext, FilterAst, FunctionArgs, GetType, LhsValue, SchemeBuilder, SimpleFunctionArgKind, SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionParam, Type, }; @@ -17,7 +17,7 @@ fn lowercase<'a>(args: FunctionArgs<'_, 'a>) -> Option> { match input { LhsValue::Bytes(mut bytes) => { let make_lowercase = match bytes { - Cow::Borrowed(bytes) => bytes.iter().any(u8::is_ascii_uppercase), + Bytes::Borrowed(bytes) => bytes.iter().any(u8::is_ascii_uppercase), _ => true, }; if make_lowercase { @@ -34,7 +34,7 @@ fn uppercase<'a>(args: FunctionArgs<'_, 'a>) -> Option> { match input { LhsValue::Bytes(mut bytes) => { let make_uppercase = match bytes { - Cow::Borrowed(bytes) => bytes.iter().any(u8::is_ascii_lowercase), + Bytes::Borrowed(bytes) => bytes.iter().any(u8::is_ascii_lowercase), _ => true, }; if make_uppercase { diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index 72babe64..8640b78b 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -562,13 +562,10 @@ mod tests { } fn lower_function<'a>(args: FunctionArgs<'_, 'a>) -> Option> { - use std::borrow::Cow; - match args.next()? { Ok(LhsValue::Bytes(mut b)) => { - let mut text: Vec = b.to_mut().to_vec(); - text.make_ascii_lowercase(); - Some(LhsValue::Bytes(Cow::Owned(text))) + b.to_mut().make_ascii_lowercase(); + Some(LhsValue::Bytes(b)) } Err(Type::Bytes) => None, _ => unreachable!(), diff --git a/engine/src/functions/concat.rs b/engine/src/functions/concat.rs index c9d83473..1d493d93 100644 --- a/engine/src/functions/concat.rs +++ b/engine/src/functions/concat.rs @@ -1,8 +1,8 @@ use crate::{ - Array, ExpectedType, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, + Array, Bytes, ExpectedType, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, FunctionParamError, GetType, LhsValue, ParserSettings, Type, }; -use std::{borrow::Cow, iter::once}; +use std::iter::once; /// A function which, given one or more arrays or byte-strings, returns the /// concatenation of each of them. @@ -43,15 +43,15 @@ fn concat_array<'a>(accumulator: Array<'a>, args: FunctionArgs<'_, 'a>) -> Array Array::try_from_vec(val_type, vec).unwrap() } -fn concat_bytes<'a>(mut accumulator: Cow<'a, [u8]>, args: FunctionArgs<'_, 'a>) -> Cow<'a, [u8]> { +fn concat_bytes<'a>(mut accumulator: Vec, args: FunctionArgs<'_, 'a>) -> Bytes<'a> { for arg in args { match arg { - Ok(LhsValue::Bytes(value)) => accumulator.to_mut().extend(value.iter()), + Ok(LhsValue::Bytes(value)) => accumulator.extend_from_slice(&value), Err(Type::Bytes) => (), _ => (), } } - accumulator + accumulator.into() } pub(crate) const EXPECTED_TYPES: [ExpectedType; 2] = @@ -103,7 +103,10 @@ impl FunctionDefinition for ConcatFunction { return Some(LhsValue::Array(concat_array(array, args))); } Ok(LhsValue::Bytes(bytes)) => { - return Some(LhsValue::Bytes(concat_bytes(bytes, args))); + return Some(LhsValue::Bytes(concat_bytes( + bytes.into_owned().into(), + args, + ))); } Err(_) => (), _ => unreachable!(), @@ -124,12 +127,12 @@ mod tests { #[test] fn test_concat_bytes() { let mut args = vec![ - Ok(LhsValue::Bytes(Cow::Borrowed(b"hello"))), - Ok(LhsValue::Bytes(Cow::Borrowed(b"world"))), + Ok(LhsValue::Bytes(Bytes::Borrowed(b"hello"))), + Ok(LhsValue::Bytes(Bytes::Borrowed(b"world"))), ] .into_iter(); assert_eq!( - Some(LhsValue::Bytes(Cow::Borrowed(b"helloworld"))), + Some(LhsValue::Bytes(Bytes::Borrowed(b"helloworld"))), CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) ); } @@ -137,14 +140,14 @@ mod tests { #[test] fn test_concat_many_bytes() { let mut args = vec![ - Ok(LhsValue::Bytes(Cow::Borrowed(b"hello"))), - Ok(LhsValue::Bytes(Cow::Borrowed(b"world"))), - Ok(LhsValue::Bytes(Cow::Borrowed(b"hello2"))), - Ok(LhsValue::Bytes(Cow::Borrowed(b"world2"))), + Ok(LhsValue::Bytes(Bytes::Borrowed(b"hello"))), + Ok(LhsValue::Bytes(Bytes::Borrowed(b"world"))), + Ok(LhsValue::Bytes(Bytes::Borrowed(b"hello2"))), + Ok(LhsValue::Bytes(Bytes::Borrowed(b"world2"))), ] .into_iter(); assert_eq!( - Some(LhsValue::Bytes(Cow::Borrowed(b"helloworldhello2world2"))), + Some(LhsValue::Bytes(Bytes::Borrowed(b"helloworldhello2world2"))), CONCAT_FN.compile(&mut std::iter::empty(), None)(&mut args) ); } diff --git a/engine/src/lhs_types/bytes.rs b/engine/src/lhs_types/bytes.rs new file mode 100644 index 00000000..1074d64f --- /dev/null +++ b/engine/src/lhs_types/bytes.rs @@ -0,0 +1,357 @@ +use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::borrow::{Borrow, Cow}; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; + +/// A byte string. +#[derive(Debug, Clone)] +pub enum Bytes<'a> { + /// Borrowed byte string. + Borrowed(&'a [u8]), + /// Owned byte string. + Owned(Box<[u8]>), +} + +impl<'a> Bytes<'a> { + /// Clones self into a fully owned byte string. + #[inline] + pub fn to_owned(&self) -> Bytes<'static> { + match self { + Self::Borrowed(b) => Bytes::Owned(Box::from(*b)), + Self::Owned(b) => Bytes::Owned(b.clone()), + } + } + + /// Converts self into a fully owned byte string. + #[inline] + pub fn into_owned(self) -> Box<[u8]> { + match self { + Self::Borrowed(b) => Box::from(b), + Self::Owned(b) => b, + } + } + + /// Converts self into an owned byte string if necessary + /// and returns a mutable reference to the bytes. + #[inline] + pub fn to_mut(&mut self) -> &mut [u8] { + if let Self::Borrowed(b) = self { + *self = Self::Owned(Box::from(*b)); + } + match self { + Self::Owned(b) => b, + Self::Borrowed(_) => { + cfg_if::cfg_if! { + if #[cfg(debug_assertions)] { + unreachable!() + } else { + std::hint::unreachable_unchecked() + } + } + } + } + } + + /// Shortens the byte string, keeping only the first `len` elements. + #[inline] + pub fn truncate(&mut self, len: usize) { + match self { + Self::Borrowed(slice) => { + *slice = &slice[..len]; + } + Self::Owned(data) => { + let mut vec = Vec::from(std::mem::take(data)); + vec.truncate(len); + *data = Box::from(vec); + } + } + } +} + +impl Deref for Bytes<'_> { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &Self::Target { + match self { + Self::Borrowed(b) => b, + Self::Owned(b) => b, + } + } +} + +impl AsRef<[u8]> for Bytes<'_> { + #[inline] + fn as_ref(&self) -> &[u8] { + match self { + Self::Borrowed(b) => b, + Self::Owned(b) => b, + } + } +} + +impl Borrow<[u8]> for Bytes<'_> { + #[inline] + fn borrow(&self) -> &[u8] { + match self { + Self::Borrowed(b) => b, + Self::Owned(b) => b, + } + } +} + +impl<'a> From<&'a [u8]> for Bytes<'a> { + #[inline] + fn from(value: &'a [u8]) -> Self { + Bytes::Borrowed(value) + } +} + +impl<'a, const N: usize> From<&'a [u8; N]> for Bytes<'a> { + #[inline] + fn from(value: &'a [u8; N]) -> Self { + Bytes::Borrowed(value) + } +} + +impl From> for Bytes<'static> { + #[inline] + fn from(value: Box<[u8]>) -> Self { + Bytes::Owned(value) + } +} + +impl From> for Bytes<'static> { + #[inline] + fn from(value: Vec) -> Self { + Bytes::Owned(value.into_boxed_slice()) + } +} + +impl<'a> From> for Bytes<'a> { + #[inline] + fn from(value: Cow<'a, [u8]>) -> Self { + match value { + Cow::Borrowed(b) => Self::Borrowed(b), + Cow::Owned(b) => Self::Owned(b.into_boxed_slice()), + } + } +} + +impl<'a> From<&'a str> for Bytes<'a> { + #[inline] + fn from(value: &'a str) -> Self { + Bytes::Borrowed(value.as_bytes()) + } +} + +impl From> for Bytes<'static> { + #[inline] + fn from(value: Box) -> Self { + Bytes::Owned(value.into_boxed_bytes()) + } +} + +impl From for Bytes<'static> { + #[inline] + fn from(value: String) -> Self { + // Call into_boxed_str in order to reduce memory usage + Bytes::Owned(value.into_boxed_str().into_boxed_bytes()) + } +} + +impl<'a> From> for Bytes<'a> { + #[inline] + fn from(value: Cow<'a, str>) -> Self { + match value { + Cow::Borrowed(b) => Self::Borrowed(b.as_bytes()), + Cow::Owned(b) => Self::Owned(b.into_boxed_str().into_boxed_bytes()), + } + } +} + +impl PartialEq for Bytes<'_> { + #[inline] + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} + +impl PartialEq<[u8]> for Bytes<'_> { + #[inline] + fn eq(&self, other: &[u8]) -> bool { + &**self == other + } +} + +impl PartialEq<&[u8]> for Bytes<'_> { + #[inline] + fn eq(&self, other: &&[u8]) -> bool { + &**self == *other + } +} + +impl PartialEq<[u8; N]> for Bytes<'_> { + #[inline] + fn eq(&self, other: &[u8; N]) -> bool { + **self == *other + } +} + +impl PartialEq<&[u8; N]> for Bytes<'_> { + #[inline] + fn eq(&self, other: &&[u8; N]) -> bool { + &**self == *other + } +} + +impl PartialEq> for Bytes<'_> { + #[inline] + fn eq(&self, other: &Vec) -> bool { + &**self == other + } +} + +impl PartialEq for Bytes<'_> { + #[inline] + fn eq(&self, other: &str) -> bool { + &**self == other.as_bytes() + } +} + +impl PartialEq<&str> for Bytes<'_> { + #[inline] + fn eq(&self, other: &&str) -> bool { + &**self == other.as_bytes() + } +} + +impl PartialEq for Bytes<'_> { + #[inline] + fn eq(&self, other: &String) -> bool { + &**self == other.as_bytes() + } +} + +impl Eq for Bytes<'_> {} + +impl Hash for Bytes<'_> { + #[inline] + fn hash(&self, h: &mut H) { + self.deref().hash(h); + } +} + +impl Serialize for Bytes<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + if let Ok(s) = std::str::from_utf8(self) { + serializer.serialize_str(s) + } else { + serializer.serialize_bytes(self) + } + } +} + +struct BytesVisitor; + +impl<'de> Visitor<'de> for BytesVisitor { + type Value = Bytes<'de>; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a byte string") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + Ok(Bytes::from(v.to_vec())) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where + E: serde::de::Error, + { + Ok(Bytes::from(v)) + } + + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result + where + E: serde::de::Error, + { + Ok(Bytes::Borrowed(v)) + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(Bytes::from(v.as_bytes().to_vec())) + } + + fn visit_string(self, v: String) -> Result + where + E: serde::de::Error, + { + Ok(Bytes::from(v)) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: serde::de::Error, + { + Ok(Bytes::Borrowed(v.as_bytes())) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut vec = Vec::::with_capacity(seq.size_hint().unwrap_or_default()); + while let Some(val) = seq.next_element()? { + vec.push(val); + } + + Ok(Bytes::from(vec)) + } +} + +impl<'de> Deserialize<'de> for Bytes<'de> { + fn deserialize(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_bytes(BytesVisitor) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bytes_deserialize() { + let bytes = serde_json::from_str::>("\"a JSON string with unicode ❤\"").unwrap(); + assert_eq!( + bytes, + Bytes::from(&b"a JSON string with unicode \xE2\x9D\xA4"[..]) + ); + + let bytes = + serde_json::from_str::>("\"a JSON string with escaped-unicode \\u2764\"") + .unwrap(); + assert_eq!( + bytes, + Bytes::from(&b"a JSON string with escaped-unicode \xE2\x9D\xA4"[..]) + ); + + let bytes = + serde_json::from_str::>("[97, 32, 74, 83, 79, 78, 32, 115, 116, 114, 105, 110, 103, 32, 102, 114, 111, 109, 32, 105, 110, 116, 101, 103, 101, 114, 32, 97, 114, 114, 97, 121]") + .unwrap(); + assert_eq!(bytes, Bytes::from(&b"a JSON string from integer array"[..])); + } +} diff --git a/engine/src/lhs_types/map.rs b/engine/src/lhs_types/map.rs index 8850b229..b65e7ab3 100644 --- a/engine/src/lhs_types/map.rs +++ b/engine/src/lhs_types/map.rs @@ -1,7 +1,7 @@ use crate::{ TypeMismatchError, - lhs_types::AsRefIterator, - types::{BytesOrString, CompoundType, GetType, IntoValue, LhsValue, LhsValueSeed, Type}, + lhs_types::{AsRefIterator, Bytes}, + types::{CompoundType, GetType, IntoValue, LhsValue, LhsValueSeed, Type}, }; use serde::{ Serialize, Serializer, @@ -332,7 +332,7 @@ impl Serialize for Map<'_> { struct MapEntrySeed<'a>(&'a Type); impl<'de> DeserializeSeed<'de> for MapEntrySeed<'_> { - type Value = (Cow<'de, [u8]>, LhsValue<'de>); + type Value = (Bytes<'de>, LhsValue<'de>); fn deserialize(self, deserializer: D) -> Result where @@ -341,7 +341,7 @@ impl<'de> DeserializeSeed<'de> for MapEntrySeed<'_> { struct MapEntryVisitor<'a>(&'a Type); impl<'de> Visitor<'de> for MapEntryVisitor<'_> { - type Value = (Cow<'de, [u8]>, LhsValue<'de>); + type Value = (Bytes<'de>, LhsValue<'de>); fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "a [key, lhs value] pair") @@ -352,12 +352,12 @@ impl<'de> DeserializeSeed<'de> for MapEntrySeed<'_> { V: SeqAccess<'de>, { let key = seq - .next_element::>()? + .next_element::>()? .ok_or_else(|| de::Error::invalid_length(0, &self))?; let value = seq .next_element_seed(LhsValueSeed(self.0))? .ok_or_else(|| de::Error::invalid_length(1, &self))?; - Ok((key.into_bytes(), value)) + Ok((key, value)) } } @@ -419,7 +419,7 @@ impl<'de> DeserializeSeed<'de> for &mut Map<'de> { value_type ))); } - self.0.data.insert(key.into_owned().into(), value); + self.0.data.insert(key.into_owned(), value); } Ok(()) } diff --git a/engine/src/lhs_types/mod.rs b/engine/src/lhs_types/mod.rs index 93172b41..fe773bdf 100644 --- a/engine/src/lhs_types/mod.rs +++ b/engine/src/lhs_types/mod.rs @@ -1,10 +1,12 @@ mod array; +mod bytes; mod map; use crate::types::LhsValue; pub use self::{ array::{Array, ArrayIterator, TypedArray}, + bytes::Bytes, map::{Map, MapIter, MapValuesIntoIter, TypedMap}, }; diff --git a/engine/src/lib.rs b/engine/src/lib.rs index af261e96..839e6c29 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -103,7 +103,7 @@ pub use self::{ SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, }, lex::LexErrorKind, - lhs_types::{Array, Map, MapIter, TypedArray, TypedMap}, + lhs_types::{Array, Bytes, Map, MapIter, TypedArray, TypedMap}, list_matcher::{ AlwaysList, AlwaysListMatcher, ListDefinition, ListMatcher, NeverList, NeverListMatcher, }, diff --git a/engine/src/types.rs b/engine/src/types.rs index 913d3298..9ba58521 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -1,6 +1,6 @@ use crate::{ lex::{Lex, LexResult, LexWith, expect, skip_space}, - lhs_types::{Array, ArrayIterator, Map, MapIter, MapValuesIntoIter}, + lhs_types::{Array, ArrayIterator, Bytes, Map, MapIter, MapValuesIntoIter}, rhs_types::{BytesExpr, IntRange, IpRange, UninhabitedArray, UninhabitedBool, UninhabitedMap}, scheme::{FieldIndex, IndexAccessError}, strict_partial_ord::StrictPartialOrd, @@ -470,29 +470,9 @@ impl PartialEq for LhsValue<'_> { } } -#[derive(Deserialize)] -#[serde(untagged)] -pub enum BytesOrString<'a> { - BorrowedBytes(#[serde(borrow)] &'a [u8]), - OwnedBytes(Vec), - BorrowedString(#[serde(borrow)] &'a str), - OwnedString(String), -} - -impl<'a> BytesOrString<'a> { - pub fn into_bytes(self) -> Cow<'a, [u8]> { - match self { - BytesOrString::BorrowedBytes(slice) => (*slice).into(), - BytesOrString::OwnedBytes(vec) => vec.into(), - BytesOrString::BorrowedString(str) => str.as_bytes().into(), - BytesOrString::OwnedString(str) => str.into_bytes().into(), - } - } -} - mod private { use super::IntoValue; - use crate::{TypedArray, TypedMap}; + use crate::{Bytes, TypedArray, TypedMap}; use std::borrow::Cow; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; @@ -516,6 +496,7 @@ mod private { impl SealedIntoValue for Box {} impl SealedIntoValue for String {} impl SealedIntoValue for Cow<'_, str> {} + impl SealedIntoValue for Bytes<'_> {} impl SealedIntoValue for IpAddr {} impl SealedIntoValue for Ipv4Addr {} @@ -603,7 +584,7 @@ impl<'a> IntoValue<'a> for &'a [u8] { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Cow::Borrowed(self)) + LhsValue::Bytes(Bytes::from(self)) } } @@ -612,7 +593,7 @@ impl<'a> IntoValue<'a> for Box<[u8]> { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Cow::Owned(Vec::from(self))) + LhsValue::Bytes(Bytes::from(self)) } } @@ -621,7 +602,7 @@ impl<'a> IntoValue<'a> for Vec { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Cow::Owned(self)) + LhsValue::Bytes(Bytes::from(self)) } } @@ -630,7 +611,7 @@ impl<'a> IntoValue<'a> for Cow<'a, [u8]> { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(self) + LhsValue::Bytes(Bytes::from(self)) } } @@ -639,7 +620,7 @@ impl<'a> IntoValue<'a> for &'a str { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Cow::Borrowed(self.as_bytes())) + LhsValue::Bytes(Bytes::from(self)) } } @@ -648,7 +629,7 @@ impl<'a> IntoValue<'a> for Box { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Cow::Owned(Vec::from(Box::<[u8]>::from(self)))) + LhsValue::Bytes(Bytes::from(self)) } } @@ -657,7 +638,7 @@ impl<'a> IntoValue<'a> for String { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Cow::Owned(self.into_bytes())) + LhsValue::Bytes(Bytes::from(self)) } } @@ -666,10 +647,16 @@ impl<'a> IntoValue<'a> for Cow<'a, str> { #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(match self { - Cow::Borrowed(slice) => Cow::Borrowed(slice.as_bytes()), - Cow::Owned(vec) => Cow::Owned(vec.into()), - }) + LhsValue::Bytes(Bytes::from(self)) + } +} + +impl<'a> IntoValue<'a> for Bytes<'a> { + const TYPE: Type = Type::Bytes; + + #[inline] + fn into_value(self) -> LhsValue<'a> { + LhsValue::Bytes(self) } } @@ -745,7 +732,7 @@ impl<'a> From<&'a RhsValue> for LhsValue<'a> { fn from(rhs_value: &'a RhsValue) -> Self { match rhs_value { RhsValue::Ip(ip) => LhsValue::Ip(*ip), - RhsValue::Bytes(bytes) => LhsValue::Bytes(Cow::Borrowed(bytes)), + RhsValue::Bytes(bytes) => LhsValue::Bytes(Bytes::Borrowed(bytes)), RhsValue::Int(integer) => LhsValue::Int(*integer), RhsValue::Bool(b) => match *b {}, RhsValue::Array(a) => match *a {}, @@ -758,7 +745,7 @@ impl From for LhsValue<'_> { fn from(rhs_value: RhsValue) -> Self { match rhs_value { RhsValue::Ip(ip) => LhsValue::Ip(ip), - RhsValue::Bytes(bytes) => LhsValue::Bytes(Cow::Owned(bytes.into())), + RhsValue::Bytes(bytes) => LhsValue::Bytes(Bytes::Owned(bytes.into())), RhsValue::Int(integer) => LhsValue::Int(integer), RhsValue::Bool(b) => match b {}, RhsValue::Array(a) => match a {}, @@ -773,7 +760,7 @@ impl<'a> LhsValue<'a> { pub fn as_ref(&'a self) -> Self { match self { LhsValue::Ip(ip) => LhsValue::Ip(*ip), - LhsValue::Bytes(bytes) => LhsValue::Bytes(Cow::Borrowed(bytes)), + LhsValue::Bytes(bytes) => LhsValue::Bytes(Bytes::Borrowed(bytes)), LhsValue::Int(integer) => LhsValue::Int(*integer), LhsValue::Bool(b) => LhsValue::Bool(*b), LhsValue::Array(a) => LhsValue::Array(a.as_ref()), @@ -785,7 +772,7 @@ impl<'a> LhsValue<'a> { pub fn into_owned(self) -> LhsValue<'static> { match self { LhsValue::Ip(ip) => LhsValue::Ip(ip), - LhsValue::Bytes(bytes) => LhsValue::Bytes(Cow::Owned(bytes.into_owned())), + LhsValue::Bytes(bytes) => LhsValue::Bytes(Bytes::Owned(bytes.into_owned())), LhsValue::Int(i) => LhsValue::Int(i), LhsValue::Bool(b) => LhsValue::Bool(b), LhsValue::Array(arr) => LhsValue::Array(arr.into_owned()), @@ -906,9 +893,7 @@ impl<'de> DeserializeSeed<'de> for LhsValueSeed<'_> { Type::Ip => Ok(LhsValue::Ip(std::net::IpAddr::deserialize(deserializer)?)), Type::Int => Ok(LhsValue::Int(i64::deserialize(deserializer)?)), Type::Bool => Ok(LhsValue::Bool(bool::deserialize(deserializer)?)), - Type::Bytes => Ok(LhsValue::Bytes( - BytesOrString::deserialize(deserializer)?.into_bytes(), - )), + Type::Bytes => Ok(LhsValue::Bytes(Bytes::deserialize(deserializer)?)), Type::Array(ty) => Ok(LhsValue::Array({ let mut arr = Array::new(*ty); arr.deserialize(deserializer)?; @@ -1148,7 +1133,7 @@ declare_types!( /// /// These are completely interchangeable in runtime and differ only in /// syntax representation, so we represent them as a single type. - Bytes(#[serde(borrow)] Cow<'a, [u8]> | BytesExpr | BytesExpr), + Bytes(#[serde(borrow)] Bytes<'a> | BytesExpr | BytesExpr), /// An Array of [`Type`]. Array[CompoundType](#[serde(skip_deserializing)] Array<'a> | UninhabitedArray | UninhabitedArray), From 013d4dd2f36e842b9e1a091fcdbde8f53a2a7e34 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Wed, 24 Dec 2025 16:35:56 +0100 Subject: [PATCH 07/30] Avoid unsafe code in `Bytes::to_mut` --- engine/src/lhs_types/bytes.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/engine/src/lhs_types/bytes.rs b/engine/src/lhs_types/bytes.rs index 1074d64f..863203f0 100644 --- a/engine/src/lhs_types/bytes.rs +++ b/engine/src/lhs_types/bytes.rs @@ -41,15 +41,7 @@ impl<'a> Bytes<'a> { } match self { Self::Owned(b) => b, - Self::Borrowed(_) => { - cfg_if::cfg_if! { - if #[cfg(debug_assertions)] { - unreachable!() - } else { - std::hint::unreachable_unchecked() - } - } - } + Self::Borrowed(_) => unreachable!(), } } From 39bfcbf9790bf083a97511fd44fd5ecaca640654 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Tue, 6 Jan 2026 15:10:47 +0100 Subject: [PATCH 08/30] Update wildcard crate to version 0.3.0 This also updates thiserror to dedup versions. --- Cargo.lock | 12 ++++++------ Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92317d14..54ae238f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -889,18 +889,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.69" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.69" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -1054,9 +1054,9 @@ dependencies = [ [[package]] name = "wildcard" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36241ad0795516b55e3b60e55c7f979d4f324e4aaea4c70d56b548b9164ee4d2" +checksum = "f9b0540e91e49de3817c314da0dd3bc518093ceacc6ea5327cb0e1eb073e5189" dependencies = [ "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index bbfd3a00..931b3e8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,8 +32,8 @@ regex-automata = { version = "0.4.9" } serde = { version = "1.0.113", features = [ "derive" ] } serde_json = "1.0.56" sliceslice = "0.4.3" -thiserror = "1.0" -wildcard = "0.2.0" +thiserror = "2.0" +wildcard = "0.3.0" wirefilter = { path = "engine", package = "wirefilter-engine" } [profile.release] From d9cea51ecb5fc10bbe812e9b600fa288b196cde9 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Tue, 6 Jan 2026 12:42:59 +0100 Subject: [PATCH 09/30] Support list (de)serialization with any serde compatible format --- Cargo.lock | 36 ++++++- Cargo.toml | 1 + engine/Cargo.toml | 3 +- engine/src/ast/field_expr.rs | 21 ++-- engine/src/execution_context.rs | 184 +++++++++++++++++++++++++++----- engine/src/list_matcher.rs | 49 ++++----- ffi/tests/ctests/src/tests.c | 6 +- 7 files changed, 225 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54ae238f..2d9ba11a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,6 +320,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + [[package]] name = "errno" version = "0.3.10" @@ -789,10 +800,11 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -807,11 +819,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -951,6 +972,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + [[package]] name = "unicode-ident" version = "1.0.14" @@ -1170,6 +1197,7 @@ dependencies = [ "cidr", "criterion", "dyn-clone", + "erased-serde", "fnv", "getrandom", "indoc", diff --git a/Cargo.toml b/Cargo.toml index 931b3e8f..5577450f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ cfg-if = "1" cidr = { version = "0.2", features = ["serde"] } criterion = "0.5" dyn-clone = "1.0.20" +erased-serde = "0.4.9" fnv = "1.0.6" getrandom = { version = "0.3" } indoc = "2" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 01ea7aed..83a32aae 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -24,12 +24,12 @@ backtrace.workspace = true cfg-if.workspace = true cidr.workspace = true dyn-clone.workspace = true +erased-serde.workspace = true fnv.workspace = true memmem.workspace = true rand.workspace = true regex-automata = { workspace = true, optional = true } serde.workspace = true -serde_json.workspace = true sliceslice.workspace = true thiserror.workspace = true wildcard.workspace = true @@ -37,6 +37,7 @@ wildcard.workspace = true [dev-dependencies] criterion.workspace = true indoc.workspace = true +serde_json.workspace = true [features] default = [ "regex" ] diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 986f8207..99527081 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -818,6 +818,7 @@ mod tests { types::ExpectedType, }; use cidr::IpCidr; + use serde::Deserialize; use std::sync::LazyLock; use std::{convert::TryFrom, iter::once, net::IpAddr}; @@ -950,12 +951,13 @@ mod tests { pub struct NumMListDefinition {} impl ListDefinition for NumMListDefinition { - fn matcher_from_json_value( + fn deserialize_matcher<'de>( &self, _: Type, - _: serde_json::Value, - ) -> Result, serde_json::Error> { - Ok(Box::new(NumMatcher {})) + deserializer: &mut dyn erased_serde::Deserializer<'de>, + ) -> Result, erased_serde::Error> { + let matcher = erased_serde::deserialize::(deserializer)?; + Ok(Box::new(matcher)) } fn new_matcher(&self) -> Box { @@ -2467,7 +2469,7 @@ mod tests { ); } - #[derive(Debug, PartialEq, Eq, Serialize, Clone)] + #[derive(Debug, PartialEq, Eq, Serialize, Clone, Deserialize)] pub struct NumMatcher {} impl ListMatcher for NumMatcher { @@ -2485,10 +2487,6 @@ mod tests { } } - fn to_json_value(&self) -> serde_json::Value { - serde_json::Value::Null - } - fn clear(&mut self) {} } @@ -2565,7 +2563,10 @@ mod tests { assert_eq!(expr.execute_one(ctx), true); let json = serde_json::to_string(ctx).unwrap(); - assert_eq!(json, "{\"tcp.port\":1001,\"$lists\":[]}"); + assert_eq!( + json, + "{\"tcp.port\":1001,\"$lists\":[{\"type\":\"Int\",\"data\":{}}]}" + ); } #[test] diff --git a/engine/src/execution_context.rs b/engine/src/execution_context.rs index 5c303a6b..26b4c86d 100644 --- a/engine/src/execution_context.rs +++ b/engine/src/execution_context.rs @@ -3,9 +3,9 @@ use crate::{ scheme::{Field, List, Scheme, SchemeMismatchError}, types::{GetType, LhsValue, LhsValueSeed, Type, TypeMismatchError}, }; -use serde::de::{self, DeserializeSeed, Deserializer, MapAccess, Visitor}; +use serde::Serialize; +use serde::de::{self, DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor}; use serde::ser::{SerializeMap, SerializeSeq, Serializer}; -use serde::{Deserialize, Serialize}; use std::borrow::Cow; use std::fmt; use std::fmt::Debug; @@ -292,11 +292,142 @@ impl Drop for ExecutionContextGuard<'_, '_, U, T> { } } -#[derive(Serialize, Deserialize)] -struct ListData { - #[serde(rename = "type")] - ty: Type, - data: serde_json::Value, +struct ListMatcherData<'a>(ListRef<'a>); + +impl<'de> DeserializeSeed<'de> for ListMatcherData<'_> { + type Value = Box; + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use serde::de::Error; + + let mut erased = >::erase(deserializer); + self.0 + .definition() + .deserialize_matcher(self.0.get_type(), &mut erased) + .map_err(D::Error::custom) + } +} + +struct ListMatcherEntry<'a>(&'a Scheme, &'a mut [Box]); + +impl<'de> DeserializeSeed<'de> for ListMatcherEntry<'_> { + type Value = (); + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ListMatcherEntryVisitor<'a>(&'a Scheme, &'a mut [Box]); + + impl<'de> Visitor<'de> for ListMatcherEntryVisitor<'_> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "list matcher data") + } + + fn visit_map(self, mut access: M) -> Result<(), M::Error> + where + M: MapAccess<'de>, + { + use serde::de::Error; + + let Some(key) = access.next_key::>()? else { + return Err(M::Error::missing_field("type")); + }; + + if key != "type" { + return Err(M::Error::unknown_field(&key, &["type", "data"])); + } + + let ty = access.next_value::()?; + + let Some(list) = self.0.get_list(&ty) else { + return Err(M::Error::custom(format!("no list defined for type {ty}"))); + }; + + let Some(key) = access.next_key::>()? else { + return Err(M::Error::missing_field("data")); + }; + + if key != "data" { + return Err(M::Error::unknown_field(&key, &["type", "data"])); + } + + let matcher = access.next_value_seed(ListMatcherData(list))?; + + self.1[list.index()] = matcher; + + Ok(()) + } + } + + const FIELDS: &[&str] = &["type", "data"]; + deserializer.deserialize_struct( + "ListMatcher", + FIELDS, + ListMatcherEntryVisitor(self.0, self.1), + ) + } +} + +struct ListMatcherSlice<'a>(&'a Scheme, &'a mut [Box]); + +impl<'de> DeserializeSeed<'de> for ListMatcherSlice<'_> { + type Value = (); + + fn deserialize(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct ListMatcherSliceVisitor<'a>(&'a Scheme, &'a mut [Box]); + + impl<'de> Visitor<'de> for ListMatcherSliceVisitor<'_> { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "a list of list matcher data") + } + + fn visit_seq(self, mut access: S) -> Result<(), S::Error> + where + S: SeqAccess<'de>, + { + while let Some(()) = access.next_element_seed(ListMatcherEntry(self.0, self.1))? {} + + Ok(()) + } + } + + deserializer.deserialize_seq(ListMatcherSliceVisitor(self.0, self.1)) + } +} + +impl Serialize for ListMatcherSlice<'_> { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + #[derive(Serialize)] + struct TypedListMatcher<'a> { + #[serde(rename = "type")] + ty: Type, + data: &'a dyn erased_serde::Serialize, + } + + let mut seq = serializer.serialize_seq(Some(self.1.len()))?; + for list in self.0.lists() { + let matcher = &*self.1[list.index()] as &dyn erased_serde::Serialize; + seq.serialize_element(&TypedListMatcher { + ty: list.get_type(), + data: matcher, + })?; + } + seq.end() + } } impl<'de, U> DeserializeSeed<'de> for &mut ExecutionContext<'de, U> { @@ -312,7 +443,7 @@ impl<'de, U> DeserializeSeed<'de> for &mut ExecutionContext<'de, U> { type Value = (); fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "a map of lhs value") + write!(formatter, "a serialized execution context") } fn visit_map(self, mut access: M) -> Result<(), M::Error> @@ -322,20 +453,10 @@ impl<'de, U> DeserializeSeed<'de> for &mut ExecutionContext<'de, U> { while let Some(key) = access.next_key::>()? { if key == "$lists" { // Deserialize lists - let vec = access.next_value::>()?; - for ListData { ty, data } in vec.into_iter() { - let list = self.0.scheme.get_list(&ty).ok_or_else(|| { - de::Error::custom(format!("unknown list for type: {ty:?}")) - })?; - self.0.list_matchers[list.index()] = list - .definition() - .matcher_from_json_value(ty, data) - .map_err(|err| { - de::Error::custom(format!( - "failed to deserialize list matcher: {err:?}" - )) - })?; - } + access.next_value_seed(ListMatcherSlice( + &self.0.scheme, + &mut self.0.list_matchers, + ))?; } else { let field = self .0 @@ -381,6 +502,13 @@ impl Serialize for ExecutionContext<'_, U> { struct ListMatcherSlice<'a>(&'a Scheme, &'a [Box]); + #[derive(Serialize)] + struct TypedListMatcher<'a> { + #[serde(rename = "type")] + ty: Type, + data: &'a dyn erased_serde::Serialize, + } + impl Serialize for ListMatcherSlice<'_> { fn serialize(&self, serializer: S) -> Result where @@ -388,13 +516,11 @@ impl Serialize for ExecutionContext<'_, U> { { let mut seq = serializer.serialize_seq(Some(self.1.len()))?; for list in self.0.lists() { - let data = self.1[list.index()].to_json_value(); - if data != serde_json::Value::Null { - seq.serialize_element(&ListData { - ty: list.get_type(), - data, - })?; - } + let matcher = &*self.1[list.index()] as &dyn erased_serde::Serialize; + seq.serialize_element(&TypedListMatcher { + ty: list.get_type(), + data: matcher, + })?; } seq.end() } diff --git a/engine/src/list_matcher.rs b/engine/src/list_matcher.rs index 4832c332..c8d38580 100644 --- a/engine/src/list_matcher.rs +++ b/engine/src/list_matcher.rs @@ -1,7 +1,7 @@ use crate::LhsValue; use crate::Type; use dyn_clone::DynClone; -use serde_json::Value; +use serde::{Deserialize, Serialize}; use std::any::Any; use std::fmt::Debug; @@ -10,15 +10,15 @@ use std::fmt::Debug; /// `ListDefinition` needs to be registered in the `Scheme` for a given `Type`. /// See `Scheme::add_list`. pub trait ListDefinition: Debug + Sync + Send { - /// Converts a deserialized `serde_json::Value` into a `ListMatcher`. + /// Deserializes a list matcher. /// /// This method is necessary to support deserialization of lists during the /// the deserialization of an `ExecutionContext`. - fn matcher_from_json_value( + fn deserialize_matcher<'de>( &self, ty: Type, - value: Value, - ) -> Result, serde_json::Error>; + deserializer: &mut dyn erased_serde::Deserializer<'de>, + ) -> Result, erased_serde::Error>; /// Creates a new matcher object for this list. fn new_matcher(&self) -> Box; @@ -58,14 +58,13 @@ impl DynPartialEq for T { } } -/// Implement this Trait to match a given `LhsValue` against a list. -pub trait ListMatcher: AsAny + Debug + DynClone + DynPartialEq + Send + Sync + 'static { +/// Implement this trait to match a given `LhsValue` against a list. +pub trait ListMatcher: + AsAny + Debug + DynClone + DynPartialEq + Send + Sync + erased_serde::Serialize + 'static +{ /// Returns true if `val` is in the given list. fn match_value(&self, list_name: &str, val: &LhsValue<'_>) -> bool; - /// Convert the list matcher to a serde_json::Value in order to serialize it. - fn to_json_value(&self) -> Value; - /// Clears the list matcher, removing all its content. fn clear(&mut self); } @@ -84,16 +83,17 @@ impl PartialEq for dyn ListMatcher { pub struct AlwaysList {} /// Matcher for `AlwaysList` -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct AlwaysListMatcher {} impl ListDefinition for AlwaysList { - fn matcher_from_json_value( + fn deserialize_matcher<'de>( &self, _: Type, - _: serde_json::Value, - ) -> Result, serde_json::Error> { - Ok(Box::new(AlwaysListMatcher {})) + deserializer: &mut dyn erased_serde::Deserializer<'de>, + ) -> Result, erased_serde::Error> { + let matcher = erased_serde::deserialize::(deserializer)?; + Ok(Box::new(matcher)) } fn new_matcher(&self) -> Box { @@ -106,10 +106,6 @@ impl ListMatcher for AlwaysListMatcher { false } - fn to_json_value(&self) -> serde_json::Value { - serde_json::Value::Null - } - fn clear(&mut self) {} } @@ -118,16 +114,17 @@ impl ListMatcher for AlwaysListMatcher { pub struct NeverList {} /// Matcher for `NeverList` -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct NeverListMatcher {} impl ListDefinition for NeverList { - fn matcher_from_json_value( + fn deserialize_matcher<'de>( &self, _: Type, - _: serde_json::Value, - ) -> Result, serde_json::Error> { - Ok(Box::new(NeverListMatcher {})) + deserializer: &mut dyn erased_serde::Deserializer<'de>, + ) -> Result, erased_serde::Error> { + let matcher = erased_serde::deserialize::(deserializer)?; + Ok(Box::new(matcher)) } fn new_matcher(&self) -> Box { @@ -140,10 +137,6 @@ impl ListMatcher for NeverListMatcher { false } - fn to_json_value(&self) -> serde_json::Value { - serde_json::Value::Null - } - fn clear(&mut self) {} } diff --git a/ffi/tests/ctests/src/tests.c b/ffi/tests/ctests/src/tests.c index c6ddf27c..b1470b1d 100644 --- a/ffi/tests/ctests/src/tests.c +++ b/ffi/tests/ctests/src/tests.c @@ -512,7 +512,7 @@ void wirefilter_ffi_ctest_execution_context_serialize() { struct wirefilter_rust_allocated_str json = serializing_result.json; rust_assert(json.ptr != NULL && json.len > 0, "could not serialize execution context to JSON"); - const char *expected = "{\"http.host\":\"www.cloudflare.com\",\"ip.src\":\"192.168.0.1\",\"ip.dst\":\"2606:4700:4700::1111\",\"ssl\":false,\"tcp.port\":80,\"$lists\":[]}"; + const char *expected = "{\"http.host\":\"www.cloudflare.com\",\"ip.src\":\"192.168.0.1\",\"ip.dst\":\"2606:4700:4700::1111\",\"ssl\":false,\"tcp.port\":80,\"$lists\":[{\"type\":\"Ip\",\"data\":{}}]}"; rust_assert(json.len == strlen(expected), "invalid JSON serialization"); @@ -548,7 +548,7 @@ void wirefilter_ffi_ctest_execution_context_deserialize() { rust_assert(json.ptr != NULL && json.len > 0, "could not serialize execution context to JSON"); rust_assert( - strncmp(json.ptr, "{\"http.host\":\"www.cloudflare.com\",\"$lists\":[]}", json.len) == 0, + strncmp(json.ptr, "{\"http.host\":\"www.cloudflare.com\",\"$lists\":[{\"type\":\"Ip\",\"data\":{}}]}", json.len) == 0, "invalid JSON serialization" ); @@ -567,7 +567,7 @@ void wirefilter_ffi_ctest_execution_context_deserialize() { rust_assert(conv_json.ptr != NULL && conv_json.len > 0, "could not serialize execution context to JSON"); rust_assert( - strncmp(conv_json.ptr, "{\"http.host\":\"www.cloudflare.com\",\"$lists\":[]}", conv_json.len) == 0, + strncmp(conv_json.ptr, "{\"http.host\":\"www.cloudflare.com\",\"$lists\":[{\"type\":\"Ip\",\"data\":{}}]}", conv_json.len) == 0, "invalid JSON serialization" ); From 2beccf5fe81e61e48baf5a98a39a7959cde0cd46 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Wed, 7 Jan 2026 09:38:47 +0100 Subject: [PATCH 10/30] Fully remove ability to mutate an `Array` It was only possible internally but now all private methods are gone and one *must* go through a `TypedArray` to build an `Array`. --- engine/src/lhs_types/array.rs | 70 +++++++++++++---------------------- 1 file changed, 25 insertions(+), 45 deletions(-) diff --git a/engine/src/lhs_types/array.rs b/engine/src/lhs_types/array.rs index 384960b8..bfc9f68f 100644 --- a/engine/src/lhs_types/array.rs +++ b/engine/src/lhs_types/array.rs @@ -30,40 +30,6 @@ impl<'a> InnerArray<'a> { const fn new() -> Self { Self::Owned(Vec::new()) } - - #[inline] - fn as_vec(&mut self) -> &mut Vec> { - match self { - InnerArray::Owned(vec) => vec, - InnerArray::Borrowed(slice) => { - *self = InnerArray::Owned(slice.to_vec()); - match self { - InnerArray::Owned(vec) => vec, - _ => unsafe { unreachable_unchecked() }, - } - } - } - } - - #[inline] - fn get_mut(&mut self, idx: usize) -> Option<&mut LhsValue<'a>> { - self.as_vec().get_mut(idx) - } - - #[inline] - fn push(&mut self, value: LhsValue<'a>) { - self.as_vec().push(value) - } - - #[inline] - fn truncate(&mut self, len: usize) { - match self { - InnerArray::Owned(vec) => vec.truncate(len), - InnerArray::Borrowed(slice) => { - *slice = &slice[..len]; - } - } - } } impl<'a> Deref for InnerArray<'a> { @@ -168,8 +134,11 @@ impl<'a> Array<'a> { where F: Fn(LhsValue<'a>) -> Option>, { - let Self { mut data, .. } = self; - let mut vec = std::mem::take(data.as_vec()); + let Self { data, .. } = self; + let mut vec = match data { + InnerArray::Owned(vec) => vec, + InnerArray::Borrowed(slice) => slice.to_vec(), + }; let val_type = value_type.into(); let mut write = 0; for read in 0..vec.len() { @@ -361,7 +330,10 @@ impl<'de> DeserializeSeed<'de> for &mut Array<'de> { A: SeqAccess<'de>, { let value_type = self.0.value_type(); - let vec = self.0.data.as_vec(); + let mut vec = match &mut self.0.data { + InnerArray::Owned(vec) => std::mem::take(vec), + InnerArray::Borrowed(slice) => slice.to_vec(), + }; while let Some(elem) = seq.next_element_seed(LhsValueSeed(&value_type))? { let elem_type = elem.get_type(); if value_type != elem_type { @@ -371,6 +343,7 @@ impl<'de> DeserializeSeed<'de> for &mut Array<'de> { } vec.push(elem); } + self.0.data = InnerArray::Owned(vec); Ok(()) } } @@ -396,16 +369,24 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, V> { pub const fn new() -> Self { const { Self { - array: InnerArray::new(), + array: InnerArray::Owned(Vec::new()), _marker: std::marker::PhantomData, } } } + #[inline] + fn as_vec(&mut self) -> &mut Vec> { + match &mut self.array { + InnerArray::Owned(vec) => vec, + InnerArray::Borrowed(_) => unreachable!(), + } + } + /// Push an element to the back of the array #[inline] pub fn push(&mut self, value: V) { - self.array.push(value.into_value()) + self.as_vec().push(value.into_value()) } /// Returns the number of elements in the array @@ -423,7 +404,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, V> { /// Shortens the array, keeping the first `len` elements and dropping the rest. #[inline] pub fn truncate(&mut self, len: usize) { - self.array.truncate(len); + self.as_vec().truncate(len); } /// Converts the strongly typed array into a borrowed loosely typed array. @@ -446,7 +427,7 @@ impl TypedArray<'static, bool> { #[inline] pub(crate) fn iter_mut(&mut self) -> impl ExactSizeIterator + '_ { - self.array.as_vec().iter_mut().map(|value| match value { + self.as_vec().iter_mut().map(|value| match value { LhsValue::Bool(b) => b, _ => unsafe { unreachable_unchecked() }, }) @@ -496,8 +477,7 @@ impl<'a, V: IntoValue<'a>> Default for TypedArray<'a, V> { impl<'a, V: IntoValue<'a>> Extend for TypedArray<'a, V> { #[inline] fn extend>(&mut self, iter: T) { - self.array - .as_vec() + self.as_vec() .extend(iter.into_iter().map(IntoValue::into_value)) } } @@ -538,7 +518,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, TypedArray<'a, V>> { /// Returns a mutable reference to an element or None if the index is out of bounds. pub fn get_mut(&mut self, index: usize) -> Option<&mut TypedArray<'a, V>> { - self.array.get_mut(index).map(|val| match val { + self.as_vec().get_mut(index).map(|val| match val { LhsValue::Array(array) => { // Safety: this is safe because `TypedArray` is a repr(transparent) // newtype over `InnerArray`. @@ -568,7 +548,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, TypedMap<'a, V>> { /// Returns a mutable reference to an element or None if the index is out of bounds. pub fn get_mut(&mut self, index: usize) -> Option<&mut TypedMap<'a, V>> { - self.array.get_mut(index).map(|val| match val { + self.as_vec().get_mut(index).map(|val| match val { LhsValue::Map(map) => { // Safety: this is safe because `TypedMap` is a repr(transparent) // newtype over `InnerMap`. From 3363b0723f08a67b47724b6f0e71491e7df5f1c9 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Thu, 8 Jan 2026 11:23:27 +0100 Subject: [PATCH 11/30] Allow downstream crates to convert their own types to `LhsValue::Bytes` --- engine/src/lhs_types/bytes.rs | 14 +++++ engine/src/types.rs | 104 ++++------------------------------ 2 files changed, 25 insertions(+), 93 deletions(-) diff --git a/engine/src/lhs_types/bytes.rs b/engine/src/lhs_types/bytes.rs index 863203f0..0ebf1f69 100644 --- a/engine/src/lhs_types/bytes.rs +++ b/engine/src/lhs_types/bytes.rs @@ -145,6 +145,13 @@ impl From> for Bytes<'static> { } } +impl<'a> From<&'a Box> for Bytes<'a> { + #[inline] + fn from(value: &'a Box) -> Self { + Bytes::Borrowed(value.as_bytes()) + } +} + impl From for Bytes<'static> { #[inline] fn from(value: String) -> Self { @@ -153,6 +160,13 @@ impl From for Bytes<'static> { } } +impl<'a> From<&'a String> for Bytes<'a> { + #[inline] + fn from(value: &'a String) -> Self { + Bytes::Borrowed(value.as_bytes()) + } +} + impl<'a> From> for Bytes<'a> { #[inline] fn from(value: Cow<'a, str>) -> Self { diff --git a/engine/src/types.rs b/engine/src/types.rs index 9ba58521..03c79549 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -8,7 +8,6 @@ use crate::{ use serde::de::{DeserializeSeed, Deserializer}; use serde::{Deserialize, Serialize, Serializer}; use std::{ - borrow::Cow, cmp::Ordering, collections::BTreeSet, convert::TryFrom, @@ -473,7 +472,6 @@ impl PartialEq for LhsValue<'_> { mod private { use super::IntoValue; use crate::{Bytes, TypedArray, TypedMap}; - use std::borrow::Cow; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; pub trait SealedIntoValue {} @@ -488,20 +486,12 @@ mod private { impl SealedIntoValue for u32 {} impl SealedIntoValue for i64 {} - impl SealedIntoValue for &[u8] {} - impl SealedIntoValue for Box<[u8]> {} - impl SealedIntoValue for Vec {} - impl SealedIntoValue for Cow<'_, [u8]> {} - impl SealedIntoValue for &str {} - impl SealedIntoValue for Box {} - impl SealedIntoValue for String {} - impl SealedIntoValue for Cow<'_, str> {} - impl SealedIntoValue for Bytes<'_> {} - impl SealedIntoValue for IpAddr {} impl SealedIntoValue for Ipv4Addr {} impl SealedIntoValue for Ipv6Addr {} + impl<'a, T: Into>> SealedIntoValue for T {} + impl<'a, V: IntoValue<'a>> SealedIntoValue for TypedArray<'a, V> {} impl<'a, V: IntoValue<'a>> SealedIntoValue for TypedMap<'a, V> {} } @@ -579,87 +569,6 @@ impl<'a> IntoValue<'a> for u8 { } } -impl<'a> IntoValue<'a> for &'a [u8] { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for Box<[u8]> { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for Vec { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for Cow<'a, [u8]> { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for &'a str { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for Box { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for String { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for Cow<'a, str> { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(Bytes::from(self)) - } -} - -impl<'a> IntoValue<'a> for Bytes<'a> { - const TYPE: Type = Type::Bytes; - - #[inline] - fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(self) - } -} - impl<'a> IntoValue<'a> for IpAddr { const TYPE: Type = Type::Ip; @@ -687,6 +596,15 @@ impl<'a> IntoValue<'a> for Ipv6Addr { } } +impl<'a, T: Into>> IntoValue<'a> for T { + const TYPE: Type = Type::Bytes; + + #[inline] + fn into_value(self) -> LhsValue<'a> { + LhsValue::Bytes(self.into()) + } +} + impl<'a, T: IntoValue<'a>> From for LhsValue<'a> { #[inline] fn from(value: T) -> Self { From 4ca01369cbb83549d32da49f9797a43db6b6840c Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Fri, 9 Jan 2026 13:22:20 +0100 Subject: [PATCH 12/30] Prefer `From` trait over `Into` to fix small performance regression --- engine/src/types.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/engine/src/types.rs b/engine/src/types.rs index 03c79549..7dda16a2 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -490,7 +490,7 @@ mod private { impl SealedIntoValue for Ipv4Addr {} impl SealedIntoValue for Ipv6Addr {} - impl<'a, T: Into>> SealedIntoValue for T {} + impl<'a, T> SealedIntoValue for T where Bytes<'a>: From {} impl<'a, V: IntoValue<'a>> SealedIntoValue for TypedArray<'a, V> {} impl<'a, V: IntoValue<'a>> SealedIntoValue for TypedMap<'a, V> {} @@ -596,12 +596,15 @@ impl<'a> IntoValue<'a> for Ipv6Addr { } } -impl<'a, T: Into>> IntoValue<'a> for T { +impl<'a, T> IntoValue<'a> for T +where + Bytes<'a>: From, +{ const TYPE: Type = Type::Bytes; #[inline] fn into_value(self) -> LhsValue<'a> { - LhsValue::Bytes(self.into()) + LhsValue::Bytes(Bytes::from(self)) } } From 27fbb35b3c1e892b74a817de3d43c848102851d8 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Thu, 8 Jan 2026 17:17:47 +0100 Subject: [PATCH 13/30] Refactor map code * `Map` and `InnerMap` are now fully immutable * Internal `Deref` impl has been removed to pave for the future introduction of a map trait * Iterators have been reworked --- engine/src/ast/function_expr.rs | 2 +- engine/src/lhs_types/map.rs | 238 +++++++++++++++++++++----------- engine/src/types.rs | 2 +- 3 files changed, 163 insertions(+), 79 deletions(-) diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index 8640b78b..6ad87eb7 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -295,7 +295,7 @@ impl ValueExpr for FunctionCallExpr { // Extract the values of the map if let LhsValue::Map(map) = first { first = LhsValue::Array( - Array::try_from_iter(map.value_type(), map.values_into_iter()).unwrap(), + Array::try_from_iter(map.value_type(), map.into_values()).unwrap(), ); } // Retrieve the underlying `Array` diff --git a/engine/src/lhs_types/map.rs b/engine/src/lhs_types/map.rs index b65e7ab3..8486fcdd 100644 --- a/engine/src/lhs_types/map.rs +++ b/engine/src/lhs_types/map.rs @@ -13,8 +13,6 @@ use std::{ collections::BTreeMap, fmt, hash::{Hash, Hasher}, - hint::unreachable_unchecked, - ops::Deref, }; use super::{TypedArray, array::InnerArray}; @@ -32,43 +30,34 @@ impl<'a> InnerMap<'a> { } #[inline] - fn as_map(&mut self) -> &mut BTreeMap, LhsValue<'a>> { + fn len(&self) -> usize { match self { - InnerMap::Owned(map) => map, - InnerMap::Borrowed(map) => { - *self = InnerMap::Owned(map.clone()); - match self { - InnerMap::Owned(map) => map, - _ => unsafe { unreachable_unchecked() }, - } - } + Self::Owned(map) => map.len(), + Self::Borrowed(map) => map.len(), } } #[inline] - fn get_mut(&mut self, key: &[u8]) -> Option<&mut LhsValue<'a>> { - self.as_map().get_mut(key) - } - - #[inline] - fn insert(&mut self, key: Box<[u8]>, value: LhsValue<'a>) { - self.as_map().insert(key, value); + fn is_empty(&self) -> bool { + match self { + Self::Owned(map) => map.is_empty(), + Self::Borrowed(map) => map.is_empty(), + } } #[inline] - fn get_or_insert(&mut self, key: Box<[u8]>, value: LhsValue<'a>) -> &mut LhsValue<'a> { - self.as_map().entry(key).or_insert(value) + fn get>(&self, key: K) -> Option<&LhsValue<'a>> { + match self { + Self::Owned(map) => map.get(key.as_ref()), + Self::Borrowed(map) => map.get(key.as_ref()), + } } -} - -impl<'a> Deref for InnerMap<'a> { - type Target = BTreeMap, LhsValue<'a>>; #[inline] - fn deref(&self) -> &Self::Target { + fn iter(&self) -> MapIter<'a, '_> { match self { - InnerMap::Owned(map) => map, - InnerMap::Borrowed(ref_map) => ref_map, + Self::Owned(map) => MapIter(map.iter()), + Self::Borrowed(map) => MapIter(map.iter()), } } } @@ -79,6 +68,16 @@ impl Default for InnerMap<'_> { } } +impl Hash for InnerMap<'_> { + #[inline] + fn hash(&self, state: &mut H) { + match self { + Self::Owned(map) => map.hash(state), + Self::Borrowed(map) => map.hash(state), + } + } +} + /// A map of string to [`Type`]. #[derive(Debug, Clone)] pub struct Map<'a> { @@ -130,22 +129,25 @@ impl<'a> Map<'a> { } /// Returns the type of the contained values. + #[inline] pub fn value_type(&self) -> Type { self.val_type.into() } /// Returns the number of elements in the map + #[inline] pub fn len(&self) -> usize { self.data.len() } /// Returns true if the map contains no elements. + #[inline] pub fn is_empty(&self) -> bool { self.data.is_empty() } /// Convert current map into an iterator over contained values - pub fn values_into_iter(self) -> MapValuesIntoIter<'a> { + pub fn into_values(self) -> MapValuesIntoIter<'a> { let Map { data, .. } = self; match data { InnerMap::Owned(map) => MapValuesIntoIter::Owned(map.into_iter()), @@ -166,7 +168,7 @@ impl<'a> Map<'a> { /// Creates an iterator visiting all key-value pairs in arbitrary order. #[inline] pub fn iter(&self) -> MapIter<'a, '_> { - MapIter(self.data.iter()) + self.data.iter() } /// Creates a new map from the specified iterator. @@ -201,7 +203,21 @@ impl<'a> Map<'a> { impl<'a> PartialEq for Map<'a> { #[inline] fn eq(&self, other: &Map<'a>) -> bool { - self.val_type == other.val_type && self.data.deref() == other.data.deref() + if self.val_type != other.val_type { + return false; + } + + if self.data.len() != other.data.len() { + return false; + } + + for (k, v) in self.data.iter() { + if other.data.get(k) != Some(v) { + return false; + } + } + + true } } @@ -217,7 +233,7 @@ impl GetType for Map<'_> { impl Hash for Map<'_> { fn hash(&self, state: &mut H) { self.get_type().hash(state); - self.data.deref().hash(state); + self.data.hash(state); } } @@ -268,6 +284,7 @@ impl<'a> Iterator for MapValuesIntoIter<'a> { } impl ExactSizeIterator for MapValuesIntoIter<'_> { + #[inline] fn len(&self) -> usize { match self { MapValuesIntoIter::Owned(iter) => iter.len(), @@ -276,13 +293,36 @@ impl ExactSizeIterator for MapValuesIntoIter<'_> { } } +enum MapIntoIterImpl<'a> { + Owned(std::collections::btree_map::IntoIter, LhsValue<'a>>), + Borrowed(std::collections::btree_map::Iter<'a, Box<[u8]>, LhsValue<'a>>), +} + +pub struct MapIntoIter<'a>(MapIntoIterImpl<'a>); + +impl<'a> Iterator for MapIntoIter<'a> { + type Item = (Cow<'a, [u8]>, LhsValue<'a>); + + fn next(&mut self) -> Option { + match self { + MapIntoIter(MapIntoIterImpl::Owned(iter)) => { + iter.next().map(|(k, v)| (Vec::from(k).into(), v)) + } + MapIntoIter(MapIntoIterImpl::Borrowed(iter)) => { + iter.next().map(|(k, v)| ((&**k).into(), v.as_ref())) + } + } + } +} + impl<'a> IntoIterator for Map<'a> { - type Item = (Box<[u8]>, LhsValue<'a>); - type IntoIter = std::collections::btree_map::IntoIter, LhsValue<'a>>; + type Item = (Cow<'a, [u8]>, LhsValue<'a>); + type IntoIter = MapIntoIter<'a>; + fn into_iter(self) -> Self::IntoIter { match self.data { - InnerMap::Owned(map) => map.into_iter(), - InnerMap::Borrowed(ref_map) => ref_map.clone().into_iter(), + InnerMap::Owned(map) => MapIntoIter(MapIntoIterImpl::Owned(map.into_iter())), + InnerMap::Borrowed(map) => MapIntoIter(MapIntoIterImpl::Borrowed(map.iter())), } } } @@ -293,7 +333,7 @@ impl<'a, 'b> IntoIterator for &'b Map<'a> { #[inline] fn into_iter(self) -> Self::IntoIter { - MapIter(self.data.deref().iter()) + self.data.iter() } } @@ -302,7 +342,10 @@ impl Serialize for Map<'_> { where S: Serializer, { - let to_map = self.data.keys().all(|key| std::str::from_utf8(key).is_ok()); + let to_map = self + .data + .iter() + .all(|(key, _)| std::str::from_utf8(key).is_ok()); if to_map { let mut map = serializer.serialize_map(Some(self.len()))?; @@ -313,14 +356,14 @@ impl Serialize for Map<'_> { } else { // Keys have to be sorted in order to have reproducible output let mut keys = Vec::new(); - for key in self.data.keys() { + for (key, _) in self.data.iter() { keys.push(key) } keys.sort(); let mut seq = serializer.serialize_seq(Some(self.len()))?; for key in keys { seq.serialize_element(&[ - &LhsValue::Bytes((&**key).into()), + &LhsValue::Bytes(key.into()), self.data.get(key).unwrap(), ])?; } @@ -389,6 +432,17 @@ impl<'de> DeserializeSeed<'de> for &mut Map<'de> { M: MapAccess<'de>, { let value_type = self.0.value_type(); + let map = match &mut self.0.data { + InnerMap::Owned(map) => map, + InnerMap::Borrowed(map) => { + let map = map.clone(); + self.0.data = InnerMap::Owned(map); + match &mut self.0.data { + InnerMap::Owned(map) => map, + InnerMap::Borrowed(_) => unreachable!(), + } + } + }; while let Some(key) = access.next_key::>()? { let value = access.next_value_seed(LhsValueSeed(&value_type))?; if value.get_type() != value_type { @@ -398,9 +452,7 @@ impl<'de> DeserializeSeed<'de> for &mut Map<'de> { value_type ))); } - self.0 - .data - .insert(key.into_owned().into_bytes().into(), value); + map.insert(key.into_owned().into_bytes().into(), value); } Ok(()) @@ -411,6 +463,17 @@ impl<'de> DeserializeSeed<'de> for &mut Map<'de> { V: SeqAccess<'de>, { let value_type = self.0.value_type(); + let map = match &mut self.0.data { + InnerMap::Owned(map) => map, + InnerMap::Borrowed(map) => { + let map = map.clone(); + self.0.data = InnerMap::Owned(map); + match &mut self.0.data { + InnerMap::Owned(map) => map, + InnerMap::Borrowed(_) => unreachable!(), + } + } + }; while let Some((key, value)) = seq.next_element_seed(MapEntrySeed(&value_type))? { if value.get_type() != value_type { return Err(de::Error::custom(format!( @@ -419,7 +482,7 @@ impl<'de> DeserializeSeed<'de> for &mut Map<'de> { value_type ))); } - self.0.data.insert(key.into_owned(), value); + map.insert(key.into_owned(), value); } Ok(()) } @@ -446,48 +509,64 @@ impl<'a, V: IntoValue<'a>> TypedMap<'a, V> { pub const fn new() -> Self { const { Self { - map: InnerMap::new(), + map: InnerMap::Owned(BTreeMap::new()), _marker: std::marker::PhantomData, } } } + #[inline] + fn as_map_ref(&self) -> &BTreeMap, LhsValue<'a>> { + match &self.map { + InnerMap::Owned(map) => map, + InnerMap::Borrowed(_) => unreachable!(), + } + } + + #[inline] + fn as_map_mut(&mut self) -> &mut BTreeMap, LhsValue<'a>> { + match &mut self.map { + InnerMap::Owned(map) => map, + InnerMap::Borrowed(_) => unreachable!(), + } + } + /// Push an element to the back of the map #[inline] pub fn insert(&mut self, key: Box<[u8]>, value: V) { - self.map.insert(key, value.into_value()) + self.as_map_mut().insert(key, value.into_value()); } /// Returns the number of elements in the array #[inline] pub fn len(&self) -> usize { - self.map.len() + self.as_map_ref().len() } /// Returns true if the array contains no elements. #[inline] pub fn is_empty(&self) -> bool { - self.map.is_empty() + self.as_map_ref().is_empty() } /// Converts the strongly typed map into a borrowed loosely typed map. pub fn as_map(&'a self) -> Map<'a> { Map { val_type: V::TYPE.into(), - data: InnerMap::Borrowed(self.map.deref()), + data: InnerMap::Borrowed(self.as_map_ref()), } } } impl<'a, V: IntoValue<'a>> fmt::Debug for TypedMap<'a, V> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_map().entries(self.map.iter()).finish() + fmt.debug_map().entries(self.as_map_ref().iter()).finish() } } impl<'a, V: IntoValue<'a>> PartialEq for TypedMap<'a, V> { fn eq(&self, other: &Self) -> bool { - self.map.deref() == other.map.deref() + self.as_map_ref() == other.as_map_ref() } } @@ -498,7 +577,7 @@ impl<'a, 'k, V: Copy + IntoValue<'a>, S: AsRef<[(&'k [u8], V)]>> PartialEq fo .iter() .copied() .map(|(k, v)| (k, v.into_value())) - .eq(self.map.iter().map(|(k, v)| (&**k, v.as_ref()))) + .eq(self.as_map_ref().iter().map(|(k, v)| (&**k, v.as_ref()))) } } @@ -522,8 +601,7 @@ impl<'a, V: IntoValue<'a>> Default for TypedMap<'a, V> { impl<'a, V: IntoValue<'a>> Extend<(Box<[u8]>, V)> for TypedMap<'a, V> { #[inline] fn extend, V)>>(&mut self, iter: T) { - self.map - .as_map() + self.as_map_mut() .extend(iter.into_iter().map(|(k, v)| (k, v.into_value()))) } } @@ -552,7 +630,7 @@ impl<'a, V: IntoValue<'a>> IntoValue<'a> for TypedMap<'a, V> { impl<'a, V: IntoValue<'a>> TypedMap<'a, TypedMap<'a, V>> { /// Returns a reference to the value corresponding to the key. pub fn get>(&self, key: K) -> Option<&TypedMap<'a, V>> { - self.map.get(key.as_ref()).map(|val| match val { + self.as_map_ref().get(key.as_ref()).map(|val| match val { LhsValue::Map(map) => { // Safety: this is safe because `TypedMap` is a repr(transparent) // newtype over `InnerMap`. @@ -564,16 +642,20 @@ impl<'a, V: IntoValue<'a>> TypedMap<'a, TypedMap<'a, V>> { /// Returns a mutable reference to the value corresponding to the key. pub fn get_mut>(&mut self, key: K) -> Option<&mut TypedMap<'a, V>> { - self.map.get_mut(key.as_ref()).map(|val| match val { - LhsValue::Map(map) => { - // Safety: this is safe because `TypedMap` is a repr(transparent) - // newtype over `InnerMap`. - unsafe { - std::mem::transmute::<&mut InnerMap<'a>, &mut TypedMap<'a, V>>(&mut map.data) + self.as_map_mut() + .get_mut(key.as_ref()) + .map(|val| match val { + LhsValue::Map(map) => { + // Safety: this is safe because `TypedMap` is a repr(transparent) + // newtype over `InnerMap`. + unsafe { + std::mem::transmute::<&mut InnerMap<'a>, &mut TypedMap<'a, V>>( + &mut map.data, + ) + } } - } - _ => unreachable!(), - }) + _ => unreachable!(), + }) } /// Returns a mutable reference to the value coressponding to the key or insert a new one. @@ -582,7 +664,7 @@ impl<'a, V: IntoValue<'a>> TypedMap<'a, TypedMap<'a, V>> { key: Box<[u8]>, value: TypedMap<'a, V>, ) -> &mut TypedMap<'a, V> { - match self.map.get_or_insert(key, value.into_value()) { + match self.as_map_mut().entry(key).or_insert(value.into_value()) { LhsValue::Map(map) => { // Safety: this is safe because `TypedMap` is a repr(transparent) // newtype over `InnerMap`. @@ -598,7 +680,7 @@ impl<'a, V: IntoValue<'a>> TypedMap<'a, TypedMap<'a, V>> { impl<'a, V: IntoValue<'a>> TypedMap<'a, TypedArray<'a, V>> { /// Returns a reference to the value corresponding to the key. pub fn get>(&self, key: K) -> Option<&TypedArray<'a, V>> { - self.map.get(key.as_ref()).map(|val| match val { + self.as_map_ref().get(key.as_ref()).map(|val| match val { LhsValue::Array(array) => { // Safety: this is safe because `TypedArray` is a repr(transparent) // newtype over `InnerArray`. @@ -610,18 +692,20 @@ impl<'a, V: IntoValue<'a>> TypedMap<'a, TypedArray<'a, V>> { /// Returns a mutable reference to the value corresponding to the key. pub fn get_mut>(&mut self, key: K) -> Option<&mut TypedArray<'a, V>> { - self.map.get_mut(key.as_ref()).map(|val| match val { - LhsValue::Array(array) => { - // Safety: this is safe because `TypedArray` is a repr(transparent) - // newtype over `InnerArray`. - unsafe { - std::mem::transmute::<&mut InnerArray<'a>, &mut TypedArray<'a, V>>( - &mut array.data, - ) + self.as_map_mut() + .get_mut(key.as_ref()) + .map(|val| match val { + LhsValue::Array(array) => { + // Safety: this is safe because `TypedArray` is a repr(transparent) + // newtype over `InnerArray`. + unsafe { + std::mem::transmute::<&mut InnerArray<'a>, &mut TypedArray<'a, V>>( + &mut array.data, + ) + } } - } - _ => unreachable!(), - }) + _ => unreachable!(), + }) } /// Returns a mutable reference to the value coressponding to the key or insert a new one. @@ -630,7 +714,7 @@ impl<'a, V: IntoValue<'a>> TypedMap<'a, TypedArray<'a, V>> { key: Box<[u8]>, value: TypedArray<'a, V>, ) -> &mut TypedArray<'a, V> { - match self.map.get_or_insert(key, value.into_value()) { + match self.as_map_mut().entry(key).or_insert(value.into_value()) { LhsValue::Array(array) => { // Safety: this is safe because `TypedArray` is a repr(transparent) // newtype over `InnerArray`. diff --git a/engine/src/types.rs b/engine/src/types.rs index 7dda16a2..a968baf4 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -864,7 +864,7 @@ impl<'a> IntoIterator for LhsValue<'a> { fn into_iter(self) -> Self::IntoIter { match self { LhsValue::Array(array) => IntoIter::IntoArray(array.into_iter()), - LhsValue::Map(map) => IntoIter::IntoMap(map.values_into_iter()), + LhsValue::Map(map) => IntoIter::IntoMap(map.into_values()), _ => unreachable!(), } } From 124b16da6277bb9397aa5528397fbb2fe9a3c81a Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Tue, 13 Jan 2026 18:47:33 +0100 Subject: [PATCH 14/30] Refactor array code * Remove `Deref` impl * Rework iterators --- engine/src/lhs_types/array.rs | 152 +++++++++++++++++++++++++--------- engine/src/lhs_types/mod.rs | 2 +- engine/src/types.rs | 8 +- 3 files changed, 120 insertions(+), 42 deletions(-) diff --git a/engine/src/lhs_types/array.rs b/engine/src/lhs_types/array.rs index bfc9f68f..ab594a15 100644 --- a/engine/src/lhs_types/array.rs +++ b/engine/src/lhs_types/array.rs @@ -11,7 +11,6 @@ use std::{ fmt, hash::{Hash, Hasher}, hint::unreachable_unchecked, - ops::Deref, }; use super::{TypedMap, map::InnerMap}; @@ -30,16 +29,36 @@ impl<'a> InnerArray<'a> { const fn new() -> Self { Self::Owned(Vec::new()) } -} -impl<'a> Deref for InnerArray<'a> { - type Target = [LhsValue<'a>]; + #[inline] + fn len(&self) -> usize { + match self { + InnerArray::Owned(vec) => vec.len(), + InnerArray::Borrowed(slice) => slice.len(), + } + } + + #[inline] + fn is_empty(&self) -> bool { + match self { + InnerArray::Owned(vec) => vec.is_empty(), + InnerArray::Borrowed(slice) => slice.is_empty(), + } + } + + #[inline] + fn get(&self, idx: usize) -> Option<&LhsValue<'a>> { + match self { + Self::Owned(vec) => vec.get(idx), + Self::Borrowed(slice) => slice.get(idx), + } + } #[inline] - fn deref(&self) -> &Self::Target { + fn iter(&self) -> std::slice::Iter<'_, LhsValue<'a>> { match self { - InnerArray::Owned(vec) => &vec[..], - InnerArray::Borrowed(slice) => slice, + Self::Owned(vec) => vec.iter(), + Self::Borrowed(slice) => slice.iter(), } } } @@ -50,6 +69,15 @@ impl Default for InnerArray<'_> { } } +impl Hash for InnerArray<'_> { + fn hash(&self, state: &mut H) { + match self { + InnerArray::Owned(vec) => vec.as_slice().hash(state), + InnerArray::Borrowed(slice) => slice.hash(state), + } + } +} + /// An array of [`Type`]. #[derive(Debug, Clone)] pub struct Array<'a> { @@ -114,6 +142,12 @@ impl<'a> Array<'a> { self.data.is_empty() } + /// Returns an iterator over the elements in array. + #[inline] + pub fn iter(&self) -> ArrayIter<'a, '_> { + ArrayIter(self.data.iter()) + } + pub(crate) fn extract(self, idx: usize) -> Option> { let Self { data, .. } = self; if idx >= data.len() { @@ -126,10 +160,6 @@ impl<'a> Array<'a> { } } - pub(crate) fn as_slice(&self) -> &[LhsValue<'a>] { - &self.data - } - pub(crate) fn filter_map_to(self, value_type: impl Into, func: F) -> Self where F: Fn(LhsValue<'a>) -> Option>, @@ -216,7 +246,21 @@ impl<'a> Array<'a> { impl<'a> PartialEq for Array<'a> { #[inline] fn eq(&self, other: &Array<'a>) -> bool { - self.val_type == other.val_type && self.data.deref() == other.data.deref() + if self.val_type != other.val_type { + return false; + } + + if self.data.len() != other.data.len() { + return false; + } + + for (v1, v2) in self.data.iter().zip(other.data.iter()) { + if v1 != v2 { + return false; + } + } + + true } } @@ -231,7 +275,7 @@ impl GetType for Array<'_> { impl Hash for Array<'_> { fn hash(&self, state: &mut H) { self.get_type().hash(state); - self.data.deref().hash(state); + self.data.hash(state); } } @@ -248,18 +292,18 @@ impl<'a, V: IntoValue<'a>> FromIterator for Array<'a> { } } -pub enum ArrayIterator<'a> { +pub enum ArrayIntoIter<'a> { Owned(std::vec::IntoIter>), Borrowed(AsRefIterator<'a, std::slice::Iter<'a, LhsValue<'a>>>), } -impl<'a> Iterator for ArrayIterator<'a> { +impl<'a> Iterator for ArrayIntoIter<'a> { type Item = LhsValue<'a>; fn next(&mut self) -> Option { match self { - ArrayIterator::Owned(vec_iter) => vec_iter.next(), - ArrayIterator::Borrowed(slice_iter) => slice_iter.next(), + ArrayIntoIter::Owned(vec_iter) => vec_iter.next(), + ArrayIntoIter::Borrowed(slice_iter) => slice_iter.next(), } } @@ -268,31 +312,57 @@ impl<'a> Iterator for ArrayIterator<'a> { } } -impl ExactSizeIterator for ArrayIterator<'_> { +impl ExactSizeIterator for ArrayIntoIter<'_> { fn len(&self) -> usize { match self { - ArrayIterator::Owned(vec_iter) => vec_iter.len(), - ArrayIterator::Borrowed(slice_iter) => slice_iter.len(), + ArrayIntoIter::Owned(vec_iter) => vec_iter.len(), + ArrayIntoIter::Borrowed(slice_iter) => slice_iter.len(), } } } impl<'a> IntoIterator for Array<'a> { type Item = LhsValue<'a>; - type IntoIter = ArrayIterator<'a>; + type IntoIter = ArrayIntoIter<'a>; + fn into_iter(self) -> Self::IntoIter { match self.data { - InnerArray::Owned(vec) => ArrayIterator::Owned(vec.into_iter()), - InnerArray::Borrowed(slice) => ArrayIterator::Borrowed(AsRefIterator(slice.iter())), + InnerArray::Owned(vec) => ArrayIntoIter::Owned(vec.into_iter()), + InnerArray::Borrowed(slice) => ArrayIntoIter::Borrowed(AsRefIterator(slice.iter())), } } } +pub struct ArrayIter<'a, 'b>(std::slice::Iter<'b, LhsValue<'a>>); + +impl<'a, 'b> Iterator for ArrayIter<'a, 'b> { + type Item = &'b LhsValue<'a>; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.len(), Some(self.len())) + } +} + +impl ExactSizeIterator for ArrayIter<'_, '_> { + #[inline] + fn len(&self) -> usize { + self.0.len() + } +} + impl<'a, 'b> IntoIterator for &'b Array<'a> { type Item = &'b LhsValue<'a>; - type IntoIter = std::slice::Iter<'b, LhsValue<'a>>; + type IntoIter = ArrayIter<'a, 'b>; + + #[inline] fn into_iter(self) -> Self::IntoIter { - self.data.iter() + self.iter() } } @@ -376,7 +446,15 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, V> { } #[inline] - fn as_vec(&mut self) -> &mut Vec> { + fn as_vec_ref(&self) -> &Vec> { + match &self.array { + InnerArray::Owned(vec) => vec, + InnerArray::Borrowed(_) => unreachable!(), + } + } + + #[inline] + fn as_vec_mut(&mut self) -> &mut Vec> { match &mut self.array { InnerArray::Owned(vec) => vec, InnerArray::Borrowed(_) => unreachable!(), @@ -386,7 +464,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, V> { /// Push an element to the back of the array #[inline] pub fn push(&mut self, value: V) { - self.as_vec().push(value.into_value()) + self.as_vec_mut().push(value.into_value()) } /// Returns the number of elements in the array @@ -404,14 +482,14 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, V> { /// Shortens the array, keeping the first `len` elements and dropping the rest. #[inline] pub fn truncate(&mut self, len: usize) { - self.as_vec().truncate(len); + self.as_vec_mut().truncate(len); } /// Converts the strongly typed array into a borrowed loosely typed array. pub fn as_array(&'a self) -> Array<'a> { Array { val_type: V::TYPE.into(), - data: InnerArray::Borrowed(self.array.deref()), + data: InnerArray::Borrowed(self.as_vec_ref()), } } } @@ -419,7 +497,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, V> { impl TypedArray<'static, bool> { #[inline] pub(crate) fn iter(&self) -> impl ExactSizeIterator + '_ { - self.array.iter().map(|value| match value { + self.as_vec_ref().iter().map(|value| match value { LhsValue::Bool(b) => b, _ => unsafe { unreachable_unchecked() }, }) @@ -427,7 +505,7 @@ impl TypedArray<'static, bool> { #[inline] pub(crate) fn iter_mut(&mut self) -> impl ExactSizeIterator + '_ { - self.as_vec().iter_mut().map(|value| match value { + self.as_vec_mut().iter_mut().map(|value| match value { LhsValue::Bool(b) => b, _ => unsafe { unreachable_unchecked() }, }) @@ -442,7 +520,7 @@ impl<'a, V: IntoValue<'a>> fmt::Debug for TypedArray<'a, V> { impl<'a, V: IntoValue<'a>> PartialEq for TypedArray<'a, V> { fn eq(&self, other: &Self) -> bool { - self.array.deref() == other.array.deref() + self.as_vec_ref() == other.as_vec_ref() } } @@ -477,7 +555,7 @@ impl<'a, V: IntoValue<'a>> Default for TypedArray<'a, V> { impl<'a, V: IntoValue<'a>> Extend for TypedArray<'a, V> { #[inline] fn extend>(&mut self, iter: T) { - self.as_vec() + self.as_vec_mut() .extend(iter.into_iter().map(IntoValue::into_value)) } } @@ -506,7 +584,7 @@ impl<'a, V: IntoValue<'a>> IntoValue<'a> for TypedArray<'a, V> { impl<'a, V: IntoValue<'a>> TypedArray<'a, TypedArray<'a, V>> { /// Returns a reference to an element or None if the index is out of bounds. pub fn get(&self, index: usize) -> Option<&TypedArray<'a, V>> { - self.array.get(index).map(|val| match val { + self.as_vec_ref().get(index).map(|val| match val { LhsValue::Array(array) => { // Safety: this is safe because `TypedArray` is a repr(transparent) // newtype over `InnerArray`. @@ -518,7 +596,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, TypedArray<'a, V>> { /// Returns a mutable reference to an element or None if the index is out of bounds. pub fn get_mut(&mut self, index: usize) -> Option<&mut TypedArray<'a, V>> { - self.as_vec().get_mut(index).map(|val| match val { + self.as_vec_mut().get_mut(index).map(|val| match val { LhsValue::Array(array) => { // Safety: this is safe because `TypedArray` is a repr(transparent) // newtype over `InnerArray`. @@ -536,7 +614,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, TypedArray<'a, V>> { impl<'a, V: IntoValue<'a>> TypedArray<'a, TypedMap<'a, V>> { /// Returns a reference to an element or None if the index is out of bounds. pub fn get(&self, index: usize) -> Option<&TypedMap<'a, V>> { - self.array.get(index).map(|val| match val { + self.as_vec_ref().get(index).map(|val| match val { LhsValue::Map(map) => { // Safety: this is safe because `TypedMap` is a repr(transparent) // newtype over `InnerMap`. @@ -548,7 +626,7 @@ impl<'a, V: IntoValue<'a>> TypedArray<'a, TypedMap<'a, V>> { /// Returns a mutable reference to an element or None if the index is out of bounds. pub fn get_mut(&mut self, index: usize) -> Option<&mut TypedMap<'a, V>> { - self.as_vec().get_mut(index).map(|val| match val { + self.as_vec_mut().get_mut(index).map(|val| match val { LhsValue::Map(map) => { // Safety: this is safe because `TypedMap` is a repr(transparent) // newtype over `InnerMap`. diff --git a/engine/src/lhs_types/mod.rs b/engine/src/lhs_types/mod.rs index fe773bdf..170e2d41 100644 --- a/engine/src/lhs_types/mod.rs +++ b/engine/src/lhs_types/mod.rs @@ -5,7 +5,7 @@ mod map; use crate::types::LhsValue; pub use self::{ - array::{Array, ArrayIterator, TypedArray}, + array::{Array, ArrayIntoIter, ArrayIter, TypedArray}, bytes::Bytes, map::{Map, MapIter, MapValuesIntoIter, TypedMap}, }; diff --git a/engine/src/types.rs b/engine/src/types.rs index a968baf4..997a2600 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -1,6 +1,6 @@ use crate::{ lex::{Lex, LexResult, LexWith, expect, skip_space}, - lhs_types::{Array, ArrayIterator, Bytes, Map, MapIter, MapValuesIntoIter}, + lhs_types::{Array, ArrayIntoIter, ArrayIter, Bytes, Map, MapIter, MapValuesIntoIter}, rhs_types::{BytesExpr, IntRange, IpRange, UninhabitedArray, UninhabitedBool, UninhabitedMap}, scheme::{FieldIndex, IndexAccessError}, strict_partial_ord::StrictPartialOrd, @@ -772,7 +772,7 @@ impl<'a> LhsValue<'a> { /// Returns an iterator over the Map or Array pub(crate) fn iter(&'a self) -> Option> { match self { - LhsValue::Array(array) => Some(Iter::IterArray(array.as_slice().iter())), + LhsValue::Array(array) => Some(Iter::IterArray(array.iter())), LhsValue::Map(map) => Some(Iter::IterMap(map.iter())), _ => None, } @@ -830,7 +830,7 @@ impl<'de> DeserializeSeed<'de> for LhsValueSeed<'_> { } pub enum IntoIter<'a> { - IntoArray(ArrayIterator<'a>), + IntoArray(ArrayIntoIter<'a>), IntoMap(MapValuesIntoIter<'a>), } @@ -871,7 +871,7 @@ impl<'a> IntoIterator for LhsValue<'a> { } pub(crate) enum Iter<'a> { - IterArray(std::slice::Iter<'a, LhsValue<'a>>), + IterArray(ArrayIter<'a, 'a>), IterMap(MapIter<'a, 'a>), } From 27a99d90dbf512b759e753dd5d4adcac485f6db9 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Fri, 30 Jan 2026 16:59:10 +0100 Subject: [PATCH 15/30] Avoid clone when compiling `OneOf` operator for IPs --- engine/src/ast/field_expr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 99527081..7faef188 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -697,8 +697,8 @@ impl Expr for ComparisonExpr { RhsValues::Ip(ranges) => { let mut v4 = Vec::new(); let mut v6 = Vec::new(); - for range in ranges { - match range.clone().into() { + for range in ranges.into_iter() { + match range.into() { ExplicitIpRange::V4(range) => v4.push(range), ExplicitIpRange::V6(range) => v6.push(range), } From 333d96e5c42e46a36d3323a534bafae54afd2239 Mon Sep 17 00:00:00 2001 From: marmeladema Date: Fri, 6 Feb 2026 20:59:57 +0100 Subject: [PATCH 16/30] Replace `memmem` by `memchr` as default substring searcher engine Because it is more performant and properly maintained. --- Cargo.lock | 12 +++------ Cargo.toml | 2 +- engine/Cargo.toml | 2 +- engine/src/ast/field_expr.rs | 4 +-- engine/src/searcher.rs | 51 ++++++------------------------------ 5 files changed, 15 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d9ba11a..490aabe3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -512,15 +512,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.7.4" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memmem" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miniz_oxide" @@ -1201,7 +1195,7 @@ dependencies = [ "fnv", "getrandom", "indoc", - "memmem", + "memchr", "rand", "regex-automata", "serde", diff --git a/Cargo.toml b/Cargo.toml index 5577450f..b18dc98a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ fnv = "1.0.6" getrandom = { version = "0.3" } indoc = "2" libc = "0.2.42" -memmem = "0.1.1" +memchr = "2.8.0" num_enum = "0.7" rand = "0.9" regex-automata = { version = "0.4.9" } diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 83a32aae..bda62f07 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -26,7 +26,7 @@ cidr.workspace = true dyn-clone.workspace = true erased-serde.workspace = true fnv.workspace = true -memmem.workspace = true +memchr.workspace = true rand.workspace = true regex-automata = { workspace = true, optional = true } serde.workspace = true diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 7faef188..6ac30266 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -13,7 +13,7 @@ use crate::{ range_set::RangeSet, rhs_types::{BytesExpr, ExplicitIpRange, ListName, Regex, Wildcard}, scheme::{Field, Identifier, List}, - searcher::{EmptySearcher, TwoWaySearcher}, + searcher::{EmptySearcher, MemmemSearcher}, strict_partial_ord::StrictPartialOrd, types::{GetType, LhsValue, RhsValue, RhsValues, Type}, }; @@ -686,7 +686,7 @@ impl Expr for ComparisonExpr { }; } - search!(TwoWaySearcher::new(bytes)) + search!(MemmemSearcher::new(bytes)) } ComparisonOpExpr::Matches(regex) => lhs.compile_with(compiler, false, regex), ComparisonOpExpr::Wildcard(wildcard) => lhs.compile_with(compiler, false, wildcard), diff --git a/engine/src/searcher.rs b/engine/src/searcher.rs index 136e268d..403faf94 100644 --- a/engine/src/searcher.rs +++ b/engine/src/searcher.rs @@ -1,6 +1,5 @@ -use memmem::Searcher; +use memchr::memmem::{Finder, FinderBuilder}; use sliceslice::MemchrSearcher; -use std::mem::ManuallyDrop; use crate::{Compare, ExecutionContext, LhsValue}; @@ -13,44 +12,20 @@ impl Compare for EmptySearcher { } } -pub struct TwoWaySearcher { - // This is an `Box` whose lifetime must exceed `searcher`. - needle: *mut [u8], +pub struct MemmemSearcher(Finder<'static>); - // We need this because `memmem::TwoWaySearcher` wants a lifetime for the data it refers to, but - // we don't want to tie it to the lifetime of `TwoWaySearcher`, since our data is heap-allocated - // and is guaranteed to deref to the same address across moves of the container. Hence, we use - // `static` as a substitute lifetime and it points to the same the data as `needle`. - searcher: ManuallyDrop>, -} - -// This is safe because we are only ever accessing `needle` mutably during `Drop::drop` -// which is statically enforced by the compiler to be called once when the searcher is -// not in used anymore. -unsafe impl Send for TwoWaySearcher {} -// This is safe because we are only ever accessing `needle` mutably during `Drop::drop` -// which is statically enforced by the compiler to be called once when the searcher is -// not in used anymore. -unsafe impl Sync for TwoWaySearcher {} - -impl TwoWaySearcher { +impl MemmemSearcher { + #[inline] pub fn new(needle: Box<[u8]>) -> Self { - let needle = Box::into_raw(needle); - // Convert needle's contents to the static lifetime. - let needle_static = unsafe { &*needle }; - - TwoWaySearcher { - needle, - searcher: ManuallyDrop::new(memmem::TwoWaySearcher::new(needle_static)), - } + Self(FinderBuilder::new().build_forward_owned(needle)) } } -impl Compare for TwoWaySearcher { +impl Compare for MemmemSearcher { #[inline] fn compare<'e>(&self, value: &LhsValue<'e>, _: &'e ExecutionContext<'e, U>) -> bool { - self.searcher - .search_in(match value { + self.0 + .find(match value { LhsValue::Bytes(bytes) => bytes, _ => unreachable!(), }) @@ -58,16 +33,6 @@ impl Compare for TwoWaySearcher { } } -impl Drop for TwoWaySearcher { - fn drop(&mut self) { - unsafe { - // Explicitly drop `searcher` first in case it needs `needle` to be alive. - ManuallyDrop::drop(&mut self.searcher); - drop(Box::from_raw(self.needle)); - } - } -} - impl Compare for MemchrSearcher { #[inline] fn compare<'e>(&self, value: &LhsValue<'e>, _: &'e ExecutionContext<'e, U>) -> bool { From bc66f5672b9e3159d417e4d44c7f222ffecf995d Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Mon, 9 Feb 2026 09:56:44 +0100 Subject: [PATCH 17/30] Re-use heap allocation when converting bytes expr to map key --- engine/src/scheme.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/scheme.rs b/engine/src/scheme.rs index c23066ad..57031911 100644 --- a/engine/src/scheme.rs +++ b/engine/src/scheme.rs @@ -82,7 +82,7 @@ impl<'i> Lex<'i> for FieldIndex { input, )), }, - RhsValue::Bytes(b) => match String::from_utf8(b.to_vec()) { + RhsValue::Bytes(b) => match String::from_utf8(b.into()) { Ok(s) => Ok((FieldIndex::MapKey(s), rest)), Err(_) => Err((LexErrorKind::ExpectedLiteral("expected utf8 string"), input)), }, From 279af41500ef3226872a8b6768f67d33bb609135 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Fri, 6 Feb 2026 13:41:54 +0000 Subject: [PATCH 18/30] Run tombi format --- Cargo.toml | 32 ++++++++++++++++---------------- engine/Cargo.toml | 22 +++++++++++----------- ffi/Cargo.toml | 16 +++++++++++----- ffi/tests/ctests/Cargo.toml | 2 +- fuzz/bytes/Cargo.toml | 2 +- fuzz/map-keys/Cargo.toml | 2 +- fuzz/raw-string/Cargo.toml | 2 +- 7 files changed, 42 insertions(+), 36 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b18dc98a..7072bafe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,19 @@ [workspace] +resolver = "2" members = [ - "engine", - "ffi", - "fuzz/bytes", - "fuzz/raw-string", - "fuzz/map-keys", - "wasm", + "engine", + "ffi", + "fuzz/bytes", + "fuzz/map-keys", + "fuzz/raw-string", + "wasm", ] -resolver = "2" [workspace.package] -authors = [ "Ingvar Stepanyan " ] version = "0.7.0" -publish = true +authors = ["Ingvar Stepanyan "] edition = "2024" +publish = true [workspace.dependencies] backtrace = "0.3" @@ -23,23 +23,23 @@ criterion = "0.5" dyn-clone = "1.0.20" erased-serde = "0.4.9" fnv = "1.0.6" -getrandom = { version = "0.3" } +getrandom = "0.3" indoc = "2" libc = "0.2.42" memchr = "2.8.0" num_enum = "0.7" rand = "0.9" -regex-automata = { version = "0.4.9" } -serde = { version = "1.0.113", features = [ "derive" ] } +regex-automata = "0.4.9" +serde = { version = "1.0.113", features = ["derive"] } serde_json = "1.0.56" sliceslice = "0.4.3" thiserror = "2.0" wildcard = "0.3.0" -wirefilter = { path = "engine", package = "wirefilter-engine" } +wirefilter = { package = "wirefilter-engine", path = "engine" } -[profile.release] +[profile.dev] panic = "unwind" -lto = true -[profile.dev] +[profile.release] +lto = true panic = "unwind" diff --git a/engine/Cargo.toml b/engine/Cargo.toml index bda62f07..bf7b9b00 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -1,23 +1,23 @@ [package] -authors.workspace = true name = "wirefilter-engine" version.workspace = true +authors.workspace = true +edition.workspace = true description = "An execution engine for Wireshark-like filters" readme = "README.md" -license = "MIT" repository = "https://github.com/cloudflare/wirefilter" -keywords = [ "wireshark", "filter", "engine", "parser", "runtime" ] -categories = [ "config", "parser-implementations" ] +license = "MIT" +keywords = ["engine", "filter", "parser", "runtime", "wireshark"] +categories = ["config", "parser-implementations"] publish.workspace = true -edition.workspace = true [lib] -name = "wirefilter" bench = false +name = "wirefilter" [[bench]] -name = "bench" harness = false +name = "bench" [dependencies] backtrace.workspace = true @@ -39,12 +39,12 @@ criterion.workspace = true indoc.workspace = true serde_json.workspace = true -[features] -default = [ "regex" ] -regex = ["dep:regex-automata"] - [target.'cfg(target_family = "wasm")'.dependencies] # By default, getrandom doesn't have any source of randomness on wasm32-unknown. # This optional dependency allows us to build with `--features getrandom/wasm_js`. # For more information see: https://docs.rs/getrandom/#webassembly-support getrandom.workspace = true + +[features] +default = ["regex"] +regex = ["dep:regex-automata"] diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index 53d50e75..d47ec987 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -1,19 +1,25 @@ [package] -authors.workspace = true name = "wirefilter-ffi" version.workspace = true +authors.workspace = true +edition.workspace = true description = "FFI bindings for the Wirefilter engine" publish = false -edition.workspace = true [package.metadata.deb] -assets = [ [ "target/release/libwirefilter_ffi.so", "usr/local/lib/libwirefilter.so", "644" ] ] +assets = [ + [ + "target/release/libwirefilter_ffi.so", + "usr/local/lib/libwirefilter.so", + "644", + ], +] [lib] -crate-type = [ "cdylib", "rlib" ] +bench = false +crate-type = ["cdylib", "rlib"] # Avoid duplicate compilation error messages as we don't have doctests anyway doctest = false -bench = false [dependencies] fnv.workspace = true diff --git a/ffi/tests/ctests/Cargo.toml b/ffi/tests/ctests/Cargo.toml index d4fbdb41..40704349 100644 --- a/ffi/tests/ctests/Cargo.toml +++ b/ffi/tests/ctests/Cargo.toml @@ -7,7 +7,7 @@ publish = false edition = "2024" [dependencies] -wirefilter-ffi = {path = "../.."} +wirefilter-ffi = { path = "../.." } [build-dependencies] cc = "1.0" diff --git a/fuzz/bytes/Cargo.toml b/fuzz/bytes/Cargo.toml index a9bb9290..520aa6e4 100644 --- a/fuzz/bytes/Cargo.toml +++ b/fuzz/bytes/Cargo.toml @@ -8,4 +8,4 @@ afl = "0.15" wirefilter.workspace = true [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } +unexpected_cfgs = { level = "warn", check-cfg = ["cfg(fuzzing)"] } diff --git a/fuzz/map-keys/Cargo.toml b/fuzz/map-keys/Cargo.toml index 7a31cfe8..cd1d29cf 100644 --- a/fuzz/map-keys/Cargo.toml +++ b/fuzz/map-keys/Cargo.toml @@ -8,4 +8,4 @@ afl = "0.15" wirefilter.workspace = true [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } +unexpected_cfgs = { level = "warn", check-cfg = ["cfg(fuzzing)"] } diff --git a/fuzz/raw-string/Cargo.toml b/fuzz/raw-string/Cargo.toml index f649a81e..b1f74575 100644 --- a/fuzz/raw-string/Cargo.toml +++ b/fuzz/raw-string/Cargo.toml @@ -8,4 +8,4 @@ afl = "0.15" wirefilter.workspace = true [lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } +unexpected_cfgs = { level = "warn", check-cfg = ["cfg(fuzzing)"] } From b2d5670c33dc718270ab2cf370c6a2ea4a841d31 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Fri, 6 Feb 2026 13:59:45 +0000 Subject: [PATCH 19/30] Add tombi format --check to CI --- .github/workflows/rust.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ec0eff6e..51762eb3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -17,12 +17,14 @@ jobs: with: toolchain: stable components: clippy,rustfmt + - uses: tombi-toml/setup-tombi@v1 - name: Print versions run: | cargo --version rustc --version clippy-driver --version rustfmt --version + tombi --version - name: Build run: cargo build --verbose - name: Run tests @@ -31,6 +33,8 @@ jobs: run: cargo clippy --verbose --all-targets -- -D clippy::all - name: Check code formatting run: cargo fmt --verbose --all -- --check + - name: Check toml formatting + run: tombi format --check doc: name: Documentation From 51f81b6817e094ff2a5df46ee720745d0f3e06de Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Fri, 6 Feb 2026 13:45:37 +0000 Subject: [PATCH 20/30] Move all deps to workspace Cargo.toml --- Cargo.toml | 4 ++++ ffi/Cargo.toml | 2 +- wasm/Cargo.toml | 8 ++++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7072bafe..17c453ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ publish = true [workspace.dependencies] backtrace = "0.3" +cbindgen = "0.28" cfg-if = "1" cidr = { version = "0.2", features = ["serde"] } criterion = "0.5" @@ -25,6 +26,7 @@ erased-serde = "0.4.9" fnv = "1.0.6" getrandom = "0.3" indoc = "2" +js-sys = "0.3.77" libc = "0.2.42" memchr = "2.8.0" num_enum = "0.7" @@ -32,8 +34,10 @@ rand = "0.9" regex-automata = "0.4.9" serde = { version = "1.0.113", features = ["derive"] } serde_json = "1.0.56" +serde-wasm-bindgen = "0.5.0" sliceslice = "0.4.3" thiserror = "2.0" +wasm-bindgen = { version = "0.2", features = ["serde-serialize"] } wildcard = "0.3.0" wirefilter = { package = "wirefilter-engine", path = "engine" } diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index d47ec987..fd588f1c 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -34,7 +34,7 @@ indoc.workspace = true regex-automata.workspace = true [build-dependencies] -cbindgen = "0.28" +cbindgen.workspace = true [target.'cfg(unix)'.dev-dependencies] wirefilter-ffi-ctests = { path = "tests/ctests" } diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 050a64ad..1f50f0fc 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -12,8 +12,8 @@ crate-type = ["cdylib"] doctest = false [dependencies] -getrandom = { version = "0.3", features = ["wasm_js"] } -js-sys = "0.3.77" -serde-wasm-bindgen = "0.5.0" -wasm-bindgen = { version = "0.2", features = ["serde-serialize"] } +getrandom = { workspace = true, features = ["wasm_js"] } +js-sys.workspace = true +serde-wasm-bindgen.workspace = true +wasm-bindgen.workspace = true wirefilter.workspace = true From d9acc05144ddd4d89c74e289a8e931bc4965a81b Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Fri, 6 Feb 2026 16:53:00 +0000 Subject: [PATCH 21/30] Update deps --- Cargo.lock | 724 +++++++++++++++++++++++++++++++++-------------------- Cargo.toml | 34 +-- 2 files changed, 463 insertions(+), 295 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 490aabe3..63879ac6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,24 +4,24 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "afl" -version = "0.15.13" +version = "0.15.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b784d6332a6978dd29861676de9df37aa37ed8852341db6340bd75eb82bc7a69" +checksum = "927cd71710d1a232519e2393470e8f74a178ae59367efe58fa122884bba35ca4" dependencies = [ "home", "libc", @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -46,9 +46,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -61,49 +61,56 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -111,20 +118,20 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-link", ] [[package]] name = "bitflags" -version = "2.6.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "cast" @@ -139,7 +146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff" dependencies = [ "clap", - "heck", + "heck 0.4.1", "indexmap", "log", "proc-macro2", @@ -153,18 +160,19 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.4" +version = "1.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "ciborium" @@ -204,18 +212,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" dependencies = [ "anstream", "anstyle", @@ -225,15 +233,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.4" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "criterion" @@ -298,9 +306,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "dyn-clone" @@ -310,15 +318,15 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "erased-serde" @@ -333,12 +341,12 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] @@ -347,12 +355,24 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "fuzz-bytes" version = "0.1.0" @@ -379,39 +399,62 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi", + "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "half" -version = "2.4.1" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", ] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -419,53 +462,70 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "home" -version = "0.5.9" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "indexmap" -version = "2.7.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] name = "indoc" -version = "2.0.5" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -478,37 +538,43 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", ] +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.168" +version = "0.2.181" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" +checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.22" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" @@ -518,9 +584,9 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] @@ -536,18 +602,19 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -557,24 +624,30 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "oorandom" -version = "11.1.4" +version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "paste" @@ -619,48 +692,57 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] @@ -675,18 +757,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom", + "getrandom 0.3.4", ] [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -694,9 +776,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -704,9 +786,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -716,9 +798,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -727,15 +809,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc_version" @@ -748,28 +830,22 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "same-file" @@ -782,15 +858,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "seq-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" @@ -835,21 +911,22 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -880,9 +957,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.90" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -891,31 +968,31 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.14.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys", ] [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -934,38 +1011,75 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.7+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1" +dependencies = [ "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "typeid" version = "1.0.3" @@ -974,9 +1088,15 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "utf8parse" @@ -995,19 +1115,28 @@ dependencies = [ ] [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -1015,27 +1144,14 @@ dependencies = [ "serde", "serde_json", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1043,141 +1159,108 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] [[package]] -name = "web-sys" -version = "0.3.77" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ - "js-sys", - "wasm-bindgen", + "leb128fmt", + "wasmparser", ] [[package]] -name = "wildcard" -version = "0.3.0" +name = "wasm-metadata" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b0540e91e49de3817c314da0dd3bc518093ceacc6ea5327cb0e1eb073e5189" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ - "thiserror", + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", ] [[package]] -name = "winapi-util" -version = "0.1.9" +name = "wasmparser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "windows-sys 0.59.0", + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "web-sys" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ - "windows-targets", + "js-sys", + "wasm-bindgen", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "wildcard" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f9b0540e91e49de3817c314da0dd3bc518093ceacc6ea5327cb0e1eb073e5189" dependencies = [ - "windows-targets", + "thiserror", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-sys", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -1193,7 +1276,7 @@ dependencies = [ "dyn-clone", "erased-serde", "fnv", - "getrandom", + "getrandom 0.3.4", "indoc", "memchr", "rand", @@ -1233,7 +1316,7 @@ dependencies = [ name = "wirefilter-wasm" version = "0.7.0" dependencies = [ - "getrandom", + "getrandom 0.3.4", "js-sys", "serde-wasm-bindgen", "wasm-bindgen", @@ -1241,36 +1324,121 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ + "anyhow", "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", ] [[package]] name = "xdg" -version = "2.5.2" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" +checksum = "2fb433233f2df9344722454bc7e96465c9d03bff9d77c248f9e7523fe79585b5" [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" diff --git a/Cargo.toml b/Cargo.toml index 17c453ce..5d6dff76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,28 +16,28 @@ edition = "2024" publish = true [workspace.dependencies] -backtrace = "0.3" -cbindgen = "0.28" -cfg-if = "1" -cidr = { version = "0.2", features = ["serde"] } -criterion = "0.5" +backtrace = "0.3.76" +cbindgen = "0.28.0" +cfg-if = "1.0.4" +cidr = { version = "0.2.3", features = ["serde"] } +criterion = "0.5.1" dyn-clone = "1.0.20" erased-serde = "0.4.9" -fnv = "1.0.6" -getrandom = "0.3" -indoc = "2" -js-sys = "0.3.77" -libc = "0.2.42" +fnv = "1.0.7" +getrandom = "0.3.4" +indoc = "2.0.7" +js-sys = "0.3.85" +libc = "0.2.181" memchr = "2.8.0" -num_enum = "0.7" -rand = "0.9" -regex-automata = "0.4.9" -serde = { version = "1.0.113", features = ["derive"] } -serde_json = "1.0.56" +num_enum = "0.7.5" +rand = "0.9.2" +regex-automata = "0.4.14" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.149" serde-wasm-bindgen = "0.5.0" sliceslice = "0.4.3" -thiserror = "2.0" -wasm-bindgen = { version = "0.2", features = ["serde-serialize"] } +thiserror = "2.0.18" +wasm-bindgen = { version = "0.2.108", features = ["serde-serialize"] } wildcard = "0.3.0" wirefilter = { package = "wirefilter-engine", path = "engine" } From a13f4ca4ca64a12e9c64ff249c9891161970dca1 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Fri, 6 Feb 2026 17:32:09 +0000 Subject: [PATCH 22/30] Upgrade deps --- Cargo.lock | 187 +++++++++++++++++++-------------------- Cargo.toml | 8 +- ffi/include/wirefilter.h | 2 +- 3 files changed, 97 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 63879ac6..f69bb03c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,6 +38,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloca" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4" +dependencies = [ + "cc", +] + [[package]] name = "anes" version = "0.1.6" @@ -123,15 +132,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5c6f81257d10a0f602a294ae4182251151ff97dbb504ef9afcdda4a64b24d9b4" [[package]] name = "cast" @@ -141,12 +150,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cbindgen" -version = "0.28.0" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff" +checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" dependencies = [ "clap", - "heck 0.4.1", + "heck", "indexmap", "log", "proc-macro2", @@ -160,9 +169,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.55" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ "find-msvc-tools", "shlex", @@ -212,18 +221,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.58" +version = "4.5.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" +checksum = "c5caf74d17c3aec5495110c34cc3f78644bfa89af6c8993ed4de2790e49b6499" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.58" +version = "4.5.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" +checksum = "370daa45065b80218950227371916a1633217ae42b2715b2287b606dcd618e24" dependencies = [ "anstream", "anstyle", @@ -245,25 +254,24 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "criterion" -version = "0.5.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3" dependencies = [ + "alloca", "anes", "cast", "ciborium", "clap", "criterion-plot", - "is-terminal", "itertools", "num-traits", - "once_cell", "oorandom", + "page_size", "plotters", "rayon", "regex", "serde", - "serde_derive", "serde_json", "tinytemplate", "walkdir", @@ -271,9 +279,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.5.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea" dependencies = [ "cast", "itertools", @@ -456,24 +464,12 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "home" version = "0.5.12" @@ -510,17 +506,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "is-terminal" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -529,9 +514,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -560,9 +545,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.181" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "linux-raw-sys" @@ -649,6 +634,16 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +[[package]] +name = "page_size" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "paste" version = "1.0.15" @@ -708,7 +703,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.10+spec-1.0.0", + "toml_edit", ] [[package]] @@ -880,9 +875,9 @@ dependencies = [ [[package]] name = "serde-wasm-bindgen" -version = "0.5.0" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" dependencies = [ "js-sys", "serde", @@ -924,11 +919,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -957,9 +952,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.114" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -1011,23 +1006,17 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" +version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "serde", + "indexmap", + "serde_core", "serde_spanned", - "toml_datetime 0.6.11", - "toml_edit 0.22.27", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", ] [[package]] @@ -1039,20 +1028,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime 0.6.11", - "toml_write", - "winnow", -] - [[package]] name = "toml_edit" version = "0.23.10+spec-1.0.0" @@ -1060,25 +1035,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime", "toml_parser", "winnow", ] [[package]] name = "toml_parser" -version = "1.0.7+spec-1.1.0" +version = "1.0.9+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow", ] [[package]] -name = "toml_write" -version = "0.1.2" +name = "toml_writer" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "typeid" @@ -1088,9 +1063,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "unicode-ident" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-xid" @@ -1232,6 +1207,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.11" @@ -1241,6 +1232,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-link" version = "0.2.1" @@ -1339,7 +1336,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" dependencies = [ "anyhow", - "heck 0.5.0", + "heck", "wit-parser", ] @@ -1350,7 +1347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", - "heck 0.5.0", + "heck", "indexmap", "prettyplease", "syn", @@ -1439,6 +1436,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml index 5d6dff76..655019b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,24 +17,24 @@ publish = true [workspace.dependencies] backtrace = "0.3.76" -cbindgen = "0.28.0" +cbindgen = "0.29.2" cfg-if = "1.0.4" cidr = { version = "0.2.3", features = ["serde"] } -criterion = "0.5.1" +criterion = "0.8.2" dyn-clone = "1.0.20" erased-serde = "0.4.9" fnv = "1.0.7" getrandom = "0.3.4" indoc = "2.0.7" js-sys = "0.3.85" -libc = "0.2.181" +libc = "0.2.182" memchr = "2.8.0" num_enum = "0.7.5" rand = "0.9.2" regex-automata = "0.4.14" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" -serde-wasm-bindgen = "0.5.0" +serde-wasm-bindgen = "0.6.5" sliceslice = "0.4.3" thiserror = "2.0.18" wasm-bindgen = { version = "0.2.108", features = ["serde-serialize"] } diff --git a/ffi/include/wirefilter.h b/ffi/include/wirefilter.h index 23c01510..7399491b 100644 --- a/ffi/include/wirefilter.h +++ b/ffi/include/wirefilter.h @@ -1,7 +1,7 @@ #ifndef _WIREFILTER_H_ #define _WIREFILTER_H_ -/* Generated with cbindgen:0.28.0 */ +/* Generated with cbindgen:0.29.2 */ /* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ From 22aa5f6d54bb903b344709cd7a63162f0b667db7 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 12 Feb 2026 12:04:27 +0000 Subject: [PATCH 23/30] Format YAML --- .github/workflows/rust.yml | 122 ++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 51762eb3..8d28063d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,9 +2,9 @@ name: Rust on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] env: CARGO_TERM_COLOR: always @@ -12,29 +12,29 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: stable - components: clippy,rustfmt - - uses: tombi-toml/setup-tombi@v1 - - name: Print versions - run: | - cargo --version - rustc --version - clippy-driver --version - rustfmt --version - tombi --version - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose - - name: Run clippy - run: cargo clippy --verbose --all-targets -- -D clippy::all - - name: Check code formatting - run: cargo fmt --verbose --all -- --check - - name: Check toml formatting - run: tombi format --check + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + components: clippy,rustfmt + - uses: tombi-toml/setup-tombi@v1 + - name: Print versions + run: | + cargo --version + rustc --version + clippy-driver --version + rustfmt --version + tombi --version + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose + - name: Run clippy + run: cargo clippy --verbose --all-targets -- -D clippy::all + - name: Check code formatting + run: cargo fmt --verbose --all -- --check + - name: Check toml formatting + run: tombi format --check doc: name: Documentation @@ -42,19 +42,19 @@ jobs: env: RUSTDOCFLAGS: -D warnings steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: stable - - name: Print versions - run: | - cargo --version - rustc --version - rustdoc --version - - name: Doc - run: cargo doc --verbose - - name: Doc with all features - run: cargo doc --verbose --all-features + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + - name: Print versions + run: | + cargo --version + rustc --version + rustdoc --version + - name: Doc + run: cargo doc --verbose + - name: Doc with all features + run: cargo doc --verbose --all-features miri-test: name: Test with miri @@ -62,13 +62,13 @@ jobs: env: MIRIFLAGS: -Zmiri-disable-isolation steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: nightly - components: miri - - run: cargo miri test --verbose --no-default-features - - run: cargo miri test --verbose --all-features + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: nightly + components: miri + - run: cargo miri test --verbose --no-default-features + - run: cargo miri test --verbose --all-features sanitizer-test: name: Test with -Zsanitizer=${{ matrix.sanitizer }} @@ -78,19 +78,19 @@ jobs: matrix: sanitizer: [address, thread, leak] steps: - - uses: actions/checkout@v4 - - uses: actions-rust-lang/setup-rust-toolchain@v1 - with: - toolchain: nightly - components: rust-src - - name: Test with sanitizer - env: - RUSTFLAGS: -Zsanitizer=${{ matrix.sanitizer }} - RUSTDOCFLAGS: -Zsanitizer=${{ matrix.sanitizer }} - # only needed by asan - ASAN_OPTIONS: detect_stack_use_after_return=1,detect_leaks=0 - # Asan's leak detection occasionally complains - # about some small leaks if backtraces are captured, - # so ensure they're not - RUST_BACKTRACE: 0 - run: cargo test -Zbuild-std --verbose --target=x86_64-unknown-linux-gnu --lib --bins --tests + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: nightly + components: rust-src + - name: Test with sanitizer + env: + RUSTFLAGS: -Zsanitizer=${{ matrix.sanitizer }} + RUSTDOCFLAGS: -Zsanitizer=${{ matrix.sanitizer }} + # only needed by asan + ASAN_OPTIONS: detect_stack_use_after_return=1,detect_leaks=0 + # Asan's leak detection occasionally complains + # about some small leaks if backtraces are captured, + # so ensure they're not + RUST_BACKTRACE: 0 + run: cargo test -Zbuild-std --verbose --target=x86_64-unknown-linux-gnu --lib --bins --tests From f65e225236d74567030de365ab8cb55c918f2a3b Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 12 Feb 2026 12:05:25 +0000 Subject: [PATCH 24/30] Update rust.yml --- .github/workflows/rust.yml | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8d28063d..94cf9aa7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,23 +16,34 @@ jobs: - uses: actions-rust-lang/setup-rust-toolchain@v1 with: toolchain: stable - components: clippy,rustfmt - - uses: tombi-toml/setup-tombi@v1 + components: clippy - name: Print versions run: | cargo --version rustc --version clippy-driver --version - rustfmt --version - tombi --version - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbose - name: Run clippy run: cargo clippy --verbose --all-targets -- -D clippy::all + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: nightly + components: rustfmt + - uses: tombi-toml/setup-tombi@v1 + - name: Print versions + run: | + cargo fmt --version + tombi --version - name: Check code formatting - run: cargo fmt --verbose --all -- --check + uses: actions-rust-lang/rustfmt@v1 - name: Check toml formatting run: tombi format --check From ec61f616c7a8cb83d7fb8ae6af3c733283aeab21 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 12 Feb 2026 11:52:55 +0000 Subject: [PATCH 25/30] Fix rustfmt.toml --- rustfmt.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index c9460f60..6ed1ba85 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,5 +1,5 @@ -format_doc_comments = true -merge_imports = true +format_code_in_doc_comments = true +imports_granularity = "Crate" normalize_comments = true normalize_doc_attributes = true wrap_comments = true From d14cb714ee6f486596224d1f1f9d9ff2eea24bd7 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 12 Feb 2026 11:53:11 +0000 Subject: [PATCH 26/30] Update rustfmt.toml --- rustfmt.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 6ed1ba85..9ded391f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,5 +1,9 @@ format_code_in_doc_comments = true -imports_granularity = "Crate" +format_macro_matchers = true +group_imports = "One" +imports_granularity = "Module" normalize_comments = true normalize_doc_attributes = true -wrap_comments = true +reorder_impl_items = true +use_field_init_shorthand = true +use_try_shorthand = true From 99fedf64d1fce182ead60371127c3360cef95b93 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Thu, 12 Feb 2026 11:53:43 +0000 Subject: [PATCH 27/30] Format code --- engine/src/functions/mod.rs | 2 +- engine/src/lhs_types/array.rs | 4 ++-- engine/src/lhs_types/map.rs | 4 ++-- engine/src/rhs_types/bytes.rs | 2 +- engine/src/types.rs | 5 +++-- ffi/src/lib.rs | 28 ++++++++++++++-------------- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/engine/src/functions/mod.rs b/engine/src/functions/mod.rs index 5fed9c05..10e497de 100644 --- a/engine/src/functions/mod.rs +++ b/engine/src/functions/mod.rs @@ -407,7 +407,7 @@ pub trait FunctionDefinition: Debug + Send + Sync { ) -> Box Fn(FunctionArgs<'i, 'a>) -> Option> + Sync + Send + 'static>; } -/* Simple function APIs */ +// Simple function APIs type FunctionPtr = for<'i, 'a> fn(FunctionArgs<'i, 'a>) -> Option>; diff --git a/engine/src/lhs_types/array.rs b/engine/src/lhs_types/array.rs index ab594a15..0ecb00ad 100644 --- a/engine/src/lhs_types/array.rs +++ b/engine/src/lhs_types/array.rs @@ -322,8 +322,8 @@ impl ExactSizeIterator for ArrayIntoIter<'_> { } impl<'a> IntoIterator for Array<'a> { - type Item = LhsValue<'a>; type IntoIter = ArrayIntoIter<'a>; + type Item = LhsValue<'a>; fn into_iter(self) -> Self::IntoIter { match self.data { @@ -357,8 +357,8 @@ impl ExactSizeIterator for ArrayIter<'_, '_> { } impl<'a, 'b> IntoIterator for &'b Array<'a> { - type Item = &'b LhsValue<'a>; type IntoIter = ArrayIter<'a, 'b>; + type Item = &'b LhsValue<'a>; #[inline] fn into_iter(self) -> Self::IntoIter { diff --git a/engine/src/lhs_types/map.rs b/engine/src/lhs_types/map.rs index 8486fcdd..92b8d203 100644 --- a/engine/src/lhs_types/map.rs +++ b/engine/src/lhs_types/map.rs @@ -316,8 +316,8 @@ impl<'a> Iterator for MapIntoIter<'a> { } impl<'a> IntoIterator for Map<'a> { - type Item = (Cow<'a, [u8]>, LhsValue<'a>); type IntoIter = MapIntoIter<'a>; + type Item = (Cow<'a, [u8]>, LhsValue<'a>); fn into_iter(self) -> Self::IntoIter { match self.data { @@ -328,8 +328,8 @@ impl<'a> IntoIterator for Map<'a> { } impl<'a, 'b> IntoIterator for &'b Map<'a> { - type Item = (&'b [u8], &'b LhsValue<'a>); type IntoIter = MapIter<'a, 'b>; + type Item = (&'b [u8], &'b LhsValue<'a>); #[inline] fn into_iter(self) -> Self::IntoIter { diff --git a/engine/src/rhs_types/bytes.rs b/engine/src/rhs_types/bytes.rs index b3ab6338..f37ad943 100644 --- a/engine/src/rhs_types/bytes.rs +++ b/engine/src/rhs_types/bytes.rs @@ -147,8 +147,8 @@ impl AsRef<[u8]> for BytesExpr { } impl<'a> IntoIterator for &'a BytesExpr { - type Item = &'a u8; type IntoIter = std::slice::Iter<'a, u8>; + type Item = &'a u8; #[inline] fn into_iter(self) -> std::slice::Iter<'a, u8> { diff --git a/engine/src/types.rs b/engine/src/types.rs index 997a2600..5d49e1d6 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -138,7 +138,7 @@ pub struct TypeMismatchError { } macro_rules! replace_underscore { - ($name:ident ($val_ty:ty)) => { + ($name:ident($val_ty:ty)) => { Type::$name(_) }; ($name:ident) => { @@ -859,8 +859,9 @@ impl ExactSizeIterator for IntoIter<'_> { } impl<'a> IntoIterator for LhsValue<'a> { - type Item = LhsValue<'a>; type IntoIter = IntoIter<'a>; + type Item = LhsValue<'a>; + fn into_iter(self) -> Self::IntoIter { match self { LhsValue::Array(array) => IntoIter::IntoArray(array.into_iter()), diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index ccc0f258..479d93a9 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -172,7 +172,7 @@ macro_rules! wrap_type { }; } -/* Wrapper types needed by cbindgen to forward declare opaque structs */ +// Wrapper types needed by cbindgen to forward declare opaque structs #[derive(Debug, Default)] #[repr(Rust)] @@ -668,9 +668,8 @@ pub struct MatchingResult { } impl MatchingResult { - #[cfg(test)] - const MISSED: Self = Self { - status: Status::Success, + const ERROR: Self = Self { + status: Status::Error, matched: false, }; #[cfg(test)] @@ -678,8 +677,9 @@ impl MatchingResult { status: Status::Success, matched: true, }; - const ERROR: Self = Self { - status: Status::Error, + #[cfg(test)] + const MISSED: Self = Self { + status: Status::Success, matched: false, }; const PANIC: Self = Self { @@ -724,6 +724,14 @@ pub struct UsingResult { } impl UsingResult { + const ERROR: Self = Self { + status: Status::Error, + used: false, + }; + const PANIC: Self = Self { + status: Status::Error, + used: false, + }; #[cfg(test)] const UNUSED: Self = Self { status: Status::Success, @@ -734,14 +742,6 @@ impl UsingResult { status: Status::Success, used: true, }; - const ERROR: Self = Self { - status: Status::Error, - used: false, - }; - const PANIC: Self = Self { - status: Status::Error, - used: false, - }; } #[unsafe(no_mangle)] From 6621924baf36f8ba7f603433dbe6f857ad3d5589 Mon Sep 17 00:00:00 2001 From: Utkarsh Gupta Date: Mon, 16 Feb 2026 10:23:15 +0000 Subject: [PATCH 28/30] Format imports --- engine/benches/bench.rs | 4 +- engine/src/ast/field_expr.rs | 66 +++++++++---------- engine/src/ast/function_expr.rs | 62 ++++++++---------- engine/src/ast/index_expr.rs | 32 +++++----- engine/src/ast/logical_expr.rs | 36 +++++------ engine/src/ast/mod.rs | 14 ++-- engine/src/ast/parse.rs | 6 +- engine/src/ast/visitor.rs | 12 ++-- engine/src/execution_context.rs | 8 +-- engine/src/filter.rs | 10 ++- engine/src/functions/mod.rs | 14 ++-- engine/src/lex.rs | 10 ++- engine/src/lhs_types/array.rs | 26 ++++---- engine/src/lhs_types/map.rs | 30 ++++----- engine/src/lhs_types/mod.rs | 9 +-- engine/src/lib.rs | 88 +++++++++++++------------- engine/src/list_matcher.rs | 3 +- engine/src/range_set.rs | 5 +- engine/src/rhs_types/array.rs | 13 ++-- engine/src/rhs_types/bool.rs | 9 ++- engine/src/rhs_types/bytes.rs | 16 ++--- engine/src/rhs_types/int.rs | 6 +- engine/src/rhs_types/ip.rs | 20 +++--- engine/src/rhs_types/map.rs | 13 ++-- engine/src/rhs_types/mod.rs | 20 +++--- engine/src/rhs_types/regex/imp_real.rs | 5 +- engine/src/rhs_types/regex/imp_stub.rs | 3 +- engine/src/rhs_types/wildcard.rs | 6 +- engine/src/scheme.rs | 31 ++++----- engine/src/searcher.rs | 3 +- engine/src/types.rs | 26 ++++---- ffi/src/cstring.rs | 8 +-- ffi/src/lib.rs | 10 ++- fuzz/map-keys/src/main.rs | 1 - 34 files changed, 274 insertions(+), 351 deletions(-) diff --git a/engine/benches/bench.rs b/engine/benches/bench.rs index 38a10e5b..33a351ec 100644 --- a/engine/benches/bench.rs +++ b/engine/benches/bench.rs @@ -6,7 +6,9 @@ use std::alloc::System; static A: System = System; use criterion::{Bencher, Criterion, criterion_group, criterion_main}; -use std::{clone::Clone, fmt::Debug, net::IpAddr}; +use std::clone::Clone; +use std::fmt::Debug; +use std::net::IpAddr; use wirefilter::{ Bytes, ExecutionContext, FilterAst, FunctionArgs, GetType, LhsValue, SchemeBuilder, SimpleFunctionArgKind, SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionParam, Type, diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 6ac30266..2a171a1e 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -1,22 +1,18 @@ -use super::{ - Expr, - function_expr::FunctionCallExpr, - parse::FilterParser, - visitor::{Visitor, VisitorMut}, -}; -use crate::{ - ExecutionContext, Scheme, - ast::index_expr::{Compare, IndexExpr}, - compiler::Compiler, - filter::CompiledExpr, - lex::{Lex, LexErrorKind, LexResult, LexWith, expect, skip_space, span}, - range_set::RangeSet, - rhs_types::{BytesExpr, ExplicitIpRange, ListName, Regex, Wildcard}, - scheme::{Field, Identifier, List}, - searcher::{EmptySearcher, MemmemSearcher}, - strict_partial_ord::StrictPartialOrd, - types::{GetType, LhsValue, RhsValue, RhsValues, Type}, -}; +use super::Expr; +use super::function_expr::FunctionCallExpr; +use super::parse::FilterParser; +use super::visitor::{Visitor, VisitorMut}; +use crate::ast::index_expr::{Compare, IndexExpr}; +use crate::compiler::Compiler; +use crate::filter::CompiledExpr; +use crate::lex::{Lex, LexErrorKind, LexResult, LexWith, expect, skip_space, span}; +use crate::range_set::RangeSet; +use crate::rhs_types::{BytesExpr, ExplicitIpRange, ListName, Regex, Wildcard}; +use crate::scheme::{Field, Identifier, List}; +use crate::searcher::{EmptySearcher, MemmemSearcher}; +use crate::strict_partial_ord::StrictPartialOrd; +use crate::types::{GetType, LhsValue, RhsValue, RhsValues, Type}; +use crate::{ExecutionContext, Scheme}; use serde::{Serialize, Serializer}; use sliceslice::MemchrSearcher; use std::cmp::Ordering; @@ -798,29 +794,29 @@ impl Expr for ComparisonExpr { #[allow(clippy::bool_assert_comparison)] mod tests { use super::*; + use crate::ast::function_expr::{FunctionCallArgExpr, FunctionCallExpr}; + use crate::ast::logical_expr::LogicalExpr; + use crate::execution_context::ExecutionContext; + use crate::functions::{ + FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, + FunctionParam, FunctionParamError, SimpleFunctionDefinition, SimpleFunctionImpl, + SimpleFunctionOptParam, SimpleFunctionParam, + }; + use crate::lhs_types::{Array, Map}; + use crate::list_matcher::{ListDefinition, ListMatcher}; + use crate::rhs_types::{IpRange, RegexFormat}; + use crate::scheme::{FieldIndex, IndexAccessError, Scheme}; + use crate::types::ExpectedType; use crate::{ BytesFormat, FieldRef, LhsValue, ParserSettings, SchemeBuilder, SimpleFunctionArgKind, TypedMap, - ast::{ - function_expr::{FunctionCallArgExpr, FunctionCallExpr}, - logical_expr::LogicalExpr, - }, - execution_context::ExecutionContext, - functions::{ - FunctionArgKind, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, - FunctionParam, FunctionParamError, SimpleFunctionDefinition, SimpleFunctionImpl, - SimpleFunctionOptParam, SimpleFunctionParam, - }, - lhs_types::{Array, Map}, - list_matcher::{ListDefinition, ListMatcher}, - rhs_types::{IpRange, RegexFormat}, - scheme::{FieldIndex, IndexAccessError, Scheme}, - types::ExpectedType, }; use cidr::IpCidr; use serde::Deserialize; + use std::convert::TryFrom; + use std::iter::once; + use std::net::IpAddr; use std::sync::LazyLock; - use std::{convert::TryFrom, iter::once, net::IpAddr}; fn any_function<'a>(args: FunctionArgs<'_, 'a>) -> Option> { match args.next()? { diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index 6ad87eb7..c9808941 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -1,26 +1,20 @@ -use super::{ - ValueExpr, - parse::FilterParser, - visitor::{Visitor, VisitorMut}, -}; -use crate::{ - FunctionRef, - ast::{ - field_expr::{ComparisonExpr, ComparisonOp, ComparisonOpExpr}, - index_expr::IndexExpr, - logical_expr::{LogicalExpr, UnaryOp}, - }, - compiler::Compiler, - filter::{CompiledExpr, CompiledValueExpr, CompiledValueResult}, - functions::{ - ExactSizeChain, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, FunctionParam, - FunctionParamError, - }, - lex::{Lex, LexError, LexErrorKind, LexResult, LexWith, expect, skip_space, span}, - lhs_types::Array, - scheme::Function, - types::{GetType, LhsValue, RhsValue, Type}, +use super::ValueExpr; +use super::parse::FilterParser; +use super::visitor::{Visitor, VisitorMut}; +use crate::FunctionRef; +use crate::ast::field_expr::{ComparisonExpr, ComparisonOp, ComparisonOpExpr}; +use crate::ast::index_expr::IndexExpr; +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, + FunctionParamError, }; +use crate::lex::{Lex, LexError, LexErrorKind, LexResult, LexWith, expect, skip_space, span}; +use crate::lhs_types::Array; +use crate::scheme::Function; +use crate::types::{GetType, LhsValue, RhsValue, Type}; use serde::Serialize; use std::hash::{Hash, Hasher}; use std::iter::once; @@ -526,21 +520,17 @@ impl<'i> LexWith<'i, &FilterParser<'_>> for FunctionCallExpr { #[cfg(test)] mod tests { use super::*; - use crate::{ - SimpleFunctionArgKind, - ast::{ - field_expr::{ComparisonExpr, ComparisonOpExpr, IdentifierExpr, OrderingOp}, - logical_expr::{LogicalExpr, LogicalOp, ParenthesizedExpr}, - parse::FilterParser, - }, - functions::{ - FunctionArgKind, FunctionArgKindMismatchError, FunctionArgs, SimpleFunctionDefinition, - SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, - }, - rhs_types::{BytesExpr, BytesFormat}, - scheme::{FieldIndex, IndexAccessError, Scheme}, - types::{RhsValues, Type, TypeMismatchError}, + use crate::SimpleFunctionArgKind; + use crate::ast::field_expr::{ComparisonExpr, ComparisonOpExpr, IdentifierExpr, OrderingOp}; + use crate::ast::logical_expr::{LogicalExpr, LogicalOp, ParenthesizedExpr}; + use crate::ast::parse::FilterParser; + use crate::functions::{ + FunctionArgKind, FunctionArgKindMismatchError, FunctionArgs, SimpleFunctionDefinition, + SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, }; + use crate::rhs_types::{BytesExpr, BytesFormat}; + use crate::scheme::{FieldIndex, IndexAccessError, Scheme}; + use crate::types::{RhsValues, Type, TypeMismatchError}; use std::convert::TryFrom; use std::sync::LazyLock; diff --git a/engine/src/ast/index_expr.rs b/engine/src/ast/index_expr.rs index dd1116cd..f1f8443c 100644 --- a/engine/src/ast/index_expr.rs +++ b/engine/src/ast/index_expr.rs @@ -1,19 +1,16 @@ -use super::{ - ValueExpr, - field_expr::IdentifierExpr, - parse::FilterParser, - visitor::{Visitor, VisitorMut}, -}; -use crate::{ - compiler::Compiler, - execution_context::ExecutionContext, - 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}; +use super::ValueExpr; +use super::field_expr::IdentifierExpr; +use super::parse::FilterParser; +use super::visitor::{Visitor, VisitorMut}; +use crate::compiler::Compiler; +use crate::execution_context::ExecutionContext; +use crate::filter::{CompiledExpr, CompiledOneExpr, CompiledValueExpr, CompiledVecExpr}; +use crate::lex::{Lex, LexErrorKind, LexResult, LexWith, expect, skip_space, span}; +use crate::lhs_types::{Array, Map, TypedArray}; +use crate::scheme::{FieldIndex, IndexAccessError}; +use crate::types::{GetType, IntoIter, LhsValue, Type}; +use serde::ser::SerializeSeq; +use serde::{Serialize, Serializer}; const BOOL_ARRAY: TypedArray<'_, bool> = TypedArray::new(); @@ -528,10 +525,11 @@ impl<'a> Iterator for MapEachIterator<'a, '_> { #[cfg(test)] mod tests { use super::*; + use crate::ast::field_expr::IdentifierExpr; use crate::{ Array, FieldIndex, FilterParser, FunctionArgs, FunctionCallArgExpr, FunctionCallExpr, Scheme, SchemeBuilder, SimpleFunctionArgKind, SimpleFunctionDefinition, SimpleFunctionImpl, - SimpleFunctionParam, ast::field_expr::IdentifierExpr, + SimpleFunctionParam, }; use std::sync::LazyLock; diff --git a/engine/src/ast/logical_expr.rs b/engine/src/ast/logical_expr.rs index 478b4e9f..4f1790a0 100644 --- a/engine/src/ast/logical_expr.rs +++ b/engine/src/ast/logical_expr.rs @@ -1,15 +1,11 @@ -use super::{ - Expr, - field_expr::ComparisonExpr, - parse::FilterParser, - visitor::{Visitor, VisitorMut}, -}; -use crate::{ - compiler::Compiler, - filter::{CompiledExpr, CompiledOneExpr, CompiledVecExpr}, - lex::{Lex, LexErrorKind, LexResult, LexWith, expect, skip_space}, - types::{GetType, Type, TypeMismatchError}, -}; +use super::Expr; +use super::field_expr::ComparisonExpr; +use super::parse::FilterParser; +use super::visitor::{Visitor, VisitorMut}; +use crate::compiler::Compiler; +use crate::filter::{CompiledExpr, CompiledOneExpr, CompiledVecExpr}; +use crate::lex::{Lex, LexErrorKind, LexResult, LexWith, expect, skip_space}; +use crate::types::{GetType, Type, TypeMismatchError}; use serde::Serialize; lex_enum!( @@ -326,15 +322,13 @@ impl Expr for LogicalExpr { #[allow(clippy::cognitive_complexity)] fn test() { use super::field_expr::ComparisonExpr; - use crate::{ - ast::field_expr::{ComparisonOpExpr, IdentifierExpr}, - ast::index_expr::IndexExpr, - execution_context::ExecutionContext, - lex::complete, - lhs_types::Array, - scheme::FieldIndex, - types::Type, - }; + use crate::ast::field_expr::{ComparisonOpExpr, IdentifierExpr}; + use crate::ast::index_expr::IndexExpr; + use crate::execution_context::ExecutionContext; + use crate::lex::complete; + use crate::lhs_types::Array; + use crate::scheme::FieldIndex; + use crate::types::Type; let scheme = &Scheme! { t: Bool, diff --git a/engine/src/ast/mod.rs b/engine/src/ast/mod.rs index 66323bb3..b158ea9a 100644 --- a/engine/src/ast/mod.rs +++ b/engine/src/ast/mod.rs @@ -8,16 +8,14 @@ pub mod visitor; use self::index_expr::IndexExpr; use self::logical_expr::LogicalExpr; use self::parse::FilterParser; -use crate::{ - compiler::{Compiler, DefaultCompiler}, - filter::{CompiledExpr, CompiledValueExpr, Filter, FilterValue}, - lex::{LexErrorKind, LexResult, LexWith}, - scheme::{Scheme, UnknownFieldError}, - types::{GetType, Type, TypeMismatchError}, -}; +use self::visitor::{UsesListVisitor, UsesVisitor, Visitor, VisitorMut}; +use crate::compiler::{Compiler, DefaultCompiler}; +use crate::filter::{CompiledExpr, CompiledValueExpr, Filter, FilterValue}; +use crate::lex::{LexErrorKind, LexResult, LexWith}; +use crate::scheme::{Scheme, UnknownFieldError}; +use crate::types::{GetType, Type, TypeMismatchError}; use serde::Serialize; use std::fmt::{self, Debug}; -use visitor::{UsesListVisitor, UsesVisitor, Visitor, VisitorMut}; /// Trait used to represent node that evaluates to a [`bool`] (or a [`Vec`]). pub trait Expr: diff --git a/engine/src/ast/parse.rs b/engine/src/ast/parse.rs index e9984294..562703d5 100644 --- a/engine/src/ast/parse.rs +++ b/engine/src/ast/parse.rs @@ -1,8 +1,6 @@ use super::{FilterAst, FilterValueAst}; -use crate::{ - lex::{LexErrorKind, LexResult, LexWith, complete}, - scheme::Scheme, -}; +use crate::lex::{LexErrorKind, LexResult, LexWith, complete}; +use crate::scheme::Scheme; use std::cmp::{max, min}; use std::error::Error; use std::fmt::{self, Debug, Display, Formatter}; diff --git a/engine/src/ast/visitor.rs b/engine/src/ast/visitor.rs index ddcbfb81..ad5ca796 100644 --- a/engine/src/ast/visitor.rs +++ b/engine/src/ast/visitor.rs @@ -1,10 +1,8 @@ -use super::{ - Expr, ValueExpr, - field_expr::{ComparisonExpr, ComparisonOpExpr}, - function_expr::{FunctionCallArgExpr, FunctionCallExpr}, - index_expr::IndexExpr, - logical_expr::LogicalExpr, -}; +use super::field_expr::{ComparisonExpr, ComparisonOpExpr}; +use super::function_expr::{FunctionCallArgExpr, FunctionCallExpr}; +use super::index_expr::IndexExpr; +use super::logical_expr::LogicalExpr; +use super::{Expr, ValueExpr}; use crate::{Field, FieldRef, Function}; /// Trait used to immutably visit all nodes in the AST. diff --git a/engine/src/execution_context.rs b/engine/src/execution_context.rs index 26b4c86d..58b0e8ce 100644 --- a/engine/src/execution_context.rs +++ b/engine/src/execution_context.rs @@ -1,8 +1,6 @@ -use crate::{ - FieldRef, ListMatcher, ListRef, UnknownFieldError, - scheme::{Field, List, Scheme, SchemeMismatchError}, - types::{GetType, LhsValue, LhsValueSeed, Type, TypeMismatchError}, -}; +use crate::scheme::{Field, List, Scheme, SchemeMismatchError}; +use crate::types::{GetType, LhsValue, LhsValueSeed, Type, TypeMismatchError}; +use crate::{FieldRef, ListMatcher, ListRef, UnknownFieldError}; use serde::Serialize; use serde::de::{self, DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor}; use serde::ser::{SerializeMap, SerializeSeq, Serializer}; diff --git a/engine/src/filter.rs b/engine/src/filter.rs index db9b1803..510672cf 100644 --- a/engine/src/filter.rs +++ b/engine/src/filter.rs @@ -5,12 +5,10 @@ //! their `execute` methods and aggregating results into a single boolean value //! as recursion unwinds. -use crate::{ - execution_context::ExecutionContext, - lhs_types::TypedArray, - scheme::{Scheme, SchemeMismatchError}, - types::{LhsValue, Type}, -}; +use crate::execution_context::ExecutionContext; +use crate::lhs_types::TypedArray; +use crate::scheme::{Scheme, SchemeMismatchError}; +use crate::types::{LhsValue, Type}; use std::fmt; type BoxedClosureToOneBool = diff --git a/engine/src/functions/mod.rs b/engine/src/functions/mod.rs index 10e497de..5129791a 100644 --- a/engine/src/functions/mod.rs +++ b/engine/src/functions/mod.rs @@ -2,14 +2,14 @@ pub(crate) mod all; pub(crate) mod any; pub(crate) mod concat; -use crate::{ - ParserSettings, - filter::CompiledValueResult, - types::{ExpectedType, ExpectedTypeList, GetType, LhsValue, RhsValue, Type, TypeMismatchError}, +pub use self::all::AllFunction; +pub use self::any::AnyFunction; +pub use self::concat::ConcatFunction; +use crate::ParserSettings; +use crate::filter::CompiledValueResult; +use crate::types::{ + ExpectedType, ExpectedTypeList, GetType, LhsValue, RhsValue, Type, TypeMismatchError, }; -pub use all::AllFunction; -pub use any::AnyFunction; -pub use concat::ConcatFunction; use std::any::Any; use std::convert::TryFrom; use std::fmt::{self, Debug}; diff --git a/engine/src/lex.rs b/engine/src/lex.rs index ec5ab33a..4fcc5633 100644 --- a/engine/src/lex.rs +++ b/engine/src/lex.rs @@ -1,9 +1,7 @@ -use crate::{ - functions::{FunctionArgInvalidConstantError, FunctionArgKindMismatchError}, - rhs_types::{RegexError, WildcardError}, - scheme::{IndexAccessError, UnknownFieldError, UnknownFunctionError}, - types::{Type, TypeMismatchError}, -}; +use crate::functions::{FunctionArgInvalidConstantError, FunctionArgKindMismatchError}; +use crate::rhs_types::{RegexError, WildcardError}; +use crate::scheme::{IndexAccessError, UnknownFieldError, UnknownFunctionError}; +use crate::types::{Type, TypeMismatchError}; use cidr::errors::NetworkParseError; use std::num::ParseIntError; use thiserror::Error; diff --git a/engine/src/lhs_types/array.rs b/engine/src/lhs_types/array.rs index 0ecb00ad..b3620f00 100644 --- a/engine/src/lhs_types/array.rs +++ b/engine/src/lhs_types/array.rs @@ -1,19 +1,15 @@ -use crate::{ - lhs_types::AsRefIterator, - types::{CompoundType, GetType, IntoValue, LhsValue, LhsValueSeed, Type, TypeMismatchError}, +use super::TypedMap; +use super::map::InnerMap; +use crate::lhs_types::AsRefIterator; +use crate::types::{ + CompoundType, GetType, IntoValue, LhsValue, LhsValueSeed, Type, TypeMismatchError, }; -use serde::{ - Serialize, Serializer, - de::{self, DeserializeSeed, Deserializer, SeqAccess, Visitor}, - ser::SerializeSeq, -}; -use std::{ - fmt, - hash::{Hash, Hasher}, - hint::unreachable_unchecked, -}; - -use super::{TypedMap, map::InnerMap}; +use serde::de::{self, DeserializeSeed, Deserializer, SeqAccess, Visitor}; +use serde::ser::SerializeSeq; +use serde::{Serialize, Serializer}; +use std::fmt; +use std::hash::{Hash, Hasher}; +use std::hint::unreachable_unchecked; // Ideally, we would want to use Cow<'a, LhsValue<'a>> here // but it doesnt work for unknown reasons diff --git a/engine/src/lhs_types/map.rs b/engine/src/lhs_types/map.rs index 92b8d203..1a26b499 100644 --- a/engine/src/lhs_types/map.rs +++ b/engine/src/lhs_types/map.rs @@ -1,21 +1,15 @@ -use crate::{ - TypeMismatchError, - lhs_types::{AsRefIterator, Bytes}, - types::{CompoundType, GetType, IntoValue, LhsValue, LhsValueSeed, Type}, -}; -use serde::{ - Serialize, Serializer, - de::{self, DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor}, - ser::{SerializeMap, SerializeSeq}, -}; -use std::{ - borrow::Cow, - collections::BTreeMap, - fmt, - hash::{Hash, Hasher}, -}; - -use super::{TypedArray, array::InnerArray}; +use super::TypedArray; +use super::array::InnerArray; +use crate::TypeMismatchError; +use crate::lhs_types::{AsRefIterator, Bytes}; +use crate::types::{CompoundType, GetType, IntoValue, LhsValue, LhsValueSeed, Type}; +use serde::de::{self, DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor}; +use serde::ser::{SerializeMap, SerializeSeq}; +use serde::{Serialize, Serializer}; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::fmt; +use std::hash::{Hash, Hasher}; #[derive(Debug, Clone)] pub(crate) enum InnerMap<'a> { diff --git a/engine/src/lhs_types/mod.rs b/engine/src/lhs_types/mod.rs index 170e2d41..2f4c6c3b 100644 --- a/engine/src/lhs_types/mod.rs +++ b/engine/src/lhs_types/mod.rs @@ -2,14 +2,11 @@ mod array; mod bytes; mod map; +pub use self::array::{Array, ArrayIntoIter, ArrayIter, TypedArray}; +pub use self::bytes::Bytes; +pub use self::map::{Map, MapIter, MapValuesIntoIter, TypedMap}; use crate::types::LhsValue; -pub use self::{ - array::{Array, ArrayIntoIter, ArrayIter, TypedArray}, - bytes::Bytes, - map::{Map, MapIter, MapValuesIntoIter, TypedMap}, -}; - pub struct AsRefIterator<'a, T: Iterator>>(T); impl<'a, T: Iterator>> AsRefIterator<'a, T> { diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 839e6c29..e9953d1d 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -79,49 +79,47 @@ mod searcher; mod strict_partial_ord; mod types; -pub use self::{ - ast::{ - Expr, FilterAst, FilterValueAst, ValueExpr, - field_expr::{ComparisonExpr, ComparisonOpExpr, IdentifierExpr, IntOp, OrderingOp}, - function_expr::{FunctionCallArgExpr, FunctionCallExpr}, - index_expr::{Compare, IndexExpr}, - logical_expr::{LogicalExpr, LogicalOp, ParenthesizedExpr, UnaryOp}, - parse::{FilterParser, ParseError, ParserSettings}, - visitor::{Visitor, VisitorMut}, - }, - compiler::{Compiler, DefaultCompiler}, - execution_context::{ - ExecutionContext, ExecutionContextGuard, InvalidListMatcherError, SetFieldValueError, - }, - filter::{ - CompiledExpr, CompiledOneExpr, CompiledValueExpr, CompiledVecExpr, Filter, FilterValue, - }, - functions::{ - AllFunction, AnyFunction, ConcatFunction, FunctionArgInvalidConstantError, FunctionArgKind, - FunctionArgKindMismatchError, FunctionArgs, FunctionDefinition, FunctionDefinitionContext, - FunctionParam, FunctionParamError, SimpleFunctionArgKind, SimpleFunctionDefinition, - SimpleFunctionImpl, SimpleFunctionOptParam, SimpleFunctionParam, - }, - lex::LexErrorKind, - lhs_types::{Array, Bytes, Map, MapIter, TypedArray, TypedMap}, - list_matcher::{ - AlwaysList, AlwaysListMatcher, ListDefinition, ListMatcher, NeverList, NeverListMatcher, - }, - panic::{ - PanicCatcherFallbackMode, catch_panic, panic_catcher_disable, panic_catcher_enable, - panic_catcher_get_backtrace, panic_catcher_set_fallback_mode, panic_catcher_set_hook, - }, - rhs_types::{ - BytesExpr, BytesFormat, ExplicitIpRange, IntRange, IpCidr, IpRange, Regex, RegexError, - RegexFormat, - }, - scheme::{ - Field, FieldIndex, FieldRedefinitionError, FieldRef, Function, FunctionRedefinitionError, - FunctionRef, IdentifierRedefinitionError, IndexAccessError, List, ListRef, Scheme, - SchemeBuilder, SchemeMismatchError, UnknownFieldError, - }, - types::{ - CompoundType, ExpectedType, ExpectedTypeList, GetType, LhsValue, RhsValue, RhsValues, Type, - TypeMismatchError, - }, +pub use self::ast::field_expr::{ + ComparisonExpr, ComparisonOpExpr, IdentifierExpr, IntOp, OrderingOp, +}; +pub use self::ast::function_expr::{FunctionCallArgExpr, FunctionCallExpr}; +pub use self::ast::index_expr::{Compare, IndexExpr}; +pub use self::ast::logical_expr::{LogicalExpr, LogicalOp, ParenthesizedExpr, UnaryOp}; +pub use self::ast::parse::{FilterParser, ParseError, ParserSettings}; +pub use self::ast::visitor::{Visitor, VisitorMut}; +pub use self::ast::{Expr, FilterAst, FilterValueAst, ValueExpr}; +pub use self::compiler::{Compiler, DefaultCompiler}; +pub use self::execution_context::{ + ExecutionContext, ExecutionContextGuard, InvalidListMatcherError, SetFieldValueError, +}; +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, +}; +pub use self::lex::LexErrorKind; +pub use self::lhs_types::{Array, Bytes, Map, MapIter, TypedArray, TypedMap}; +pub use self::list_matcher::{ + AlwaysList, AlwaysListMatcher, ListDefinition, ListMatcher, NeverList, NeverListMatcher, +}; +pub use self::panic::{ + PanicCatcherFallbackMode, catch_panic, panic_catcher_disable, panic_catcher_enable, + panic_catcher_get_backtrace, panic_catcher_set_fallback_mode, panic_catcher_set_hook, +}; +pub use self::rhs_types::{ + BytesExpr, BytesFormat, ExplicitIpRange, IntRange, IpCidr, IpRange, Regex, RegexError, + RegexFormat, +}; +pub use self::scheme::{ + Field, FieldIndex, FieldRedefinitionError, FieldRef, Function, FunctionRedefinitionError, + FunctionRef, IdentifierRedefinitionError, IndexAccessError, List, ListRef, Scheme, + SchemeBuilder, SchemeMismatchError, UnknownFieldError, +}; +pub use self::types::{ + CompoundType, ExpectedType, ExpectedTypeList, GetType, LhsValue, RhsValue, RhsValues, Type, + TypeMismatchError, }; diff --git a/engine/src/list_matcher.rs b/engine/src/list_matcher.rs index c8d38580..2de813ed 100644 --- a/engine/src/list_matcher.rs +++ b/engine/src/list_matcher.rs @@ -1,5 +1,4 @@ -use crate::LhsValue; -use crate::Type; +use crate::{LhsValue, Type}; use dyn_clone::DynClone; use serde::{Deserialize, Serialize}; use std::any::Any; diff --git a/engine/src/range_set.rs b/engine/src/range_set.rs index 69f0c967..e024f787 100644 --- a/engine/src/range_set.rs +++ b/engine/src/range_set.rs @@ -1,4 +1,7 @@ -use std::{borrow::Borrow, cmp::Ordering, iter::FromIterator, ops::RangeInclusive}; +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::iter::FromIterator; +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. diff --git a/engine/src/rhs_types/array.rs b/engine/src/rhs_types/array.rs index dee02abc..f3ef2771 100644 --- a/engine/src/rhs_types/array.rs +++ b/engine/src/rhs_types/array.rs @@ -1,11 +1,10 @@ -use crate::{ - lex::{Lex, LexResult}, - lhs_types::Array, - strict_partial_ord::StrictPartialOrd, - types::{GetType, Type}, -}; +use crate::lex::{Lex, LexResult}; +use crate::lhs_types::Array; +use crate::strict_partial_ord::StrictPartialOrd; +use crate::types::{GetType, Type}; use serde::Serialize; -use std::{borrow::Borrow, cmp::Ordering}; +use std::borrow::Borrow; +use std::cmp::Ordering; /// [Uninhabited / empty type](https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types) /// for `array` with traits we need for RHS values. diff --git a/engine/src/rhs_types/bool.rs b/engine/src/rhs_types/bool.rs index 0c549014..e44b4211 100644 --- a/engine/src/rhs_types/bool.rs +++ b/engine/src/rhs_types/bool.rs @@ -1,9 +1,8 @@ -use crate::{ - lex::{Lex, LexResult}, - strict_partial_ord::StrictPartialOrd, -}; +use crate::lex::{Lex, LexResult}; +use crate::strict_partial_ord::StrictPartialOrd; use serde::Serialize; -use std::{borrow::Borrow, cmp::Ordering}; +use std::borrow::Borrow; +use std::cmp::Ordering; /// [Uninhabited / empty type](https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types) /// for `bool` with traits we need for RHS values. diff --git a/engine/src/rhs_types/bytes.rs b/engine/src/rhs_types/bytes.rs index f37ad943..45e51b59 100644 --- a/engine/src/rhs_types/bytes.rs +++ b/engine/src/rhs_types/bytes.rs @@ -1,14 +1,10 @@ -use crate::{ - lex::{Lex, LexErrorKind, LexResult, take}, - strict_partial_ord::StrictPartialOrd, -}; +use crate::lex::{Lex, LexErrorKind, LexResult, take}; +use crate::strict_partial_ord::StrictPartialOrd; use serde::{Serialize, Serializer}; -use std::{ - fmt::{self, Debug, Formatter}, - hash::{Hash, Hasher}, - ops::Deref, - str, -}; +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; +use std::ops::Deref; +use std::str; /// BytesFormat describes the format in which the string was expressed #[derive(PartialEq, Eq, Copy, Clone)] diff --git a/engine/src/rhs_types/int.rs b/engine/src/rhs_types/int.rs index 5021f61a..4643090c 100644 --- a/engine/src/rhs_types/int.rs +++ b/engine/src/rhs_types/int.rs @@ -1,7 +1,5 @@ -use crate::{ - lex::{Lex, LexErrorKind, LexResult, expect, span, take_while}, - strict_partial_ord::StrictPartialOrd, -}; +use crate::lex::{Lex, LexErrorKind, LexResult, expect, span, take_while}; +use crate::strict_partial_ord::StrictPartialOrd; use serde::Serialize; use std::ops::RangeInclusive; diff --git a/engine/src/rhs_types/ip.rs b/engine/src/rhs_types/ip.rs index a5526d76..b1597958 100644 --- a/engine/src/rhs_types/ip.rs +++ b/engine/src/rhs_types/ip.rs @@ -1,17 +1,13 @@ +use crate::lex::{Lex, LexError, LexErrorKind, LexResult, take_while}; +use crate::strict_partial_ord::StrictPartialOrd; pub use cidr::IpCidr; - -use crate::{ - lex::{Lex, LexError, LexErrorKind, LexResult, take_while}, - strict_partial_ord::StrictPartialOrd, -}; -use cidr::{Ipv4Cidr, Ipv6Cidr, errors::NetworkParseError}; +use cidr::errors::NetworkParseError; +use cidr::{Ipv4Cidr, Ipv6Cidr}; use serde::Serialize; -use std::{ - cmp::Ordering, - net::{IpAddr, Ipv4Addr, Ipv6Addr}, - ops::RangeInclusive, - str::FromStr, -}; +use std::cmp::Ordering; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::ops::RangeInclusive; +use std::str::FromStr; fn match_addr_or_cidr(input: &str) -> LexResult<'_, &str> { take_while( diff --git a/engine/src/rhs_types/map.rs b/engine/src/rhs_types/map.rs index 004fb0d5..72baa80b 100644 --- a/engine/src/rhs_types/map.rs +++ b/engine/src/rhs_types/map.rs @@ -1,11 +1,10 @@ -use crate::{ - lex::{Lex, LexResult}, - lhs_types::Map, - strict_partial_ord::StrictPartialOrd, - types::{GetType, Type}, -}; +use crate::lex::{Lex, LexResult}; +use crate::lhs_types::Map; +use crate::strict_partial_ord::StrictPartialOrd; +use crate::types::{GetType, Type}; use serde::Serialize; -use std::{borrow::Borrow, cmp::Ordering}; +use std::borrow::Borrow; +use std::cmp::Ordering; /// [Uninhabited / empty type](https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types) /// for `map` with traits we need for RHS values. diff --git a/engine/src/rhs_types/mod.rs b/engine/src/rhs_types/mod.rs index ac3801cd..78e8756d 100644 --- a/engine/src/rhs_types/mod.rs +++ b/engine/src/rhs_types/mod.rs @@ -8,14 +8,12 @@ mod map; mod regex; mod wildcard; -pub use self::{ - array::UninhabitedArray, - bool::UninhabitedBool, - bytes::{BytesExpr, BytesFormat}, - int::IntRange, - ip::{ExplicitIpRange, IpCidr, IpRange}, - list::ListName, - map::UninhabitedMap, - regex::{Error as RegexError, Regex, RegexFormat}, - wildcard::{Wildcard, WildcardError}, -}; +pub use self::array::UninhabitedArray; +pub use self::bool::UninhabitedBool; +pub use self::bytes::{BytesExpr, BytesFormat}; +pub use self::int::IntRange; +pub use self::ip::{ExplicitIpRange, IpCidr, IpRange}; +pub use self::list::ListName; +pub use self::map::UninhabitedMap; +pub use self::regex::{Error as RegexError, Regex, RegexFormat}; +pub use self::wildcard::{Wildcard, WildcardError}; diff --git a/engine/src/rhs_types/regex/imp_real.rs b/engine/src/rhs_types/regex/imp_real.rs index 2b5a6480..4425ccbd 100644 --- a/engine/src/rhs_types/regex/imp_real.rs +++ b/engine/src/rhs_types/regex/imp_real.rs @@ -1,8 +1,7 @@ -use regex_automata::MatchKind; -use regex_automata::nfa::thompson::WhichCaptures; - use super::Error; use crate::{ParserSettings, RegexFormat}; +use regex_automata::MatchKind; +use regex_automata::nfa::thompson::WhichCaptures; use std::ops::Deref; use std::sync::Arc; diff --git a/engine/src/rhs_types/regex/imp_stub.rs b/engine/src/rhs_types/regex/imp_stub.rs index 0f5a1081..00e03d0f 100644 --- a/engine/src/rhs_types/regex/imp_stub.rs +++ b/engine/src/rhs_types/regex/imp_stub.rs @@ -1,6 +1,5 @@ -use thiserror::Error; - use crate::{FilterParser, RegexFormat}; +use thiserror::Error; /// Dummy regex error. #[derive(Debug, PartialEq, Error)] diff --git a/engine/src/rhs_types/wildcard.rs b/engine/src/rhs_types/wildcard.rs index 068e50f6..d0db6827 100644 --- a/engine/src/rhs_types/wildcard.rs +++ b/engine/src/rhs_types/wildcard.rs @@ -2,10 +2,8 @@ use crate::lex::{LexResult, LexWith}; use crate::rhs_types::bytes::{BytesExpr, lex_quoted_or_raw_string}; use crate::{FilterParser, LexErrorKind}; use serde::{Serialize, Serializer}; -use std::{ - fmt::{self, Debug, Formatter}, - hash::{Hash, Hasher}, -}; +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; use thiserror::Error; use wildcard::WildcardToken; diff --git a/engine/src/scheme.rs b/engine/src/scheme.rs index 57031911..db21743f 100644 --- a/engine/src/scheme.rs +++ b/engine/src/scheme.rs @@ -1,26 +1,20 @@ -use crate::{ - ast::{ - FilterAst, FilterValueAst, - parse::{FilterParser, ParseError, ParserSettings}, - }, - functions::FunctionDefinition, - lex::{Lex, LexErrorKind, LexResult, LexWith, expect, span, take_while}, - list_matcher::ListDefinition, - types::{GetType, RhsValue, Type}, -}; +use crate::ast::parse::{FilterParser, ParseError, ParserSettings}; +use crate::ast::{FilterAst, FilterValueAst}; +use crate::functions::FunctionDefinition; +use crate::lex::{Lex, LexErrorKind, LexResult, LexWith, expect, span, take_while}; +use crate::list_matcher::ListDefinition; +use crate::types::{GetType, RhsValue, Type}; use fnv::FnvBuildHasher; use serde::de::Visitor; use serde::ser::SerializeMap; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::collections::HashMap; use std::collections::hash_map::Entry; +use std::convert::TryFrom; +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; +use std::iter::Iterator; use std::sync::Arc; -use std::{ - collections::HashMap, - convert::TryFrom, - fmt::{self, Debug, Formatter}, - hash::{Hash, Hasher}, - iter::Iterator, -}; use thiserror::Error; /// An error that occurs if two underlying [schemes](struct@Scheme) @@ -1270,7 +1264,8 @@ fn test_parse_error() { fn test_parse_error_in_op() { use cidr::errors::NetworkParseError; use indoc::indoc; - use std::{net::IpAddr, str::FromStr}; + use std::net::IpAddr; + use std::str::FromStr; let scheme = &Scheme! { num: Int, diff --git a/engine/src/searcher.rs b/engine/src/searcher.rs index 403faf94..23846c71 100644 --- a/engine/src/searcher.rs +++ b/engine/src/searcher.rs @@ -1,8 +1,7 @@ +use crate::{Compare, ExecutionContext, LhsValue}; use memchr::memmem::{Finder, FinderBuilder}; use sliceslice::MemchrSearcher; -use crate::{Compare, ExecutionContext, LhsValue}; - pub struct EmptySearcher; impl Compare for EmptySearcher { diff --git a/engine/src/types.rs b/engine/src/types.rs index 5d49e1d6..d6466481 100644 --- a/engine/src/types.rs +++ b/engine/src/types.rs @@ -1,20 +1,18 @@ -use crate::{ - lex::{Lex, LexResult, LexWith, expect, skip_space}, - lhs_types::{Array, ArrayIntoIter, ArrayIter, Bytes, Map, MapIter, MapValuesIntoIter}, - rhs_types::{BytesExpr, IntRange, IpRange, UninhabitedArray, UninhabitedBool, UninhabitedMap}, - scheme::{FieldIndex, IndexAccessError}, - strict_partial_ord::StrictPartialOrd, +use crate::lex::{Lex, LexResult, LexWith, expect, skip_space}; +use crate::lhs_types::{Array, ArrayIntoIter, ArrayIter, Bytes, Map, MapIter, MapValuesIntoIter}; +use crate::rhs_types::{ + BytesExpr, IntRange, IpRange, UninhabitedArray, UninhabitedBool, UninhabitedMap, }; +use crate::scheme::{FieldIndex, IndexAccessError}; +use crate::strict_partial_ord::StrictPartialOrd; use serde::de::{DeserializeSeed, Deserializer}; use serde::{Deserialize, Serialize, Serializer}; -use std::{ - cmp::Ordering, - collections::BTreeSet, - convert::TryFrom, - fmt::{self, Debug, Formatter}, - iter::once, - net::{IpAddr, Ipv4Addr, Ipv6Addr}, -}; +use std::cmp::Ordering; +use std::collections::BTreeSet; +use std::convert::TryFrom; +use std::fmt::{self, Debug, Formatter}; +use std::iter::once; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use thiserror::Error; fn lex_rhs_values<'i, T: Lex<'i>>(input: &'i str) -> LexResult<'i, Vec> { diff --git a/ffi/src/cstring.rs b/ffi/src/cstring.rs index 8fa16d0c..ddb18ab3 100644 --- a/ffi/src/cstring.rs +++ b/ffi/src/cstring.rs @@ -1,8 +1,6 @@ -use std::{ - fmt::{self, Debug}, - io, - os::raw::c_char, -}; +use std::fmt::{self, Debug}; +use std::io; +use std::os::raw::c_char; /// Used for replacing null bytes in C strings that cannot contain null bytes. const SUBSTITUTE_BYTE: u8 = 0x1a; diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index 479d93a9..7fe3ecbb 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -10,13 +10,11 @@ use libc::c_char; use num_enum::{IntoPrimitive, TryFromPrimitive}; use serde::de::DeserializeSeed; use std::cell::RefCell; +use std::convert::TryFrom; +use std::hash::Hasher; +use std::io::{self, Write}; +use std::net::IpAddr; use std::ops::{Deref, DerefMut}; -use std::{ - convert::TryFrom, - hash::Hasher, - io::{self, Write}, - net::IpAddr, -}; use wirefilter::{AlwaysList, GetType, NeverList, Type, catch_panic}; const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/fuzz/map-keys/src/main.rs b/fuzz/map-keys/src/main.rs index a30d399c..80b2c36b 100644 --- a/fuzz/map-keys/src/main.rs +++ b/fuzz/map-keys/src/main.rs @@ -1,5 +1,4 @@ use std::sync::LazyLock; - use wirefilter::{ FunctionArgs, LhsValue, SimpleFunctionArgKind, SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionParam, Type, From 84faf1ff2273166c2d9113e2494c950c7a3ca7b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Apr 2026 03:33:03 +0000 Subject: [PATCH 29/30] Bump rand from 0.9.2 to 0.9.3 Bumps [rand](https://github.com/rust-random/rand) from 0.9.2 to 0.9.3. - [Release notes](https://github.com/rust-random/rand/releases) - [Changelog](https://github.com/rust-random/rand/blob/0.9.3/CHANGELOG.md) - [Commits](https://github.com/rust-random/rand/compare/rand_core-0.9.2...0.9.3) --- updated-dependencies: - dependency-name: rand dependency-version: 0.9.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f69bb03c..d0a2450a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -732,9 +732,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core", diff --git a/Cargo.toml b/Cargo.toml index 655019b7..2f4fffcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ js-sys = "0.3.85" libc = "0.2.182" memchr = "2.8.0" num_enum = "0.7.5" -rand = "0.9.2" +rand = "0.9.3" regex-automata = "0.4.14" serde = { version = "1.0.228", features = ["derive"] } serde_json = "1.0.149" From 21b3103d68a8eb566da8f1532bbe78d9326b394f Mon Sep 17 00:00:00 2001 From: Hrushikesh Deshpande Date: Thu, 23 Apr 2026 18:30:55 -0400 Subject: [PATCH 30/30] ci: add Semgrep OSS scanning workflow --- .github/workflows/semgrep.yml | 40 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index 4090692f..62b7ccdd 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -1,24 +1,30 @@ +name: Semgrep OSS scan on: pull_request: {} + push: + branches: [main, master] workflow_dispatch: {} - push: - branches: - - main - - master schedule: - - cron: '0 0 * * *' -name: Semgrep config + - cron: '0 0 20 * *' +concurrency: + group: semgrep-${{ github.event_name }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +permissions: + contents: read jobs: semgrep: - name: semgrep/ci - runs-on: ubuntu-latest - env: - SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }} - SEMGREP_URL: https://cloudflare.semgrep.dev - SEMGREP_APP_URL: https://cloudflare.semgrep.dev - SEMGREP_VERSION_CHECK_URL: https://cloudflare.semgrep.dev/api/check-version - container: - image: semgrep/semgrep + name: semgrep-oss + runs-on: ubuntu-slim steps: - - uses: actions/checkout@v4 - - run: semgrep ci + - uses: actions/checkout@v5 + with: + fetch-depth: 1 + - id: cache-semgrep + uses: actions/cache@v5 + with: + path: ~/.local + key: semgrep-1.160.0-${{ runner.os }} + - if: steps.cache-semgrep.outputs.cache-hit != 'true' + run: pip install --user semgrep==1.160.0 + - run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" + - run: semgrep scan --config=auto