Skip to content

Commit 7963899

Browse files
committed
Rework Scheme serialization
This change is a necessary rework of scheme serialization to allow for additional field properties that will be introduced in a future commit. Before this change, a serialized scheme was a map of field name to field type. After this change, a serialized scheme is a map of field name to field definition object, which only contain its type for now but can be extended with additional properties.
1 parent 35f49ec commit 7963899

File tree

2 files changed

+72
-15
lines changed

2 files changed

+72
-15
lines changed

engine/src/scheme.rs

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
types::{GetType, RhsValue, Type},
1010
};
1111
use fnv::FnvBuildHasher;
12+
use serde::de::Visitor;
1213
use serde::ser::SerializeMap;
1314
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1415
use std::collections::hash_map::Entry;
@@ -139,7 +140,7 @@ impl<'s> FieldRef<'s> {
139140
/// Returns the field's name as recorded in the [`Scheme`](struct@Scheme).
140141
#[inline]
141142
pub fn name(&self) -> &'s str {
142-
&self.scheme.inner.fields[self.index].0
143+
&self.scheme.inner.fields[self.index].name
143144
}
144145

145146
/// Get the field's index in the [`Scheme`](struct@Scheme) identifier's list.
@@ -183,7 +184,7 @@ impl<'s> FieldRef<'s> {
183184
impl GetType for FieldRef<'_> {
184185
#[inline]
185186
fn get_type(&self) -> Type {
186-
self.scheme.inner.fields[self.index].1
187+
self.scheme.inner.fields[self.index].ty
187188
}
188189
}
189190

@@ -217,7 +218,7 @@ impl Field {
217218
/// Returns the field's name as recorded in the [`Scheme`](struct@Scheme).
218219
#[inline]
219220
pub fn name(&self) -> &str {
220-
&self.scheme.inner.fields[self.index].0
221+
&self.scheme.inner.fields[self.index].name
221222
}
222223

223224
/// Get the field's index in the [`Scheme`](struct@Scheme) identifier's list.
@@ -245,7 +246,7 @@ impl Field {
245246
impl GetType for Field {
246247
#[inline]
247248
fn get_type(&self) -> Type {
248-
self.scheme.inner.fields[self.index].1
249+
self.scheme.inner.fields[self.index].ty
249250
}
250251
}
251252

@@ -609,10 +610,16 @@ pub struct ListRedefinitionError(Type);
609610

610611
type IdentifierName = Arc<str>;
611612

613+
#[derive(Debug, PartialEq)]
614+
struct FieldDefinition {
615+
name: IdentifierName,
616+
ty: Type,
617+
}
618+
612619
/// A builder for a [`Scheme`].
613620
#[derive(Default, Debug)]
614621
pub struct SchemeBuilder {
615-
fields: Vec<(IdentifierName, Type)>,
622+
fields: Vec<FieldDefinition>,
616623
functions: Vec<(IdentifierName, Box<dyn FunctionDefinition>)>,
617624
items: HashMap<IdentifierName, SchemeItem, FnvBuildHasher>,
618625

@@ -643,7 +650,10 @@ impl SchemeBuilder {
643650
},
644651
Entry::Vacant(entry) => {
645652
let index = self.fields.len();
646-
self.fields.push((entry.key().clone(), ty));
653+
self.fields.push(FieldDefinition {
654+
name: entry.key().clone(),
655+
ty,
656+
});
647657
entry.insert(SchemeItem::Field(index));
648658
Ok(())
649659
}
@@ -737,14 +747,21 @@ impl Hash for Scheme {
737747
}
738748
}
739749

750+
#[derive(Deserialize, Serialize)]
751+
struct SerdeField {
752+
#[serde(rename = "type")]
753+
ty: Type,
754+
}
755+
740756
impl Serialize for Scheme {
741757
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
742758
where
743759
S: Serializer,
744760
{
745-
let mut map = serializer.serialize_map(Some(self.field_count()))?;
746-
for f in self.fields() {
747-
map.serialize_entry(f.name(), &f.get_type())?;
761+
let fields = self.fields();
762+
let mut map = serializer.serialize_map(Some(fields.len()))?;
763+
for f in fields {
764+
map.serialize_entry(f.name(), &SerdeField { ty: f.get_type() })?;
748765
}
749766
map.end()
750767
}
@@ -757,12 +774,31 @@ impl<'de> Deserialize<'de> for Scheme {
757774
{
758775
use serde::de::Error;
759776

760-
let mut builder = SchemeBuilder::new();
761-
let map: HashMap<String, Type> = HashMap::<String, Type>::deserialize(deserializer)?;
762-
for (name, ty) in map {
763-
builder.add_field(&name, ty).map_err(D::Error::custom)?;
777+
struct FieldMapVisitor;
778+
779+
impl<'de> Visitor<'de> for FieldMapVisitor {
780+
type Value = SchemeBuilder;
781+
782+
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
783+
formatter.write_str("a wirefilter scheme")
784+
}
785+
786+
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
787+
where
788+
A: serde::de::MapAccess<'de>,
789+
{
790+
let mut builder = SchemeBuilder::new();
791+
while let Some((name, SerdeField { ty })) = map.next_entry::<&str, SerdeField>()? {
792+
builder.add_field(name, ty).map_err(A::Error::custom)?;
793+
}
794+
795+
Ok(builder)
796+
}
764797
}
765-
Ok(builder.build())
798+
799+
deserializer
800+
.deserialize_map(FieldMapVisitor)
801+
.map(|builder| builder.build())
766802
}
767803
}
768804

@@ -1743,3 +1779,24 @@ fn test_scheme_iter_fields() {
17431779
]
17441780
);
17451781
}
1782+
1783+
#[test]
1784+
fn test_scheme_json_serialization() {
1785+
let scheme = Scheme! {
1786+
bytes: Bytes,
1787+
int: Int,
1788+
bool: Bool,
1789+
ip: Ip,
1790+
map_of_bytes: Map(Bytes),
1791+
map_of_array_of_bytes: Map(Array(Bytes)),
1792+
array_of_bytes: Array(Bytes),
1793+
array_of_map_of_bytes: Array(Map(Bytes)),
1794+
}
1795+
.build();
1796+
1797+
let json = serde_json::to_string(&scheme).unwrap();
1798+
1799+
let new_scheme = serde_json::from_str::<Scheme>(&json).unwrap();
1800+
1801+
assert_eq!(scheme.inner.fields, new_scheme.inner.fields);
1802+
}

ffi/tests/ctests/src/tests.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ void wirefilter_ffi_ctest_scheme_serialize() {
305305
rust_assert(json.ptr != NULL && json.len > 0, "could not serialize scheme to JSON");
306306

307307
rust_assert(
308-
strncmp(json.ptr, "{\"http.host\":\"Bytes\",\"ip.src\":\"Ip\",\"ip.dst\":\"Ip\",\"ssl\":\"Bool\",\"tcp.port\":\"Int\",\"http.headers\":{\"Map\":\"Bytes\"},\"http.cookies\":{\"Array\":\"Bytes\"}}", json.len) == 0,
308+
strncmp(json.ptr, "{\"http.host\":{\"type\":\"Bytes\"},\"ip.src\":{\"type\":\"Ip\"},\"ip.dst\":{\"type\":\"Ip\"},\"ssl\":{\"type\":\"Bool\"},\"tcp.port\":{\"type\":\"Int\"},\"http.headers\":{\"type\":{\"Map\":\"Bytes\"}},\"http.cookies\":{\"type\":{\"Array\":\"Bytes\"}}}", json.len) == 0,
309309
"invalid JSON serialization"
310310
);
311311

0 commit comments

Comments
 (0)