New concise encoding
This commit is contained in:
parent
abc27adea4
commit
52f6bd177c
3 changed files with 88 additions and 67 deletions
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -100,7 +85,7 @@ mod tests {
|
|||
test_bidir(input, expected);
|
||||
|
||||
let input = E::Struct { a: 1 };
|
||||
let expected = r#"E.Struct { a = 1 }"#;
|
||||
let expected = r#"E.Struct {a=1}"#;
|
||||
test_bidir(input, expected);
|
||||
|
||||
let input = vec![
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue