From eb7411d176d057390267f17bbfe9df1400a40d01 Mon Sep 17 00:00:00 2001 From: Elie ROUDNINSKI Date: Tue, 18 Mar 2025 22:03:25 +0100 Subject: [PATCH] Introduce `SchemeBuilder` to build a `Scheme` This makes the scheme immutable and allows to tailor its internals for parsing and execution of filter expressions. --- engine/benches/bench.rs | 23 +-- engine/examples/cli.rs | 6 +- engine/src/ast/field_expr.rs | 18 +-- engine/src/ast/function_expr.rs | 14 +- engine/src/ast/index_expr.rs | 18 +-- engine/src/ast/logical_expr.rs | 3 +- engine/src/ast/visitor.rs | 8 +- engine/src/execution_context.rs | 41 +++-- engine/src/filter.rs | 4 +- engine/src/lib.rs | 6 +- engine/src/rhs_types/regex/mod.rs | 6 +- engine/src/rhs_types/wildcard.rs | 16 +- engine/src/scheme.rs | 250 ++++++++++++++++-------------- ffi/cbindgen.toml | 1 + ffi/include/wirefilter.h | 14 +- ffi/src/lib.rs | 62 +++++--- ffi/tests/ctests/src/lib.rs | 2 +- ffi/tests/ctests/src/tests.c | 117 ++++++-------- 18 files changed, 319 insertions(+), 290 deletions(-) diff --git a/engine/benches/bench.rs b/engine/benches/bench.rs index a4edeb4f..b2626551 100644 --- a/engine/benches/bench.rs +++ b/engine/benches/bench.rs @@ -8,7 +8,7 @@ static A: System = System; use criterion::{criterion_group, criterion_main, Bencher, Criterion}; use std::{borrow::Cow, clone::Clone, fmt::Debug, net::IpAddr}; use wirefilter::{ - ExecutionContext, FilterAst, FunctionArgKind, FunctionArgs, GetType, LhsValue, Scheme, + ExecutionContext, FilterAst, FunctionArgKind, FunctionArgs, GetType, LhsValue, SchemeBuilder, SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionParam, Type, }; @@ -79,11 +79,12 @@ impl>> FieldBench<'_, T> { let mut group = c.benchmark_group("parsing"); group.bench_function(name, { - let mut scheme = Scheme::default(); - scheme.add_field(field, ty).unwrap(); + let mut builder = SchemeBuilder::default(); + builder.add_field(field, ty).unwrap(); for (name, function) in functions { - scheme.add_function(name, function.clone()).unwrap(); + builder.add_function(name, function.clone()).unwrap(); } + let scheme = builder.build(); move |b: &mut Bencher| { b.iter(|| scheme.parse(filter).unwrap()); } @@ -94,11 +95,12 @@ impl>> FieldBench<'_, T> { let mut group = c.benchmark_group("compilation"); group.bench_function(name, { - let mut scheme = Scheme::default(); - scheme.add_field(field, ty).unwrap(); + let mut builder = SchemeBuilder::default(); + builder.add_field(field, ty).unwrap(); for (name, function) in functions { - scheme.add_function(name, function.clone()).unwrap(); + builder.add_function(name, function.clone()).unwrap(); } + let scheme = builder.build(); move |b: &mut Bencher| { let filter = scheme.parse(filter).unwrap(); @@ -111,11 +113,12 @@ impl>> FieldBench<'_, T> { let mut group = c.benchmark_group("execution"); group.bench_with_input(name, values, { - let mut scheme = Scheme::default(); - scheme.add_field(field, ty).unwrap(); + let mut builder = SchemeBuilder::default(); + builder.add_field(field, ty).unwrap(); for (name, function) in functions { - scheme.add_function(name, function.clone()).unwrap(); + builder.add_function(name, function.clone()).unwrap(); } + let scheme = builder.build(); move |b: &mut Bencher, values: &[T]| { let filter = scheme.parse(filter).unwrap(); diff --git a/engine/examples/cli.rs b/engine/examples/cli.rs index 2264bd1a..f15ad248 100644 --- a/engine/examples/cli.rs +++ b/engine/examples/cli.rs @@ -13,7 +13,7 @@ fn main() { .nth(1) .expect("Expected an input as a command-line argument"); - let mut scheme = Scheme! { + let mut builder = Scheme! { ip: Ip, str: Bytes, int: Int, @@ -23,7 +23,7 @@ fn main() { bool_arr: Array(Bool), }; - scheme + builder .add_function( "panic", SimpleFunctionDefinition { @@ -41,6 +41,8 @@ fn main() { ) .unwrap(); + let scheme = builder.build(); + match scheme.parse(&filter) { Ok(res) => println!("{res:#?}"), Err(err) => println!("{err}"), diff --git a/engine/src/ast/field_expr.rs b/engine/src/ast/field_expr.rs index 990e4d90..0840d3ab 100644 --- a/engine/src/ast/field_expr.rs +++ b/engine/src/ast/field_expr.rs @@ -805,7 +805,7 @@ mod tests { } static SCHEME: LazyLock = LazyLock::new(|| { - let mut scheme: Scheme = Scheme! { + let mut builder = Scheme! { http.cookies: Array(Bytes), http.headers: Map(Bytes), http.host: Bytes, @@ -816,7 +816,7 @@ mod tests { array.of.bool: Array(Bool), http.parts: Array(Array(Bytes)), }; - scheme + builder .add_function( "any", SimpleFunctionDefinition { @@ -830,7 +830,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "echo", SimpleFunctionDefinition { @@ -844,7 +844,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "lowercase", SimpleFunctionDefinition { @@ -858,7 +858,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "concat", SimpleFunctionDefinition { @@ -878,10 +878,10 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function("filter", FilterFunction::new()) .unwrap(); - scheme + builder .add_function( "len", SimpleFunctionDefinition { @@ -895,10 +895,10 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_list(Type::Int, Box::new(NumMListDefinition {})) .unwrap(); - scheme + builder.build() }); fn field(name: &'static str) -> Field<'static> { diff --git a/engine/src/ast/function_expr.rs b/engine/src/ast/function_expr.rs index 0bc4a6d0..fdf3b97a 100644 --- a/engine/src/ast/function_expr.rs +++ b/engine/src/ast/function_expr.rs @@ -592,7 +592,7 @@ mod tests { } static SCHEME: LazyLock = LazyLock::new(|| { - let mut scheme = Scheme! { + let mut builder = Scheme! { http.headers: Map(Bytes), http.host: Bytes, http.request.headers.names: Array(Bytes), @@ -602,7 +602,7 @@ mod tests { ssl: Bool, tcp.port: Int, }; - scheme + builder .add_function( "any", SimpleFunctionDefinition { @@ -616,7 +616,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "echo", SimpleFunctionDefinition { @@ -639,7 +639,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "lower", SimpleFunctionDefinition { @@ -653,7 +653,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "regex_replace", SimpleFunctionDefinition { @@ -677,7 +677,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "len", SimpleFunctionDefinition { @@ -691,7 +691,7 @@ mod tests { }, ) .unwrap(); - scheme + builder.build() }); #[test] diff --git a/engine/src/ast/index_expr.rs b/engine/src/ast/index_expr.rs index d5eb1470..cbf64fc8 100644 --- a/engine/src/ast/index_expr.rs +++ b/engine/src/ast/index_expr.rs @@ -548,8 +548,8 @@ mod tests { use super::*; use crate::{ ast::field_expr::IdentifierExpr, Array, FieldIndex, FilterParser, FunctionArgKind, - FunctionArgs, FunctionCallArgExpr, FunctionCallExpr, Scheme, SimpleFunctionDefinition, - SimpleFunctionImpl, SimpleFunctionParam, + FunctionArgs, FunctionCallArgExpr, FunctionCallExpr, Scheme, SchemeBuilder, + SimpleFunctionDefinition, SimpleFunctionImpl, SimpleFunctionParam, }; use std::sync::LazyLock; @@ -574,17 +574,17 @@ mod tests { } static SCHEME: LazyLock = LazyLock::new(|| { - let mut scheme = Scheme::new(); - scheme + let mut builder = SchemeBuilder::new(); + builder .add_field("test", Type::Array(Type::Bytes.into())) .unwrap(); - scheme + builder .add_field("test2", Type::Array(Type::Array(Type::Bytes.into()).into())) .unwrap(); - scheme + builder .add_field("map", Type::Map(Type::Bytes.into())) .unwrap(); - scheme + builder .add_function( "array", SimpleFunctionDefinition { @@ -598,7 +598,7 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_function( "array2", SimpleFunctionDefinition { @@ -612,7 +612,7 @@ mod tests { }, ) .unwrap(); - scheme + builder.build() }); #[test] diff --git a/engine/src/ast/logical_expr.rs b/engine/src/ast/logical_expr.rs index 8b43effa..d03daf5f 100644 --- a/engine/src/ast/logical_expr.rs +++ b/engine/src/ast/logical_expr.rs @@ -345,7 +345,8 @@ fn test() { at: Array(Bool), af: Array(Bool), aat: Array(Array(Bool)), - }; + } + .build(); let ctx = &mut ExecutionContext::new(scheme); diff --git a/engine/src/ast/visitor.rs b/engine/src/ast/visitor.rs index c9b9d6a9..c9cd51cf 100644 --- a/engine/src/ast/visitor.rs +++ b/engine/src/ast/visitor.rs @@ -225,7 +225,7 @@ mod tests { use std::sync::LazyLock; static SCHEME: LazyLock = LazyLock::new(|| { - let mut scheme = Scheme! { + let mut builder = Scheme! { http.headers: Map(Bytes), http.request.headers.names: Array(Bytes), http.request.headers.values: Array(Bytes), @@ -234,7 +234,7 @@ mod tests { ssl: Bool, tcp.port: Int, }; - scheme + builder .add_function( "echo", SimpleFunctionDefinition { @@ -248,10 +248,10 @@ mod tests { }, ) .unwrap(); - scheme + builder .add_list(Type::Bytes, Box::new(AlwaysList {})) .unwrap(); - scheme + builder.build() }); #[test] diff --git a/engine/src/execution_context.rs b/engine/src/execution_context.rs index 4bec4ae6..a47ab632 100644 --- a/engine/src/execution_context.rs +++ b/engine/src/execution_context.rs @@ -355,7 +355,7 @@ impl Serialize for ExecutionContext<'_> { fn test_field_value_type_mismatch() { use crate::types::Type; - let scheme = Scheme! { foo: Int }; + let scheme = Scheme! { foo: Int }.build(); let mut ctx = ExecutionContext::<()>::new(&scheme); @@ -370,11 +370,11 @@ fn test_field_value_type_mismatch() { #[test] fn test_scheme_mismatch() { - let scheme = Scheme! { foo: Bool }; + let scheme = Scheme! { foo: Bool }.build(); let mut ctx = ExecutionContext::<()>::new(&scheme); - let scheme2 = Scheme! { foo: Bool }; + let scheme2 = Scheme! { foo: Bool }.build(); assert_eq!( ctx.set_field_value(scheme2.get_field("foo").unwrap(), LhsValue::Bool(false)), @@ -391,20 +391,18 @@ fn test_serde() { use std::net::IpAddr; use std::str::FromStr; - let mut scheme = Scheme::new(); - scheme.add_field("bool", Type::Bool).unwrap(); - scheme.add_field("ip", Type::Ip).unwrap(); - scheme.add_field("str", Type::Bytes).unwrap(); - scheme.add_field("bytes", Type::Bytes).unwrap(); - scheme.add_field("num", Type::Int).unwrap(); - scheme.add_field("min_num", Type::Int).unwrap(); - scheme.add_field("max_num", Type::Int).unwrap(); - scheme - .add_field("arr", Type::Array(Type::Bool.into())) - .unwrap(); - scheme - .add_field("map", Type::Map(Type::Int.into())) - .unwrap(); + let scheme = Scheme! { + bool: Bool, + ip: Ip, + str: Bytes, + bytes: Bytes, + num: Int, + min_num: Int, + max_num: Int, + arr: Array(Bool), + map: Map(Int), + } + .build(); let mut ctx = ExecutionContext::new(&scheme); @@ -550,13 +548,14 @@ fn test_serde() { #[test] fn test_clear() { - use crate::types::Type; use std::net::IpAddr; use std::str::FromStr; - let mut scheme = Scheme::new(); - scheme.add_field("bool", Type::Bool).unwrap(); - scheme.add_field("ip", Type::Ip).unwrap(); + let scheme = Scheme! { + bool: Bool, + ip: Ip, + } + .build(); let bool_field = scheme.get_field("bool").unwrap(); let ip_field = scheme.get_field("ip").unwrap(); diff --git a/engine/src/filter.rs b/engine/src/filter.rs index dd87a0f6..736bf778 100644 --- a/engine/src/filter.rs +++ b/engine/src/filter.rs @@ -244,8 +244,8 @@ mod tests { #[test] fn test_scheme_mismatch() { - let scheme1 = Scheme! { foo: Int }; - let scheme2 = Scheme! { foo: Int, bar: Int }; + let scheme1 = Scheme! { foo: Int }.build(); + let scheme2 = Scheme! { foo: Int, bar: Int }.build(); let filter = scheme1.parse("foo == 42").unwrap().compile(); let ctx = ExecutionContext::new(&scheme2); diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 346c095a..d9109654 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -14,7 +14,7 @@ //! http.method: Bytes, //! http.ua: Bytes, //! port: Int, -//! }; +//! }.build(); //! //! // Parse a Wireshark-like expression into an AST. //! let ast = scheme.parse( @@ -116,8 +116,8 @@ pub use self::{ }, scheme::{ Field, FieldIndex, FieldRedefinitionError, Function, FunctionRedefinitionError, Identifier, - IdentifierRedefinitionError, IndexAccessError, List, Scheme, SchemeMismatchError, - UnknownFieldError, + IdentifierRedefinitionError, IndexAccessError, List, Scheme, SchemeBuilder, + SchemeMismatchError, UnknownFieldError, }, types::{ CompoundType, ExpectedType, ExpectedTypeList, GetType, LhsValue, LhsValueMut, RhsValue, diff --git a/engine/src/rhs_types/regex/mod.rs b/engine/src/rhs_types/regex/mod.rs index a25b7776..865b1ea8 100644 --- a/engine/src/rhs_types/regex/mod.rs +++ b/engine/src/rhs_types/regex/mod.rs @@ -149,11 +149,11 @@ pub enum Error { #[cfg(test)] mod test { use super::*; - use crate::{ParserSettings, Scheme}; + use crate::{ParserSettings, SchemeBuilder}; #[test] fn test() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); let parser = FilterParser::new(&scheme); let expr = assert_ok!( @@ -178,7 +178,7 @@ mod test { #[test] fn test_raw_string() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); let parser = FilterParser::new(&scheme); let expr = assert_ok!( diff --git a/engine/src/rhs_types/wildcard.rs b/engine/src/rhs_types/wildcard.rs index 970b1d5c..54d56ff6 100644 --- a/engine/src/rhs_types/wildcard.rs +++ b/engine/src/rhs_types/wildcard.rs @@ -137,7 +137,7 @@ impl<'i, 's, const STRICT: bool> LexWith<'i, &FilterParser<'s>> for Wildcard() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); let expr = assert_ok!( Wildcard::::lex_with(r#""a quoted string";"#, &FilterParser::new(&scheme)), @@ -206,7 +206,7 @@ mod test { #[test] fn test_wildcard_lex_raw_string() { fn t() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); // Note that the `\\xaa` is escaping the `\` at the wildcard-language level, not at the // wirefilter-language level. @@ -243,7 +243,7 @@ mod test { #[test] fn test_wildcard_lex_escape_quoted_string_invalid_utf8() { fn t() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); let bytes = [ "a quoted ".as_bytes().to_vec(), @@ -281,7 +281,7 @@ mod test { #[test] fn test_wildcard_lex_reject_bytes_syntax() { fn t() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); assert_err!( Wildcard::::lex_with("61:20:71:75:6F:74", &FilterParser::new(&scheme)), @@ -297,7 +297,7 @@ mod test { #[test] fn test_wildcard_reject_invalid_wildcard() { fn t() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); assert!(matches!( Wildcard::::lex_with(r#"r"*foo\bar*""#, &FilterParser::new(&scheme)) @@ -315,7 +315,7 @@ mod test { #[test] fn test_wildcard_star_limit() { fn t() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); let mut parser = FilterParser::new(&scheme); parser.wildcard_set_star_limit(3); @@ -337,7 +337,7 @@ mod test { #[test] fn test_wildcard_reject_double_star() { fn t() { - let scheme = Scheme::new(); + let scheme = SchemeBuilder::new().build(); assert!( Wildcard::::lex_with("\"*foo*bar*\"", &FilterParser::new(&scheme)).is_ok() diff --git a/engine/src/scheme.rs b/engine/src/scheme.rs index ce73c9f1..97975a49 100644 --- a/engine/src/scheme.rs +++ b/engine/src/scheme.rs @@ -140,7 +140,7 @@ impl<'s> Field<'s> { /// Returns the field's name as recorded in the [`Scheme`](struct@Scheme). #[inline] pub fn name(&self) -> &'s str { - &self.scheme.fields[self.index].0 + &self.scheme.inner.fields[self.index].0 } /// Get the field's index in the [`Scheme`](struct@Scheme) identifier's list. @@ -159,7 +159,7 @@ impl<'s> Field<'s> { impl GetType for Field<'_> { #[inline] fn get_type(&self) -> Type { - self.scheme.fields[self.index].1 + self.scheme.inner.fields[self.index].1 } } @@ -202,7 +202,7 @@ impl<'s> Function<'s> { /// Returns the function's name as recorded in the [`Scheme`](struct@Scheme). #[inline] pub fn name(&self) -> &'s str { - &self.scheme.functions[self.index].0 + &self.scheme.inner.functions[self.index].0 } /// Get the function's index in the [`Scheme`](struct@Scheme) identifier's list. @@ -219,7 +219,7 @@ impl<'s> Function<'s> { #[inline] pub(crate) fn as_definition(&self) -> &'s dyn FunctionDefinition { - &*self.scheme.functions[self.index].1 + &*self.scheme.inner.functions[self.index].1 } } @@ -342,20 +342,20 @@ impl<'s> List<'s> { } pub(crate) fn definition(&self) -> &'s dyn ListDefinition { - &*self.scheme.lists[self.index].1 + &*self.scheme.inner.lists[self.index].1 } } impl Debug for List<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self.scheme.lists[self.index]) + write!(f, "{:?}", self.scheme.inner.lists[self.index]) } } impl GetType for List<'_> { #[inline] fn get_type(&self) -> Type { - self.scheme.lists[self.index].0 + self.scheme.inner.lists[self.index].0 } } @@ -366,13 +366,9 @@ pub struct ListRedefinitionError(Type); type IdentifierName = Arc; -/// The main registry for fields and their associated types. -/// -/// This is necessary to provide typechecking for runtime values provided -/// to the [`crate::ExecutionContext`] and also to aid parser -/// in ambiguous contexts. +/// A builder for a [`Scheme`]. #[derive(Default, Debug)] -pub struct Scheme { +pub struct SchemeBuilder { fields: Vec<(IdentifierName, Type)>, functions: Vec<(IdentifierName, Box)>, items: HashMap, @@ -381,6 +377,106 @@ pub struct Scheme { lists: Vec<(Type, Box)>, } +impl SchemeBuilder { + /// Creates a new scheme. + pub fn new() -> Self { + Default::default() + } + + /// Registers a field and its corresponding type. + pub fn add_field>( + &mut self, + name: N, + ty: Type, + ) -> Result<(), IdentifierRedefinitionError> { + match self.items.entry(name.as_ref().into()) { + Entry::Occupied(entry) => match entry.get() { + SchemeItem::Field(_) => Err(IdentifierRedefinitionError::Field( + FieldRedefinitionError(entry.key().to_string()), + )), + SchemeItem::Function(_) => Err(IdentifierRedefinitionError::Function( + FunctionRedefinitionError(entry.key().to_string()), + )), + }, + Entry::Vacant(entry) => { + let index = self.fields.len(); + self.fields.push((entry.key().clone(), ty)); + entry.insert(SchemeItem::Field(index)); + Ok(()) + } + } + } + + /// Registers a function + pub fn add_function>( + &mut self, + name: N, + function: impl Into>, + ) -> Result<(), IdentifierRedefinitionError> { + match self.items.entry(name.as_ref().into()) { + Entry::Occupied(entry) => match entry.get() { + SchemeItem::Field(_) => Err(IdentifierRedefinitionError::Field( + FieldRedefinitionError(entry.key().to_string()), + )), + SchemeItem::Function(_) => Err(IdentifierRedefinitionError::Function( + FunctionRedefinitionError(entry.key().to_string()), + )), + }, + Entry::Vacant(entry) => { + let index = self.functions.len(); + self.functions.push((entry.key().clone(), function.into())); + entry.insert(SchemeItem::Function(index)); + Ok(()) + } + } + } + + /// Registers a new [`list`](trait.ListDefinition.html) for a given [`type`](enum.Type.html). + pub fn add_list( + &mut self, + ty: Type, + definition: Box, + ) -> Result<(), ListRedefinitionError> { + match self.list_types.entry(ty) { + Entry::Occupied(entry) => Err(ListRedefinitionError(*entry.key())), + Entry::Vacant(entry) => { + let index = self.lists.len(); + self.lists.push((ty, definition)); + entry.insert(index); + Ok(()) + } + } + } + + /// Build a new [`Scheme`] from this builder. + pub fn build(self) -> Scheme { + Scheme { inner: self } + } +} + +impl> FromIterator<(N, Type)> for SchemeBuilder { + fn from_iter>(iter: T) -> Self { + let mut builder = SchemeBuilder::new(); + for (name, ty) in iter { + builder + .add_field(name.as_ref(), ty) + .map_err(|err| err.to_string()) + .unwrap(); + } + builder + } +} + +/// The main registry for fields and their associated types. +/// +/// This is necessary to provide typechecking for runtime values provided +/// to the [`crate::ExecutionContext`] and also to aid parser +/// in ambiguous contexts. +#[derive(Debug)] +pub struct Scheme { + inner: SchemeBuilder, +} + impl PartialEq for Scheme { fn eq(&self, other: &Self) -> bool { ptr::eq(self, other) @@ -415,24 +511,19 @@ impl<'de> Deserialize<'de> for Scheme { { use serde::de::Error; - let mut scheme = Scheme::new(); + let mut builder = SchemeBuilder::new(); let map: HashMap = HashMap::::deserialize(deserializer)?; for (name, ty) in map { - scheme.add_field(&name, ty).map_err(D::Error::custom)?; + builder.add_field(&name, ty).map_err(D::Error::custom)?; } - Ok(scheme) + Ok(builder.build()) } } impl<'s> Scheme { - /// Creates a new scheme. - pub fn new() -> Self { - Default::default() - } - /// Returns the [`identifier`](enum@Identifier) with the specified `name`. pub fn get(&'s self, name: &str) -> Option> { - self.items.get(name).map(move |item| match *item { + self.inner.items.get(name).map(move |item| match *item { SchemeItem::Field(index) => Identifier::Field(Field { scheme: self, index, @@ -444,30 +535,6 @@ impl<'s> Scheme { }) } - /// Registers a field and its corresponding type. - pub fn add_field>( - &mut self, - name: N, - ty: Type, - ) -> Result<(), IdentifierRedefinitionError> { - match self.items.entry(name.as_ref().into()) { - Entry::Occupied(entry) => match entry.get() { - SchemeItem::Field(_) => Err(IdentifierRedefinitionError::Field( - FieldRedefinitionError(entry.key().to_string()), - )), - SchemeItem::Function(_) => Err(IdentifierRedefinitionError::Function( - FunctionRedefinitionError(entry.key().to_string()), - )), - }, - Entry::Vacant(entry) => { - let index = self.fields.len(); - self.fields.push((entry.key().clone(), ty)); - entry.insert(SchemeItem::Field(index)); - Ok(()) - } - } - } - /// Returns the [`field`](struct@Field) with the specified `name`. pub fn get_field(&'s self, name: &str) -> Result, UnknownFieldError> { match self.get(name) { @@ -479,7 +546,7 @@ impl<'s> Scheme { /// Iterates over fields registered in the [`scheme`](struct@Scheme). #[inline] pub fn fields(&'s self) -> impl ExactSizeIterator> + 's { - (0..self.fields.len()).map(|index| Field { + (0..self.inner.fields.len()).map(|index| Field { scheme: self, index, }) @@ -488,37 +555,13 @@ impl<'s> Scheme { /// Returns the number of fields in the [`scheme`](struct@Scheme). #[inline] pub fn field_count(&self) -> usize { - self.fields.len() + self.inner.fields.len() } /// Returns the number of functions in the [`scheme`](struct@Scheme). #[inline] pub fn function_count(&self) -> usize { - self.functions.len() - } - - /// Registers a function - pub fn add_function>( - &mut self, - name: N, - function: impl Into>, - ) -> Result<(), IdentifierRedefinitionError> { - match self.items.entry(name.as_ref().into()) { - Entry::Occupied(entry) => match entry.get() { - SchemeItem::Field(_) => Err(IdentifierRedefinitionError::Field( - FieldRedefinitionError(entry.key().to_string()), - )), - SchemeItem::Function(_) => Err(IdentifierRedefinitionError::Function( - FunctionRedefinitionError(entry.key().to_string()), - )), - }, - Entry::Vacant(entry) => { - let index = self.functions.len(); - self.functions.push((entry.key().clone(), function.into())); - entry.insert(SchemeItem::Function(index)); - Ok(()) - } - } + self.inner.functions.len() } /// Returns the [`function`](struct@Function) with the specified `name`. @@ -532,7 +575,7 @@ impl<'s> Scheme { /// Iterates over functions registered in the [`scheme`](struct@Scheme). #[inline] pub fn functions(&'s self) -> impl ExactSizeIterator> + 's { - (0..self.functions.len()).map(|index| Function { + (0..self.inner.functions.len()).map(|index| Function { scheme: self, index, }) @@ -561,29 +604,12 @@ impl<'s> Scheme { /// Returns the number of lists in the [`scheme`](struct@Scheme) #[inline] pub fn list_count(&self) -> usize { - self.lists.len() - } - - /// Registers a new [`list`](trait.ListDefinition.html) for a given [`type`](enum.Type.html). - pub fn add_list( - &mut self, - ty: Type, - definition: Box, - ) -> Result<(), ListRedefinitionError> { - match self.list_types.entry(ty) { - Entry::Occupied(entry) => Err(ListRedefinitionError(*entry.key())), - Entry::Vacant(entry) => { - let index = self.lists.len(); - self.lists.push((ty, definition)); - entry.insert(index); - Ok(()) - } - } + self.inner.lists.len() } /// Returns the [`list`](struct.List.html) for a given [`type`](enum.Type.html). pub fn get_list(&self, ty: &Type) -> Option> { - self.list_types.get(ty).map(move |index| List { + self.inner.list_types.get(ty).map(move |index| List { scheme: self, index: *index, }) @@ -591,32 +617,18 @@ impl<'s> Scheme { /// Iterates over all registered [`lists`](trait.ListDefinition.html). pub fn lists(&self) -> impl ExactSizeIterator> { - (0..self.lists.len()).map(|index| List { + (0..self.inner.lists.len()).map(|index| List { scheme: self, index, }) } } -impl> FromIterator<(N, Type)> for Scheme { - fn from_iter>(iter: T) -> Self { - let mut scheme = Scheme::new(); - for (name, ty) in iter { - scheme - .add_field(name.as_ref(), ty) - .map_err(|err| err.to_string()) - .unwrap(); - } - scheme - } -} - -/// A convenience macro for constructing a [`Scheme`](struct@Scheme) with static -/// contents. +/// A convenience macro for constructing a [`SchemeBuilder`] with static contents. #[macro_export] macro_rules! Scheme { ($($ns:ident $(. $field:ident)*: $ty:ident $(($subty:tt $($rest:tt)*))?),* $(,)*) => { - $crate::Scheme::from_iter([$( + $crate::SchemeBuilder::from_iter([$( ( concat!(stringify!($ns) $(, ".", stringify!($field))*), Scheme!($ty $(($subty $($rest)*))?), @@ -632,16 +644,18 @@ fn test_parse_error() { use crate::ConcatFunction; use indoc::indoc; - let mut scheme = Scheme! { + let mut builder = Scheme! { num: Int, str: Bytes, arr: Array(Bool), }; - scheme + builder .add_function("concat", ConcatFunction::new()) .unwrap(); + let scheme = builder.build(); + { let err = scheme.parse("xyz").unwrap_err(); assert_eq!( @@ -924,7 +938,8 @@ fn test_parse_error_in_op() { ip: Ip, str_arr: Array(Bytes), str_map: Map(Bytes), - }; + } + .build(); { let err = scheme.parse("bool in {0}").unwrap_err(); @@ -1193,7 +1208,8 @@ fn test_parse_error_ordering_op() { ip: Ip, str_arr: Array(Bytes), str_map: Map(Bytes), - }; + } + .build(); for op in &["eq", "ne", "ge", "le", "gt", "lt"] { { @@ -1385,7 +1401,8 @@ fn test_field() { x.y.z0: Int, is_TCP: Bool, map: Map(Bytes) - }; + } + .build(); assert_ok!( Field::lex_with("x;", scheme), @@ -1462,7 +1479,8 @@ fn test_scheme_iter_fields() { x.y.z0: Int, is_TCP: Bool, map: Map(Bytes) - }; + } + .build(); let mut fields = scheme.fields().collect::>(); fields.sort_by(|f1, f2| f1.name().partial_cmp(f2.name()).unwrap()); diff --git a/ffi/cbindgen.toml b/ffi/cbindgen.toml index 3773e6d1..46e89d62 100644 --- a/ffi/cbindgen.toml +++ b/ffi/cbindgen.toml @@ -32,6 +32,7 @@ renaming_overrides_prefixing = false "ParsingResult" = "parsing_result" "RustAllocatedString" = "rust_allocated_str" "Scheme" = "scheme" +"SchemeBuilder" = "scheme_builder" "SerializingResult" = "serializing_result" "StaticRustAllocatedString" = "static_rust_allocated_str" "Status" = "status" diff --git a/ffi/include/wirefilter.h b/ffi/include/wirefilter.h index 878beab1..2949e6ff 100644 --- a/ffi/include/wirefilter.h +++ b/ffi/include/wirefilter.h @@ -61,6 +61,8 @@ struct wirefilter_map; struct wirefilter_scheme; +struct wirefilter_scheme_builder; + struct wirefilter_type { uint32_t layers; uint8_t len; @@ -124,9 +126,9 @@ const char *wirefilter_get_last_error(void); */ void wirefilter_clear_last_error(void); -struct wirefilter_scheme *wirefilter_create_scheme(void); +struct wirefilter_scheme_builder *wirefilter_create_scheme_builder(void); -void wirefilter_free_scheme(struct wirefilter_scheme *scheme); +void wirefilter_free_scheme_builder(struct wirefilter_scheme_builder *scheme); struct wirefilter_type wirefilter_create_primitive_type(wirefilter_primitive_type ty); @@ -134,7 +136,7 @@ struct wirefilter_type wirefilter_create_map_type(struct wirefilter_type ty); struct wirefilter_type wirefilter_create_array_type(struct wirefilter_type ty); -bool wirefilter_add_type_field_to_scheme(struct wirefilter_scheme *scheme, +bool wirefilter_add_type_field_to_scheme(struct wirefilter_scheme_builder *builder, const char *name_ptr, size_t name_len, struct wirefilter_type ty); @@ -143,10 +145,14 @@ struct wirefilter_list_definition *wirefilter_create_always_list(void); struct wirefilter_list_definition *wirefilter_create_never_list(void); -bool wirefilter_add_type_list_to_scheme(struct wirefilter_scheme *scheme, +bool wirefilter_add_type_list_to_scheme(struct wirefilter_scheme_builder *builder, struct wirefilter_type ty, struct wirefilter_list_definition *list); +struct wirefilter_scheme *wirefilter_build_scheme(struct wirefilter_scheme_builder *builder); + +void wirefilter_free_scheme(struct wirefilter_scheme *scheme); + void wirefilter_free_string(struct wirefilter_rust_allocated_str s); struct wirefilter_parsing_result wirefilter_parse_filter(const struct wirefilter_scheme *scheme, diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index f0bd74e9..df14d380 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -172,7 +172,13 @@ macro_rules! wrap_type { }; } -/* Wrapper types needed by cbindgen to forard declare opaque structs */ +/* Wrapper types needed by cbindgen to forward declare opaque structs */ + +#[derive(Debug, Default)] +#[repr(Rust)] +pub struct SchemeBuilder(wirefilter::SchemeBuilder); + +wrap_type!(SchemeBuilder); #[derive(Debug, PartialEq)] #[repr(Rust)] @@ -256,12 +262,12 @@ pub extern "C" fn wirefilter_clear_last_error() { } #[no_mangle] -pub extern "C" fn wirefilter_create_scheme() -> Box { - Box::new(Scheme(Default::default())) +pub extern "C" fn wirefilter_create_scheme_builder() -> Box { + Box::default() } #[no_mangle] -pub extern "C" fn wirefilter_free_scheme(scheme: Box) { +pub extern "C" fn wirefilter_free_scheme_builder(scheme: Box) { drop(scheme); } @@ -307,13 +313,13 @@ macro_rules! to_str { #[no_mangle] pub extern "C" fn wirefilter_add_type_field_to_scheme( - scheme: &mut Scheme, + builder: &mut SchemeBuilder, name_ptr: *const c_char, name_len: usize, ty: CType, ) -> bool { let name = to_str!(name_ptr, name_len); - scheme.add_field(name, ty.into()).is_ok() + builder.add_field(name, ty.into()).is_ok() } pub type CListDefinition = Box; @@ -330,11 +336,21 @@ pub extern "C" fn wirefilter_create_never_list() -> Box { #[no_mangle] pub extern "C" fn wirefilter_add_type_list_to_scheme( - scheme: &mut Scheme, + builder: &mut SchemeBuilder, ty: CType, list: Box, ) -> bool { - scheme.add_list(ty.into(), *list).is_ok() + builder.add_list(ty.into(), *list).is_ok() +} + +#[no_mangle] +pub extern "C" fn wirefilter_build_scheme(builder: Box) -> Box { + Box::new(Scheme(builder.0.build())) +} + +#[no_mangle] +pub extern "C" fn wirefilter_free_scheme(scheme: Box) { + drop(scheme); } #[derive(Debug, PartialEq)] @@ -1060,12 +1076,12 @@ mod ffi_test { } fn create_scheme() -> Box { - let mut scheme = wirefilter_create_scheme(); + let mut builder = wirefilter_create_scheme_builder(); macro_rules! add_field { - ($scheme:ident, $field:literal, $ty:expr) => { + ($builder:ident, $field:literal, $ty:expr) => { assert!(wirefilter_add_type_field_to_scheme( - &mut $scheme, + &mut $builder, $field.as_ptr().cast(), $field.len(), $ty.into(), @@ -1073,29 +1089,33 @@ mod ffi_test { }; } - add_field!(scheme, "ip1", Type::Ip); - add_field!(scheme, "ip2", Type::Ip); + add_field!(builder, "ip1", Type::Ip); + add_field!(builder, "ip2", Type::Ip); - add_field!(scheme, "str1", Type::Bytes); - add_field!(scheme, "str2", Type::Bytes); + add_field!(builder, "str1", Type::Bytes); + add_field!(builder, "str2", Type::Bytes); - add_field!(scheme, "num1", Type::Int); - add_field!(scheme, "num2", Type::Int); + add_field!(builder, "num1", Type::Int); + add_field!(builder, "num2", Type::Int); - add_field!(scheme, "map1", wirefilter_create_map_type(Type::Int.into())); add_field!( - scheme, + builder, + "map1", + wirefilter_create_map_type(Type::Int.into()) + ); + add_field!( + builder, "map2", wirefilter_create_map_type(Type::Bytes.into()) ); wirefilter_add_type_list_to_scheme( - &mut scheme, + &mut builder, Type::Int.into(), wirefilter_create_always_list(), ); - scheme + wirefilter_build_scheme(builder) } fn create_execution_context<'e, 's: 'e>(scheme: &'s Scheme) -> Box> { diff --git a/ffi/tests/ctests/src/lib.rs b/ffi/tests/ctests/src/lib.rs index a1430e9d..34eb7020 100644 --- a/ffi/tests/ctests/src/lib.rs +++ b/ffi/tests/ctests/src/lib.rs @@ -33,7 +33,7 @@ mod ffi_ctest { create_array_type, create_map_type, create_complex_type, - create_scheme, + create_scheme_builder, add_fields_to_scheme, add_malloced_type_field_to_scheme, parse_good_filter, diff --git a/ffi/tests/ctests/src/tests.c b/ffi/tests/ctests/src/tests.c index 6da0bc1a..9be73834 100644 --- a/ffi/tests/ctests/src/tests.c +++ b/ffi/tests/ctests/src/tests.c @@ -15,49 +15,58 @@ extern void rust_assert(bool check, const char *msg); #define WIREFILTER_TYPE_BOOL (wirefilter_create_primitive_type(WIREFILTER_PRIMITIVE_TYPE_BOOL)) #define WIREFILTER_TYPE_INT (wirefilter_create_primitive_type(WIREFILTER_PRIMITIVE_TYPE_INT)) -void initialize_scheme(struct wirefilter_scheme *scheme) { +void initialize_scheme(struct wirefilter_scheme_builder *builder) { rust_assert(wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("http.host"), WIREFILTER_TYPE_BYTES ), "could not add field http.host of type \"Bytes\" to scheme"); rust_assert(wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("ip.src"), WIREFILTER_TYPE_IP ), "could not add field ip.src of type \"Ip\" to scheme"); rust_assert(wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("ip.dst"), WIREFILTER_TYPE_IP ), "could not add field ip.dst of type \"Ip\" to scheme"); rust_assert(wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("ssl"), WIREFILTER_TYPE_BOOL ), "could not add field ssl of type \"Bool\" to scheme"); rust_assert(wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("tcp.port"), WIREFILTER_TYPE_INT ), "could not add field tcp.port of type \"Int\" to scheme"); wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("http.headers"), wirefilter_create_map_type(WIREFILTER_TYPE_BYTES) ); rust_assert(wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("http.cookies"), wirefilter_create_array_type(WIREFILTER_TYPE_BYTES) ), "could not add field http.cookies of type \"Array\" to scheme"); rust_assert(wirefilter_add_type_list_to_scheme( - scheme, - WIREFILTER_TYPE_IP, - wirefilter_create_always_list() + builder, + WIREFILTER_TYPE_IP, + wirefilter_create_always_list() ), "could not add list for type \"Ip\" to scheme"); } +struct wirefilter_scheme *build_scheme() { + struct wirefilter_scheme_builder *builder = wirefilter_create_scheme_builder(); + rust_assert(builder != NULL, "could not create scheme builder"); + + initialize_scheme(builder); + + return wirefilter_build_scheme(builder); +} + void wirefilter_ffi_ctest_create_array_type() { struct wirefilter_type array_type = wirefilter_create_array_type(WIREFILTER_TYPE_BYTES); rust_assert(array_type.layers == 0, "could not create valid array type"); @@ -88,46 +97,44 @@ void wirefilter_ffi_ctest_create_complex_type() { rust_assert(type.primitive == WIREFILTER_PRIMITIVE_TYPE_BYTES, "could not create valid type"); } -void wirefilter_ffi_ctest_create_scheme() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); - rust_assert(scheme != NULL, "could not create scheme"); - wirefilter_free_scheme(scheme); +void wirefilter_ffi_ctest_create_scheme_builder() { + struct wirefilter_scheme_builder *builder = wirefilter_create_scheme_builder(); + rust_assert(builder != NULL, "could not create scheme builder"); + wirefilter_free_scheme_builder(builder); } void wirefilter_ffi_ctest_add_fields_to_scheme() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); - rust_assert(scheme != NULL, "could not create scheme"); + struct wirefilter_scheme_builder *builder = wirefilter_create_scheme_builder(); + rust_assert(builder != NULL, "could not create scheme builder"); - initialize_scheme(scheme); + initialize_scheme(builder); - wirefilter_free_scheme(scheme); + wirefilter_free_scheme_builder(builder); } void wirefilter_ffi_ctest_add_malloced_type_field_to_scheme() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); - rust_assert(scheme != NULL, "could not create scheme"); + struct wirefilter_scheme_builder *builder = wirefilter_create_scheme_builder(); + rust_assert(builder != NULL, "could not create scheme builder"); struct wirefilter_type *byte_type = (struct wirefilter_type *)malloc(sizeof(struct wirefilter_type)); rust_assert(byte_type != NULL, "could not allocate type"); *byte_type = WIREFILTER_TYPE_BYTES; rust_assert(wirefilter_add_type_field_to_scheme( - scheme, + builder, STRING("http.host"), *byte_type ), "could not add field http.host of type \"Bytes\" to scheme"); free(byte_type); - wirefilter_free_scheme(scheme); + wirefilter_free_scheme_builder(builder); } void wirefilter_ffi_ctest_parse_good_filter() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result = wirefilter_parse_filter( scheme, STRING("tcp.port == 80") @@ -141,11 +148,9 @@ void wirefilter_ffi_ctest_parse_good_filter() { } void wirefilter_ffi_ctest_parse_bad_filter() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result = wirefilter_parse_filter( scheme, STRING("tcp.port == \"wirefilter\"") @@ -157,11 +162,9 @@ void wirefilter_ffi_ctest_parse_bad_filter() { } void wirefilter_ffi_ctest_filter_uses_field() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result parsing_result = wirefilter_parse_filter( scheme, STRING("tcp.port == 80") @@ -193,11 +196,9 @@ void wirefilter_ffi_ctest_filter_uses_field() { } void wirefilter_ffi_ctest_filter_uses_list_field() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result parsing_result = wirefilter_parse_filter( scheme, STRING("ip.src in $bad") @@ -229,11 +230,9 @@ void wirefilter_ffi_ctest_filter_uses_list_field() { } void wirefilter_ffi_ctest_filter_hash() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result1 = wirefilter_parse_filter( scheme, STRING("tcp.port == 80") @@ -268,11 +267,9 @@ void wirefilter_ffi_ctest_filter_hash() { } void wirefilter_ffi_ctest_filter_serialize() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result = wirefilter_parse_filter( scheme, STRING("tcp.port == 80") @@ -299,11 +296,9 @@ void wirefilter_ffi_ctest_filter_serialize() { } void wirefilter_ffi_ctest_scheme_serialize() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_serializing_result serializing_result = wirefilter_serialize_scheme_to_json(scheme); rust_assert(serializing_result.status == WIREFILTER_STATUS_SUCCESS, "could not serialize scheme to JSON"); @@ -353,11 +348,9 @@ void wirefilter_ffi_ctest_type_serialize() { } void wirefilter_ffi_ctest_compile_filter() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result = wirefilter_parse_filter( scheme, STRING("tcp.port == 80") @@ -375,7 +368,7 @@ void wirefilter_ffi_ctest_compile_filter() { } void wirefilter_ffi_ctest_create_execution_context() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); struct wirefilter_execution_context *exec_ctx = wirefilter_create_execution_context(scheme); @@ -387,11 +380,9 @@ void wirefilter_ffi_ctest_create_execution_context() { } void wirefilter_ffi_ctest_add_values_to_execution_context() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_execution_context *exec_ctx = wirefilter_create_execution_context(scheme); rust_assert(exec_ctx != NULL, "could not create execution context"); @@ -433,11 +424,9 @@ void wirefilter_ffi_ctest_add_values_to_execution_context() { } void wirefilter_ffi_ctest_add_values_to_execution_context_errors() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_execution_context *exec_ctx = wirefilter_create_execution_context(scheme); rust_assert(exec_ctx != NULL, "could not create execution context"); @@ -497,11 +486,9 @@ void wirefilter_ffi_ctest_add_values_to_execution_context_errors() { } void wirefilter_ffi_ctest_execution_context_serialize() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_execution_context *exec_ctx = wirefilter_create_execution_context(scheme); rust_assert(exec_ctx != NULL, "could not create execution context"); @@ -561,11 +548,9 @@ void wirefilter_ffi_ctest_execution_context_serialize() { } void wirefilter_ffi_ctest_execution_context_deserialize() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_execution_context *exec_ctx = wirefilter_create_execution_context(scheme); rust_assert(exec_ctx != NULL, "could not create execution context"); @@ -618,11 +603,9 @@ void wirefilter_ffi_ctest_execution_context_deserialize() { void wirefilter_ffi_ctest_match_filter() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result = wirefilter_parse_filter( scheme, STRING("tcp.port == 80") @@ -676,11 +659,9 @@ void wirefilter_ffi_ctest_match_filter() { } void wirefilter_ffi_ctest_match_map() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result = wirefilter_parse_filter( scheme, STRING("http.headers[\"host\"] == \"www.cloudflare.com\"") @@ -750,11 +731,9 @@ void wirefilter_ffi_ctest_match_map() { } void wirefilter_ffi_ctest_match_array() { - struct wirefilter_scheme *scheme = wirefilter_create_scheme(); + struct wirefilter_scheme *scheme = build_scheme(); rust_assert(scheme != NULL, "could not create scheme"); - initialize_scheme(scheme); - struct wirefilter_parsing_result result = wirefilter_parse_filter( scheme, STRING("http.cookies[2] == \"www.cloudflare.com\"")