1use bcp_wire::varint::{decode_varint, encode_varint};
2
3use crate::error::TypeError;
4
5#[derive(Clone, Debug, PartialEq, Eq)]
25pub struct Summary {
26 pub text: String,
27}
28
29const MAX_VARINT_LEN: usize = 10;
31
32impl Summary {
33 pub fn encode(&self, buf: &mut Vec<u8>) {
38 let mut scratch = [0u8; MAX_VARINT_LEN];
39 let n = encode_varint(self.text.len() as u64, &mut scratch);
40 buf.extend_from_slice(&scratch[..n]);
41 buf.extend_from_slice(self.text.as_bytes());
42 }
43
44 pub fn decode(buf: &[u8]) -> Result<(Self, usize), TypeError> {
49 let (len, n) = decode_varint(buf)?;
50 let len = len as usize;
51 let text_bytes = buf
52 .get(n..n + len)
53 .ok_or(bcp_wire::WireError::UnexpectedEof { offset: n })?;
54 let text = String::from_utf8_lossy(text_bytes).into_owned();
55 Ok((Self { text }, n + len))
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62
63 #[test]
64 fn roundtrip_summary() {
65 let summary = Summary {
66 text: "This block contains the main entry point.".to_string(),
67 };
68 let mut buf = Vec::new();
69 summary.encode(&mut buf);
70
71 let (decoded, consumed) = Summary::decode(&buf).unwrap();
72 assert_eq!(decoded, summary);
73 assert_eq!(consumed, buf.len());
74 }
75
76 #[test]
77 fn roundtrip_empty_summary() {
78 let summary = Summary {
79 text: String::new(),
80 };
81 let mut buf = Vec::new();
82 summary.encode(&mut buf);
83
84 let (decoded, consumed) = Summary::decode(&buf).unwrap();
85 assert_eq!(decoded, summary);
86 assert_eq!(consumed, buf.len());
87 }
88
89 #[test]
90 fn summary_followed_by_other_data() {
91 let summary = Summary {
92 text: "short".to_string(),
93 };
94 let mut buf = Vec::new();
95 summary.encode(&mut buf);
96 buf.extend_from_slice(b"remaining TLV data");
97
98 let (decoded, consumed) = Summary::decode(&buf).unwrap();
99 assert_eq!(decoded.text, "short");
100 assert_eq!(&buf[consumed..], b"remaining TLV data");
101 }
102}