1use crate::error::{Error, Result};
19use std::fmt;
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum Element {
24 SectionStart(String),
26 SectionEnd,
28 KeyValue(String, Vec<u8>),
30 ListStart(String),
32 ListItem(Vec<u8>),
34 ListEnd,
36}
37
38impl Element {
39 fn encode_into(&self, out: &mut Vec<u8>) -> Result<()> {
40 match self {
41 Element::SectionStart(name) => {
42 out.push(1);
43 encode_name(out, name)?;
44 }
45 Element::SectionEnd => out.push(2),
46 Element::KeyValue(name, val) => {
47 out.push(3);
48 encode_name(out, name)?;
49 encode_value(out, val)?;
50 }
51 Element::ListStart(name) => {
52 out.push(4);
53 encode_name(out, name)?;
54 }
55 Element::ListItem(val) => {
56 out.push(5);
57 encode_value(out, val)?;
58 }
59 Element::ListEnd => out.push(6),
60 }
61 Ok(())
62 }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, Default)]
68pub struct Message {
69 elements: Vec<Element>,
70}
71
72impl Message {
73 pub fn new() -> Self {
75 Self {
76 elements: Vec::new(),
77 }
78 }
79
80 pub fn elements(&self) -> &[Element] {
82 &self.elements
83 }
84
85 pub fn push(&mut self, el: Element) {
87 self.elements.push(el);
88 }
89
90 pub fn kv_str(mut self, name: impl Into<String>, value: impl AsRef<str>) -> Self {
92 self.elements.push(Element::KeyValue(
93 name.into(),
94 value.as_ref().as_bytes().to_vec(),
95 ));
96 self
97 }
98
99 pub fn kv_bytes(mut self, name: impl Into<String>, value: impl AsRef<[u8]>) -> Self {
101 self.elements
102 .push(Element::KeyValue(name.into(), value.as_ref().to_vec()));
103 self
104 }
105
106 pub fn section_start(mut self, name: impl Into<String>) -> Self {
108 self.elements.push(Element::SectionStart(name.into()));
109 self
110 }
111
112 pub fn section_end(mut self) -> Self {
114 self.elements.push(Element::SectionEnd);
115 self
116 }
117
118 pub fn list_start(mut self, name: impl Into<String>) -> Self {
120 self.elements.push(Element::ListStart(name.into()));
121 self
122 }
123
124 pub fn list_item_str(mut self, value: impl AsRef<str>) -> Self {
126 self.elements
127 .push(Element::ListItem(value.as_ref().as_bytes().to_vec()));
128 self
129 }
130
131 pub fn list_item_bytes(mut self, value: impl AsRef<[u8]>) -> Self {
133 self.elements
134 .push(Element::ListItem(value.as_ref().to_vec()));
135 self
136 }
137
138 pub fn list_end(mut self) -> Self {
140 self.elements.push(Element::ListEnd);
141 self
142 }
143
144 pub fn encode(&self) -> Result<Vec<u8>> {
146 let mut out = Vec::with_capacity(self.elements.len() * 8);
147 for el in &self.elements {
148 el.encode_into(&mut out)?;
149 }
150 Ok(out)
151 }
152
153 pub fn decode(mut bytes: &[u8]) -> Result<Self> {
155 let mut elements = Vec::new();
156 while !bytes.is_empty() {
157 let (el, rest) = decode_element(bytes)?;
158 elements.push(el);
159 bytes = rest;
160 }
161 Ok(Self { elements })
162 }
163}
164
165fn encode_name(out: &mut Vec<u8>, name: &str) -> Result<()> {
166 let bytes = name.as_bytes();
167 if bytes.len() > u8::MAX as usize {
168 return Err(Error::TooLong("element name"));
169 }
170 out.push(bytes.len() as u8);
171 out.extend_from_slice(bytes);
172 Ok(())
173}
174
175fn encode_value(out: &mut Vec<u8>, value: &[u8]) -> Result<()> {
176 if value.len() > u16::MAX as usize {
177 return Err(Error::TooLong("element value"));
178 }
179 out.extend_from_slice(&(value.len() as u16).to_be_bytes());
180 out.extend_from_slice(value);
181 Ok(())
182}
183
184fn decode_u8(input: &[u8]) -> Result<(u8, &[u8])> {
185 if input.is_empty() {
186 return Err(Error::Protocol("unexpected EOF reading u8"));
187 }
188 Ok((input[0], &input[1..]))
189}
190
191fn decode_be_u16(input: &[u8]) -> Result<(u16, &[u8])> {
192 if input.len() < 2 {
193 return Err(Error::Protocol("unexpected EOF reading u16"));
194 }
195 let v = u16::from_be_bytes([input[0], input[1]]);
196 Ok((v, &input[2..]))
197}
198
199fn take(input: &[u8], n: usize) -> Result<(&[u8], &[u8])> {
200 if input.len() < n {
201 return Err(Error::Protocol("unexpected EOF taking slice"));
202 }
203 Ok((&input[..n], &input[n..]))
204}
205
206fn decode_name(input: &[u8]) -> Result<(String, &[u8])> {
207 let (len, input) = decode_u8(input)?;
208 let (name_bytes, rest) = take(input, len as usize)?;
209 Ok((String::from_utf8(name_bytes.to_vec())?, rest))
210}
211
212fn decode_value(input: &[u8]) -> Result<(Vec<u8>, &[u8])> {
213 let (len, input) = decode_be_u16(input)?;
214 let (value, rest) = take(input, len as usize)?;
215 Ok((value.to_vec(), rest))
216}
217
218fn decode_element(input: &[u8]) -> Result<(Element, &[u8])> {
219 let (tag, input) = decode_u8(input)?;
220 match tag {
221 1 => {
222 let (name, rest) = decode_name(input)?;
224 Ok((Element::SectionStart(name), rest))
225 }
226 2 => Ok((Element::SectionEnd, input)),
227 3 => {
228 let (name, input) = decode_name(input)?;
229 let (value, rest) = decode_value(input)?;
230 Ok((Element::KeyValue(name, value), rest))
231 }
232 4 => {
233 let (name, rest) = decode_name(input)?;
234 Ok((Element::ListStart(name), rest))
235 }
236 5 => {
237 let (value, rest) = decode_value(input)?;
238 Ok((Element::ListItem(value), rest))
239 }
240 6 => Ok((Element::ListEnd, input)),
241 _ => Err(Error::Protocol("unknown message element tag")),
242 }
243}
244
245impl fmt::Display for Message {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 for el in &self.elements {
248 match el {
249 Element::SectionStart(n) => writeln!(f, "<section {n}>")?,
250 Element::SectionEnd => writeln!(f, "</section>")?,
251 Element::KeyValue(k, v) => match String::from_utf8(v.clone()) {
252 Ok(s) => writeln!(f, "{k} = {s}")?,
253 Err(_) => writeln!(f, "{k} = 0x{}", hex(v))?,
254 },
255 Element::ListStart(n) => writeln!(f, "<list {n}>")?,
256 Element::ListItem(v) => match String::from_utf8(v.clone()) {
257 Ok(s) => writeln!(f, "- {s}")?,
258 Err(_) => writeln!(f, "- 0x{}", hex(v))?,
259 },
260 Element::ListEnd => writeln!(f, "</list>")?,
261 }
262 }
263 Ok(())
264 }
265}
266
267fn hex(bytes: &[u8]) -> String {
268 const HEX: &[u8; 16] = b"0123456789abcdef";
269 let mut s = String::with_capacity(bytes.len() * 2);
270 for &b in bytes {
271 s.push(HEX[(b >> 4) as usize] as char);
272 s.push(HEX[(b & 0x0F) as usize] as char);
273 }
274 s
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280
281 #[test]
282 fn roundtrip_simple_message() {
283 let msg = Message::new()
284 .section_start("root")
285 .kv_str("key", "value")
286 .list_start("ids")
287 .list_item_str("a")
288 .list_item_str("b")
289 .list_end()
290 .section_end();
291
292 let encoded = msg.encode().unwrap();
293 let decoded = Message::decode(&encoded).unwrap();
294 assert_eq!(msg, decoded);
295 }
296}