1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::Result;
use crate::serialize::{Serialize, SerializeInto, generic_serialize_into};
use crate::crypto::sexp::{Sexp, String_};
impl Serialize for Sexp {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
match self {
Sexp::String(ref s) => s.serialize(o),
Sexp::List(ref l) => {
write!(o, "(")?;
for sexp in l {
sexp.serialize(o)?;
}
write!(o, ")")?;
Ok(())
},
}
}
}
impl SerializeInto for Sexp {
fn serialized_len(&self) -> usize {
match self {
Sexp::String(ref s) => s.serialized_len(),
Sexp::List(ref l) =>
2 + l.iter().map(|s| s.serialized_len()).sum::<usize>(),
}
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
impl Serialize for String_ {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
if let Some(display) = self.display_hint() {
write!(o, "[{}:", display.len())?;
o.write_all(display)?;
write!(o, "]")?;
}
write!(o, "{}:", self.len())?;
o.write_all(self)?;
Ok(())
}
}
fn size_tag_len(len: usize) -> usize {
let mut l = len;
let mut digits = 0;
while l > 0 {
l /= 10;
digits += 1;
}
std::cmp::max(1, digits)
}
impl SerializeInto for String_ {
fn serialized_len(&self) -> usize {
self.display_hint()
.map(|d| size_tag_len(d.len()) + 3 + d.len()).unwrap_or(0)
+ size_tag_len(self.len()) + 1 + self.len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
generic_serialize_into(self, buf)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sexp() {
assert_eq!(
&Sexp::List(vec![]).to_vec().unwrap(),
b"()");
assert_eq!(
&Sexp::List(vec![Sexp::String(b"hi"[..].into()),
Sexp::String(b"ho"[..].into()),
]).to_vec().unwrap(),
b"(2:hi2:ho)");
assert_eq!(
&Sexp::List(vec![
Sexp::String(b"hi"[..].into()),
Sexp::String(String_::with_display_hint(b"ho".to_vec(),
b"fancy".to_vec())),
]).to_vec().unwrap(),
b"(2:hi[5:fancy]2:ho)");
assert_eq!(
&Sexp::List(vec![
Sexp::String(b"hi"[..].into()),
Sexp::List(vec![
Sexp::String(b"ha"[..].into()),
Sexp::String(b"ho"[..].into()),
]),
]).to_vec().unwrap(),
b"(2:hi(2:ha2:ho))");
assert_eq!(
&Sexp::List(vec![
Sexp::String(b"sig-val"[..].into()),
Sexp::List(vec![
Sexp::String(b"rsa"[..].into()),
Sexp::List(vec![
Sexp::String(b"s"[..].into()),
Sexp::String(b"abc"[..].into()),
]),
]),
]).to_vec().unwrap(),
b"(7:sig-val(3:rsa(1:s3:abc)))");
}
#[test]
fn string() {
assert_eq!(&String_::new(b"hi".to_vec()).to_vec().unwrap(),
b"2:hi");
assert_eq!(&String_::with_display_hint(b"hi".to_vec(),
b"fancy".to_vec())
.to_vec().unwrap(),
b"[5:fancy]2:hi");
}
}