1use crate::error::{Error, Result};
10
11#[must_use]
13#[allow(clippy::manual_div_ceil)] pub fn align_up(n: usize, align: usize) -> usize {
15 (n + align - 1) & !(align - 1)
16}
17
18pub fn put_u8(out: &mut Vec<u8>, v: u8) {
20 out.push(v);
21}
22pub fn put_u16(out: &mut Vec<u8>, v: u16) {
24 out.extend_from_slice(&v.to_le_bytes());
25}
26pub fn put_u32(out: &mut Vec<u8>, v: u32) {
28 out.extend_from_slice(&v.to_le_bytes());
29}
30pub fn put_u64(out: &mut Vec<u8>, v: u64) {
32 out.extend_from_slice(&v.to_le_bytes());
33}
34pub fn put_str(out: &mut Vec<u8>, s: &str) {
36 debug_assert!(u16::try_from(s.len()).is_ok());
37 put_u16(out, s.len() as u16);
38 out.extend_from_slice(s.as_bytes());
39}
40pub fn put_blob(out: &mut Vec<u8>, s: &str) {
42 put_len_prefixed(out, s.as_bytes());
43}
44pub fn put_len_prefixed(out: &mut Vec<u8>, bytes: &[u8]) {
46 put_u32(out, u32::try_from(bytes.len()).unwrap_or(u32::MAX));
47 out.extend_from_slice(bytes);
48}
49pub fn put_f32(out: &mut Vec<u8>, v: f32) {
51 put_u32(out, v.to_bits());
52}
53pub fn put_varint(out: &mut Vec<u8>, mut v: u64) {
55 loop {
56 let byte = (v & 0x7f) as u8;
57 v >>= 7;
58 if v == 0 {
59 out.push(byte);
60 return;
61 }
62 out.push(byte | 0x80);
63 }
64}
65
66#[must_use]
68pub fn get_u16(bytes: &[u8], off: usize) -> u16 {
69 u16::from_le_bytes([bytes[off], bytes[off + 1]])
70}
71#[must_use]
73pub fn get_u32(bytes: &[u8], off: usize) -> u32 {
74 u32::from_le_bytes([bytes[off], bytes[off + 1], bytes[off + 2], bytes[off + 3]])
75}
76#[must_use]
78pub fn get_u64(bytes: &[u8], off: usize) -> u64 {
79 let mut b = [0u8; 8];
80 b.copy_from_slice(&bytes[off..off + 8]);
81 u64::from_le_bytes(b)
82}
83
84#[derive(Debug)]
86pub struct Reader<'a> {
87 bytes: &'a [u8],
88 pos: usize,
89}
90
91impl<'a> Reader<'a> {
92 #[must_use]
94 pub fn new(bytes: &'a [u8]) -> Self {
95 Self { bytes, pos: 0 }
96 }
97
98 #[must_use]
102 pub fn remaining(&self) -> usize {
103 self.bytes.len() - self.pos
104 }
105
106 fn take(&mut self, n: usize) -> Result<&'a [u8]> {
107 let end =
108 self.pos.checked_add(n).filter(|&e| e <= self.bytes.len()).ok_or_else(|| {
109 Error::format(format!("truncated: need {n} bytes at {}", self.pos))
110 })?;
111 let out = &self.bytes[self.pos..end];
112 self.pos = end;
113 Ok(out)
114 }
115
116 pub fn u8(&mut self) -> Result<u8> {
118 Ok(self.take(1)?[0])
119 }
120 pub fn u16(&mut self) -> Result<u16> {
122 let b = self.take(2)?;
123 Ok(u16::from_le_bytes([b[0], b[1]]))
124 }
125 pub fn u32(&mut self) -> Result<u32> {
127 let b = self.take(4)?;
128 Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
129 }
130 pub fn u64(&mut self) -> Result<u64> {
132 let b = self.take(8)?;
133 let mut a = [0u8; 8];
134 a.copy_from_slice(b);
135 Ok(u64::from_le_bytes(a))
136 }
137 pub fn f32(&mut self) -> Result<f32> {
139 Ok(f32::from_bits(self.u32()?))
140 }
141 pub fn len_prefixed(&mut self) -> Result<&'a [u8]> {
143 let len = self.u32()? as usize;
144 self.take(len)
145 }
146 pub fn bytes(&mut self, n: usize) -> Result<&'a [u8]> {
148 self.take(n)
149 }
150 pub fn str(&mut self) -> Result<&'a str> {
152 let len = usize::from(self.u16()?);
153 let raw = self.take(len)?;
154 std::str::from_utf8(raw).map_err(|_| Error::format("invalid utf-8 in string"))
155 }
156 pub fn blob(&mut self) -> Result<&'a str> {
158 let raw = self.len_prefixed()?;
159 std::str::from_utf8(raw).map_err(|_| Error::format("invalid utf-8 in blob"))
160 }
161 pub fn varint(&mut self) -> Result<u64> {
163 let mut v: u64 = 0;
164 for shift in (0..64).step_by(7) {
165 let byte = self.u8()?;
166 v |= u64::from(byte & 0x7f) << shift;
167 if byte & 0x80 == 0 {
168 return Ok(v);
169 }
170 }
171 Err(Error::format("varint overlong"))
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn round_trips_all_widths() {
181 let mut out = Vec::new();
182 put_u8(&mut out, 7);
183 put_u16(&mut out, 300);
184 put_u32(&mut out, 70_000);
185 put_u64(&mut out, u64::MAX - 1);
186 put_str(&mut out, "héllo");
187 put_varint(&mut out, 0);
188 put_varint(&mut out, 127);
189 put_varint(&mut out, 128);
190 put_varint(&mut out, u64::MAX);
191
192 let mut r = Reader::new(&out);
193 assert_eq!(r.u8().unwrap(), 7);
194 assert_eq!(r.u16().unwrap(), 300);
195 assert_eq!(r.u32().unwrap(), 70_000);
196 assert_eq!(r.u64().unwrap(), u64::MAX - 1);
197 assert_eq!(r.str().unwrap(), "héllo");
198 assert_eq!(r.varint().unwrap(), 0);
199 assert_eq!(r.varint().unwrap(), 127);
200 assert_eq!(r.varint().unwrap(), 128);
201 assert_eq!(r.varint().unwrap(), u64::MAX);
202 assert_eq!(r.remaining(), 0);
203 }
204
205 #[test]
206 fn truncation_is_an_error_never_a_panic() {
207 let mut out = Vec::new();
208 put_str(&mut out, "abcdef");
209 for cut in 0..out.len() {
210 let mut r = Reader::new(&out[..cut]);
211 assert!(r.str().is_err() || cut >= out.len());
212 }
213 let mut r = Reader::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
214 assert!(r.varint().is_err(), "overlong varint rejected");
215 }
216
217 #[test]
218 fn invalid_utf8_is_a_format_error() {
219 let mut out = Vec::new();
220 put_u16(&mut out, 2);
221 out.extend_from_slice(&[0xff, 0xfe]);
222 assert!(Reader::new(&out).str().is_err());
223 }
224
225 #[test]
226 fn align_up_works() {
227 assert_eq!(align_up(0, 64), 0);
228 assert_eq!(align_up(1, 64), 64);
229 assert_eq!(align_up(64, 64), 64);
230 assert_eq!(align_up(65, 64), 128);
231 }
232}