1#[derive(Default)]
6pub struct Writer {
7 buf: Vec<u8>,
8}
9
10const VARINT: u32 = 0;
11const FIXED64: u32 = 1;
12const LEN: u32 = 2;
13const START_GROUP: u32 = 3;
14const END_GROUP: u32 = 4;
15const FIXED32: u32 = 5;
16
17impl Writer {
18 pub fn into_bytes(self) -> Vec<u8> {
19 self.buf
20 }
21
22 fn varint(&mut self, mut value: u64) {
23 while value >= 0x80 {
24 #[allow(clippy::cast_possible_truncation)]
25 self.buf.push((value as u8) | 0x80);
26 value >>= 7;
27 }
28 #[allow(clippy::cast_possible_truncation)]
29 self.buf.push(value as u8);
30 }
31
32 fn tag(&mut self, field: u32, wire_type: u32) {
33 self.varint(u64::from(field << 3 | wire_type));
34 }
35
36 pub fn uint(&mut self, field: u32, value: u64) {
37 self.tag(field, VARINT);
38 self.varint(value);
39 }
40
41 pub fn int(&mut self, field: u32, value: i64) {
43 #[allow(clippy::cast_sign_loss)]
44 self.uint(field, value as u64);
45 }
46
47 pub fn double(&mut self, field: u32, value: f64) {
48 self.tag(field, FIXED64);
49 self.buf.extend_from_slice(&value.to_bits().to_le_bytes());
50 }
51
52 pub fn bytes(&mut self, field: u32, value: &[u8]) {
53 self.tag(field, LEN);
54 self.varint(value.len() as u64);
55 self.buf.extend_from_slice(value);
56 }
57
58 pub fn message(&mut self, field: u32, write: impl FnOnce(&mut Self)) {
60 let mut inner = Self::default();
61 write(&mut inner);
62 self.bytes(field, &inner.buf);
63 }
64
65 pub fn group(&mut self, field: u32, write: impl FnOnce(&mut Self)) {
67 self.tag(field, START_GROUP);
68 write(self);
69 self.tag(field, END_GROUP);
70 }
71}
72
73#[derive(Debug, Clone, Copy)]
75pub enum Field<'a> {
76 Varint(u64),
77 Fixed64(u64),
78 Fixed32,
80 Bytes(&'a [u8]),
82 Group(&'a [u8]),
84}
85
86impl<'a> Field<'a> {
87 pub fn as_varint(self) -> Option<u64> {
88 match self {
89 Self::Varint(v) => Some(v),
90 _ => None,
91 }
92 }
93
94 pub fn as_fixed64(self) -> Option<u64> {
95 match self {
96 Self::Fixed64(v) => Some(v),
97 _ => None,
98 }
99 }
100
101 pub fn as_bytes(self) -> Option<&'a [u8]> {
102 match self {
103 Self::Bytes(b) => Some(b),
104 _ => None,
105 }
106 }
107
108 pub fn fields(self) -> Option<Reader<'a>> {
110 match self {
111 Self::Bytes(b) | Self::Group(b) => Some(Reader::new(b)),
112 _ => None,
113 }
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119pub struct Malformed;
120
121#[derive(Debug, Clone)]
123pub struct Reader<'a> {
124 data: &'a [u8],
125 pos: usize,
126}
127
128impl<'a> Reader<'a> {
129 pub fn new(data: &'a [u8]) -> Self {
130 Self { data, pos: 0 }
131 }
132
133 fn varint(&mut self) -> Result<u64, Malformed> {
134 let mut value = 0u64;
135 for shift in (0..64).step_by(7) {
136 let byte = *self.data.get(self.pos).ok_or(Malformed)?;
137 self.pos += 1;
138 value |= u64::from(byte & 0x7f) << shift;
139 if byte < 0x80 {
140 return Ok(value);
141 }
142 }
143 Err(Malformed)
144 }
145
146 fn take(&mut self, len: usize) -> Result<&'a [u8], Malformed> {
147 let end = self.pos.checked_add(len).ok_or(Malformed)?;
148 let slice = self.data.get(self.pos..end).ok_or(Malformed)?;
149 self.pos = end;
150 Ok(slice)
151 }
152
153 fn tag(&mut self) -> Result<Option<(u32, u32)>, Malformed> {
155 if self.pos == self.data.len() {
156 return Ok(None);
157 }
158 let tag = u32::try_from(self.varint()?).map_err(|_| Malformed)?;
159 if tag >> 3 == 0 {
160 return Err(Malformed);
161 }
162 Ok(Some((tag >> 3, tag & 7)))
163 }
164
165 fn value(&mut self, field: u32, wire_type: u32) -> Result<Field<'a>, Malformed> {
166 Ok(match wire_type {
167 VARINT => Field::Varint(self.varint()?),
168 FIXED64 => Field::Fixed64(u64::from_le_bytes(
169 self.take(8)?.try_into().map_err(|_| Malformed)?,
170 )),
171 FIXED32 => {
172 self.take(4)?;
173 Field::Fixed32
174 }
175 LEN => {
176 let len = usize::try_from(self.varint()?).map_err(|_| Malformed)?;
177 Field::Bytes(self.take(len)?)
178 }
179 START_GROUP => {
180 let start = self.pos;
181 loop {
182 let end = self.pos;
183 let (inner, inner_type) = self.tag()?.ok_or(Malformed)?;
184 if inner_type == END_GROUP {
185 if inner != field {
186 return Err(Malformed);
187 }
188 return Ok(Field::Group(&self.data[start..end]));
189 }
190 self.value(inner, inner_type)?;
191 }
192 }
193 _ => return Err(Malformed),
194 })
195 }
196}
197
198impl<'a> Iterator for Reader<'a> {
199 type Item = Result<(u32, Field<'a>), Malformed>;
200
201 fn next(&mut self) -> Option<Self::Item> {
202 let result = (|| {
203 let Some((field, wire_type)) = self.tag()? else {
204 return Ok(None);
205 };
206 Ok(Some((field, self.value(field, wire_type)?)))
207 })();
208 match result {
209 Ok(Some(item)) => Some(Ok(item)),
210 Ok(None) => None,
211 Err(err) => {
212 self.pos = self.data.len();
214 Some(Err(err))
215 }
216 }
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223
224 #[test]
225 fn groups_nest_and_round_trip() {
226 let mut w = Writer::default();
227 w.uint(1, 300);
228 w.group(12, |g| {
229 g.bytes(13, b"app");
230 g.group(14, |e| {
231 e.bytes(15, b"kind");
232 e.int(16, -3);
233 });
234 });
235 w.double(4, 1.5);
236 let bytes = w.into_bytes();
237
238 let fields: Vec<_> = Reader::new(&bytes).collect::<Result<_, _>>().unwrap();
239 assert_eq!(fields.len(), 3);
240 assert_eq!(fields[0].1.as_varint(), Some(300));
241 let reference: Vec<_> = fields[1]
242 .1
243 .fields()
244 .unwrap()
245 .collect::<Result<_, _>>()
246 .unwrap();
247 assert_eq!(reference[0].1.as_bytes(), Some(&b"app"[..]));
248 let element: Vec<_> = reference[1]
249 .1
250 .fields()
251 .unwrap()
252 .collect::<Result<_, _>>()
253 .unwrap();
254 #[allow(clippy::cast_possible_wrap)]
255 let id = element[1].1.as_varint().unwrap() as i64;
256 assert_eq!(id, -3);
257 assert_eq!(fields[2].1.as_fixed64(), Some(1.5f64.to_bits()));
258 }
259
260 #[test]
261 fn truncated_input_is_malformed() {
262 let mut w = Writer::default();
263 w.bytes(3, b"hello");
264 let bytes = w.into_bytes();
265 assert!(Reader::new(&bytes[..4]).any(|f| f.is_err()));
266 assert!(Reader::new(&[0x63, 0x08, 0x01]).any(|f| f.is_err()));
268 }
269}