New concise encoding

This commit is contained in:
Alex 2022-12-15 15:36:41 +01:00
parent abc27adea4
commit 52f6bd177c
Signed by: lx
GPG key ID: 0E496D15096376BE
3 changed files with 88 additions and 67 deletions

View file

@ -2,7 +2,7 @@
name = "nettext" name = "nettext"
description = "A text-based data format for cryptographic network protocols" description = "A text-based data format for cryptographic network protocols"
authors = ["Alex Auvolat <alex@adnab.me>"] authors = ["Alex Auvolat <alex@adnab.me>"]
version = "0.3.0" version = "0.3.1"
edition = "2021" edition = "2021"
license = "AGPL-3.0" license = "AGPL-3.0"
readme = "README.md" readme = "README.md"

View file

@ -262,6 +262,13 @@ impl<'a> Term<'a> {
pub fn encode_string(self) -> String { pub fn encode_string(self) -> String {
unsafe { String::from_utf8_unchecked(self.encode()) } unsafe { String::from_utf8_unchecked(self.encode()) }
} }
/// Generate the concise nettext representation of a term
pub fn encode_concise(self) -> Vec<u8> {
let mut buf = Vec::with_capacity(128);
self.0.encode_concise_aux(&mut buf);
buf
}
} }
impl<'a> T<'a> { impl<'a> T<'a> {
@ -339,6 +346,46 @@ impl<'a> T<'a> {
} }
} }
} }
fn encode_concise_aux(self, buf: &mut Vec<u8>) {
match self {
T::Str(s) => buf.extend_from_slice(s),
T::OwnedStr(s) => buf.extend_from_slice(&s),
T::Dict(mut d) => {
buf.push(b'{');
let mut keys = d.keys().cloned().collect::<Vec<_>>();
keys.sort();
for (i, k) in keys.into_iter().enumerate() {
if i > 0 {
buf.push(b',');
}
let v = d.remove(&k).unwrap();
buf.extend_from_slice(k.borrow());
buf.push(b'=');
v.encode_concise_aux(buf);
}
buf.push(b'}');
}
T::List(l) => {
buf.push(b'[');
for (i,item) in l.into_iter().enumerate() {
if i > 0 {
buf.push(b',');
}
item.encode_concise_aux(buf);
}
buf.push(b']');
}
T::Seq(l) => {
for (i, v) in l.into_iter().enumerate() {
if i > 0 {
buf.push(b' ');
}
v.encode_concise_aux(buf);
}
}
}
}
} }
#[cfg(test)] #[cfg(test)]
@ -363,6 +410,7 @@ mod tests {
.unwrap(), .unwrap(),
]) ])
.unwrap(); .unwrap();
let expected = "HELLO alexhelloworld [ let expected = "HELLO alexhelloworld [
dude, dude,
why, why,
@ -371,9 +419,27 @@ mod tests {
from = jxx, from = jxx,
subject = hello, subject = hello,
}"; }";
let enc = input.encode(); assert_eq!(debug(&input.encode()), expected);
eprintln!("{}", debug(&enc)); }
eprintln!("{}", expected);
assert_eq!(debug(&enc), expected); #[test]
fn complex1_concise() {
let input = seq([
string("HELLO").unwrap(),
string("alexhelloworld").unwrap(),
list([
string("dude").unwrap(),
string("why").unwrap(),
]),
dict([
("from", string("jxx").unwrap()),
("subject", string("hello").unwrap()),
("data", raw(b"{ f1 = plop, f2 = kuko }").unwrap()),
])
.unwrap(),
])
.unwrap();
let expected_concise = "HELLO alexhelloworld [dude,why] {data={ f1 = plop, f2 = kuko },from=jxx,subject=hello}";
assert_eq!(debug(&input.encode_concise()), expected_concise);
} }
} }

View file

@ -17,14 +17,20 @@ mod tests {
fn test_bidir<T: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug>( fn test_bidir<T: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug>(
input: T, input: T,
expected: &str, expected_concise: &str,
) { ) {
eprintln!("Expecting: {}", expected); eprintln!("Expecting: {}", expected_concise);
let ser = to_bytes(&input).unwrap(); let ser = to_bytes(&input).unwrap();
let ser = debug(&ser); let ser = debug(&ser);
eprintln!("Serialized: {}", ser); eprintln!("Serialized: {}", ser);
assert_eq!(ser, expected);
assert_eq!(from_bytes::<T>(ser.as_bytes()).unwrap(), input); assert_eq!(from_bytes::<T>(ser.as_bytes()).unwrap(), input);
let ser_concise = to_term(&input).unwrap().encode_concise();
let ser_concise = debug(&ser_concise);
eprintln!("Serialized (concise): {}", ser_concise);
assert_eq!(ser_concise, expected_concise);
assert_eq!(from_bytes::<T>(ser_concise.as_bytes()).unwrap(), input);
} }
#[test] #[test]
@ -39,13 +45,7 @@ mod tests {
int: 1, int: 1,
seq: vec!["a".to_string(), "b".to_string()], seq: vec!["a".to_string(), "b".to_string()],
}; };
let expected = r#"Test { let expected = r#"Test {int=1,seq=[YQ,Yg]}"#;
int = 1,
seq = [
YQ,
Yg,
],
}"#;
test_bidir(input, expected); test_bidir(input, expected);
let input = vec![ let input = vec![
@ -58,22 +58,7 @@ mod tests {
seq: vec!["c".to_string(), "d".to_string()], seq: vec!["c".to_string(), "d".to_string()],
}, },
]; ];
let expected = r#"[ let expected = r#"[Test {int=1,seq=[YQ,Yg]},Test {int=2,seq=[Yw,ZA]}]"#;
Test {
int = 1,
seq = [
YQ,
Yg,
],
},
Test {
int = 2,
seq = [
Yw,
ZA,
],
},
]"#;
test_bidir(input, expected); test_bidir(input, expected);
} }
@ -100,7 +85,7 @@ mod tests {
test_bidir(input, expected); test_bidir(input, expected);
let input = E::Struct { a: 1 }; let input = E::Struct { a: 1 };
let expected = r#"E.Struct { a = 1 }"#; let expected = r#"E.Struct {a=1}"#;
test_bidir(input, expected); test_bidir(input, expected);
let input = vec![ let input = vec![
@ -112,14 +97,7 @@ mod tests {
E::Tuple(3, 2), E::Tuple(3, 2),
]; ];
let expected = let expected =
r#"[ r#"[E.Unit,E.Unit,E.Newtype 1,E.Tuple 1 2,E.Struct {a=1},E.Tuple 3 2]"#;
E.Unit,
E.Unit,
E.Newtype 1,
E.Tuple 1 2,
E.Struct { a = 1 },
E.Tuple 3 2,
]"#;
test_bidir(input, expected); test_bidir(input, expected);
} }
@ -133,24 +111,14 @@ mod tests {
#[test] #[test]
fn test_list() { fn test_list() {
let input = vec![1, 2, 3, 4]; let input = vec![1, 2, 3, 4];
let expected = r#"[ let expected = r#"[1,2,3,4]"#;
1,
2,
3,
4,
]"#;
test_bidir(input, expected); test_bidir(input, expected);
} }
#[test] #[test]
fn test_seqlist() { fn test_seqlist() {
let input = vec![(1, 2), (2, 3), (3, 4), (5, 6)]; let input = vec![(1, 2), (2, 3), (3, 4), (5, 6)];
let expected = r#"[ let expected = r#"[1 2,2 3,3 4,5 6]"#;
1 2,
2 3,
3 4,
5 6,
]"#;
test_bidir(input, expected); test_bidir(input, expected);
} }
@ -159,26 +127,13 @@ mod tests {
let mut input = HashMap::new(); let mut input = HashMap::new();
input.insert("hello".to_string(), "world".to_string()); input.insert("hello".to_string(), "world".to_string());
input.insert("dont".to_string(), "panic".to_string()); input.insert("dont".to_string(), "panic".to_string());
let expected = r#"{ let expected = r#"{ZG9udA=cGFuaWM,aGVsbG8=d29ybGQ}"#;
ZG9udA = cGFuaWM,
aGVsbG8 = d29ybGQ,
}"#;
test_bidir(input, expected); test_bidir(input, expected);
let mut input = HashMap::new(); let mut input = HashMap::new();
input.insert(12, vec![42, 125]); input.insert(12, vec![42, 125]);
input.insert(33, vec![19, 22, 21]); input.insert(33, vec![19, 22, 21]);
let expected = r#"{ let expected = r#"{12=[42,125],33=[19,22,21]}"#;
12 = [
42,
125,
],
33 = [
19,
22,
21,
],
}"#;
test_bidir(input, expected); test_bidir(input, expected);
} }
} }