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

View file

@ -262,6 +262,13 @@ impl<'a> Term<'a> {
pub fn encode_string(self) -> String {
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> {
@ -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)]
@ -363,6 +410,7 @@ mod tests {
.unwrap(),
])
.unwrap();
let expected = "HELLO alexhelloworld [
dude,
why,
@ -371,9 +419,27 @@ mod tests {
from = jxx,
subject = hello,
}";
let enc = input.encode();
eprintln!("{}", debug(&enc));
eprintln!("{}", expected);
assert_eq!(debug(&enc), expected);
assert_eq!(debug(&input.encode()), 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>(
input: T,
expected: &str,
expected_concise: &str,
) {
eprintln!("Expecting: {}", expected);
eprintln!("Expecting: {}", expected_concise);
let ser = to_bytes(&input).unwrap();
let ser = debug(&ser);
eprintln!("Serialized: {}", ser);
assert_eq!(ser, expected);
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]
@ -39,13 +45,7 @@ mod tests {
int: 1,
seq: vec!["a".to_string(), "b".to_string()],
};
let expected = r#"Test {
int = 1,
seq = [
YQ,
Yg,
],
}"#;
let expected = r#"Test {int=1,seq=[YQ,Yg]}"#;
test_bidir(input, expected);
let input = vec![
@ -58,22 +58,7 @@ mod tests {
seq: vec!["c".to_string(), "d".to_string()],
},
];
let expected = r#"[
Test {
int = 1,
seq = [
YQ,
Yg,
],
},
Test {
int = 2,
seq = [
Yw,
ZA,
],
},
]"#;
let expected = r#"[Test {int=1,seq=[YQ,Yg]},Test {int=2,seq=[Yw,ZA]}]"#;
test_bidir(input, expected);
}
@ -112,14 +97,7 @@ mod tests {
E::Tuple(3, 2),
];
let expected =
r#"[
E.Unit,
E.Unit,
E.Newtype 1,
E.Tuple 1 2,
E.Struct { a = 1 },
E.Tuple 3 2,
]"#;
r#"[E.Unit,E.Unit,E.Newtype 1,E.Tuple 1 2,E.Struct {a=1},E.Tuple 3 2]"#;
test_bidir(input, expected);
}
@ -133,24 +111,14 @@ mod tests {
#[test]
fn test_list() {
let input = vec![1, 2, 3, 4];
let expected = r#"[
1,
2,
3,
4,
]"#;
let expected = r#"[1,2,3,4]"#;
test_bidir(input, expected);
}
#[test]
fn test_seqlist() {
let input = vec![(1, 2), (2, 3), (3, 4), (5, 6)];
let expected = r#"[
1 2,
2 3,
3 4,
5 6,
]"#;
let expected = r#"[1 2,2 3,3 4,5 6]"#;
test_bidir(input, expected);
}
@ -159,26 +127,13 @@ mod tests {
let mut input = HashMap::new();
input.insert("hello".to_string(), "world".to_string());
input.insert("dont".to_string(), "panic".to_string());
let expected = r#"{
ZG9udA = cGFuaWM,
aGVsbG8 = d29ybGQ,
}"#;
let expected = r#"{ZG9udA=cGFuaWM,aGVsbG8=d29ybGQ}"#;
test_bidir(input, expected);
let mut input = HashMap::new();
input.insert(12, vec![42, 125]);
input.insert(33, vec![19, 22, 21]);
let expected = r#"{
12 = [
42,
125,
],
33 = [
19,
22,
21,
],
}"#;
let expected = r#"{12=[42,125],33=[19,22,21]}"#;
test_bidir(input, expected);
}
}