iris_abi/wire.rs
1//! Reading and writing the primitive values that ABI records are built out of.
2//!
3//! Everything on the wire is little-endian, because every machine anyone is going to run this on
4//! is little-endian and pretending otherwise would cost real instructions in the hot path for a
5//! portability nobody is asking for. If that ever stops being true it is a new ABI major version,
6//! not a runtime flag.
7//!
8//! Variable-length fields are padded so that the cursor lands back on a multiple of eight. That
9//! costs at most seven bytes per field and it means a later version of this crate can read a fixed
10//! width run of a record by pointing at it instead of copying it out field by field.
11
12use crate::error::{Error, Result};
13
14/// How wide the alignment of a record payload is, in bytes.
15///
16/// Record headers are exactly this wide too, so a record that starts aligned has a payload that
17/// starts aligned.
18pub const ALIGN: usize = 8;
19
20/// Rounds `n` up to the next multiple of [`ALIGN`].
21#[must_use]
22pub const fn align_up(n: usize) -> usize {
23 n.next_multiple_of(ALIGN)
24}
25
26/// A cursor that reads ABI values out of a byte slice.
27///
28/// The reader borrows its input and hands back borrowed slices, so decoding a record does not
29/// allocate and does not copy the payload.
30#[derive(Clone, Debug)]
31pub struct Reader<'a> {
32 buf: &'a [u8],
33 pos: usize,
34}
35
36impl<'a> Reader<'a> {
37 /// Starts reading at the beginning of `buf`.
38 #[must_use]
39 pub const fn new(buf: &'a [u8]) -> Self {
40 Self { buf, pos: 0 }
41 }
42
43 /// How many bytes are left.
44 #[must_use]
45 pub const fn remaining(&self) -> usize {
46 self.buf.len() - self.pos
47 }
48
49 /// Whether the reader has consumed everything.
50 #[must_use]
51 pub const fn is_empty(&self) -> bool {
52 self.remaining() == 0
53 }
54
55 /// How far into the buffer the cursor is.
56 #[must_use]
57 pub const fn position(&self) -> usize {
58 self.pos
59 }
60
61 fn take(&mut self, n: usize) -> Result<&'a [u8]> {
62 let available = self.remaining();
63 if n > available {
64 return Err(Error::Truncated {
65 needed: n,
66 available,
67 });
68 }
69 let out = &self.buf[self.pos..self.pos + n];
70 self.pos += n;
71 Ok(out)
72 }
73
74 /// Reads one byte.
75 ///
76 /// # Errors
77 ///
78 /// Returns [`Error::Truncated`] if the buffer is exhausted.
79 pub fn u8(&mut self) -> Result<u8> {
80 Ok(self.take(1)?[0])
81 }
82
83 /// Reads a little-endian `u16`.
84 ///
85 /// # Errors
86 ///
87 /// Returns [`Error::Truncated`] if fewer than two bytes are left.
88 pub fn u16(&mut self) -> Result<u16> {
89 let b = self.take(2)?;
90 Ok(u16::from_le_bytes([b[0], b[1]]))
91 }
92
93 /// Reads a little-endian `u32`.
94 ///
95 /// # Errors
96 ///
97 /// Returns [`Error::Truncated`] if fewer than four bytes are left.
98 pub fn u32(&mut self) -> Result<u32> {
99 let b = self.take(4)?;
100 Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
101 }
102
103 /// Reads a little-endian `u64`.
104 ///
105 /// # Errors
106 ///
107 /// Returns [`Error::Truncated`] if fewer than eight bytes are left.
108 pub fn u64(&mut self) -> Result<u64> {
109 let b = self.take(8)?;
110 Ok(u64::from_le_bytes([
111 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
112 ]))
113 }
114
115 /// Reads a `u64` that a later version of a record appended, if the writer knew about it.
116 ///
117 /// This is the other half of the grow-at-the-end rule. A reader that does not care about a new
118 /// field just stops early and the framing puts it on the next record. A reader that does care
119 /// has to tell two situations apart: a writer that predates the field, which is fine and means
120 /// the field is absent, and a payload that was cut in half, which is not fine. Nothing left is
121 /// the first, something but not enough is the second.
122 ///
123 /// # Errors
124 ///
125 /// Returns [`Error::Truncated`] if there is at least one byte left but fewer than eight.
126 pub fn opt_u64(&mut self) -> Result<Option<u64>> {
127 if self.is_empty() {
128 return Ok(None);
129 }
130 self.u64().map(Some)
131 }
132
133 /// Reads exactly `n` bytes and borrows them from the input.
134 ///
135 /// # Errors
136 ///
137 /// Returns [`Error::Truncated`] if fewer than `n` bytes are left.
138 pub fn bytes(&mut self, n: usize) -> Result<&'a [u8]> {
139 self.take(n)
140 }
141
142 /// Skips `n` bytes.
143 ///
144 /// This is how a reader gets past a field it does not understand, which is the whole reason the
145 /// format carries lengths.
146 ///
147 /// # Errors
148 ///
149 /// Returns [`Error::Truncated`] if fewer than `n` bytes are left.
150 pub fn skip(&mut self, n: usize) -> Result<()> {
151 self.take(n).map(|_| ())
152 }
153
154 /// Skips forward to the next alignment boundary.
155 ///
156 /// # Errors
157 ///
158 /// Returns [`Error::Truncated`] if the padding runs off the end of the buffer.
159 pub fn align(&mut self) -> Result<()> {
160 self.skip(align_up(self.pos) - self.pos)
161 }
162
163 /// Reads a length-prefixed byte string, including its trailing padding.
164 ///
165 /// # Errors
166 ///
167 /// Returns [`Error::Truncated`] if the buffer ends inside the field, or
168 /// [`Error::LengthOverflow`] if the declared length does not fit in a `usize`.
169 pub fn var_bytes(&mut self) -> Result<&'a [u8]> {
170 let len = self.u32()?;
171 let len = usize::try_from(len).map_err(|_| Error::LengthOverflow)?;
172 let out = self.take(len)?;
173 self.align()?;
174 Ok(out)
175 }
176
177 /// Reads a length-prefixed UTF-8 string.
178 ///
179 /// # Errors
180 ///
181 /// Returns [`Error::NotUtf8`] if the bytes are not valid UTF-8, or the same errors as
182 /// [`Reader::var_bytes`].
183 pub fn var_str(&mut self) -> Result<&'a str> {
184 core::str::from_utf8(self.var_bytes()?).map_err(|_| Error::NotUtf8)
185 }
186
187 /// Splits off a reader over the next `n` bytes and steps this one past them.
188 ///
189 /// # Errors
190 ///
191 /// Returns [`Error::Truncated`] if fewer than `n` bytes are left.
192 pub fn sub(&mut self, n: usize) -> Result<Reader<'a>> {
193 Ok(Reader::new(self.take(n)?))
194 }
195}
196
197/// A cursor that writes ABI values into a byte slice.
198///
199/// The writer never grows its buffer. A caller that does not know how big a record will be should
200/// size the buffer with [`Writer::position`] on a dry run, or just use a buffer big enough for the
201/// largest record the ABI allows.
202#[derive(Debug)]
203pub struct Writer<'a> {
204 buf: &'a mut [u8],
205 pos: usize,
206}
207
208impl<'a> Writer<'a> {
209 /// Starts writing at the beginning of `buf`.
210 #[must_use]
211 pub fn new(buf: &'a mut [u8]) -> Self {
212 Self { buf, pos: 0 }
213 }
214
215 /// How many bytes have been written.
216 #[must_use]
217 pub const fn position(&self) -> usize {
218 self.pos
219 }
220
221 /// How much room is left.
222 #[must_use]
223 pub const fn remaining(&self) -> usize {
224 self.buf.len() - self.pos
225 }
226
227 /// Everything written so far.
228 #[must_use]
229 pub fn written(&self) -> &[u8] {
230 &self.buf[..self.pos]
231 }
232
233 fn room(&mut self, n: usize) -> Result<usize> {
234 let available = self.remaining();
235 if n > available {
236 return Err(Error::BufferFull {
237 needed: n,
238 available,
239 });
240 }
241 let at = self.pos;
242 self.pos += n;
243 Ok(at)
244 }
245
246 /// Writes one byte.
247 ///
248 /// # Errors
249 ///
250 /// Returns [`Error::BufferFull`] if there is no room.
251 pub fn u8(&mut self, v: u8) -> Result<()> {
252 let at = self.room(1)?;
253 self.buf[at] = v;
254 Ok(())
255 }
256
257 /// Writes a little-endian `u16`.
258 ///
259 /// # Errors
260 ///
261 /// Returns [`Error::BufferFull`] if there is no room.
262 pub fn u16(&mut self, v: u16) -> Result<()> {
263 self.raw(&v.to_le_bytes())
264 }
265
266 /// Writes a little-endian `u32`.
267 ///
268 /// # Errors
269 ///
270 /// Returns [`Error::BufferFull`] if there is no room.
271 pub fn u32(&mut self, v: u32) -> Result<()> {
272 self.raw(&v.to_le_bytes())
273 }
274
275 /// Writes a little-endian `u64`.
276 ///
277 /// # Errors
278 ///
279 /// Returns [`Error::BufferFull`] if there is no room.
280 pub fn u64(&mut self, v: u64) -> Result<()> {
281 self.raw(&v.to_le_bytes())
282 }
283
284 /// Writes bytes with no length prefix and no padding.
285 ///
286 /// # Errors
287 ///
288 /// Returns [`Error::BufferFull`] if there is no room.
289 pub fn raw(&mut self, v: &[u8]) -> Result<()> {
290 let at = self.room(v.len())?;
291 self.buf[at..at + v.len()].copy_from_slice(v);
292 Ok(())
293 }
294
295 /// Writes zeroes up to the next alignment boundary.
296 ///
297 /// # Errors
298 ///
299 /// Returns [`Error::BufferFull`] if there is no room.
300 pub fn align(&mut self) -> Result<()> {
301 let pad = align_up(self.pos) - self.pos;
302 let at = self.room(pad)?;
303 self.buf[at..at + pad].fill(0);
304 Ok(())
305 }
306
307 /// Writes a length-prefixed byte string and pads it out.
308 ///
309 /// # Errors
310 ///
311 /// Returns [`Error::BufferFull`] if there is no room, or [`Error::LengthOverflow`] if the slice
312 /// is longer than a `u32` can describe.
313 pub fn var_bytes(&mut self, v: &[u8]) -> Result<()> {
314 let len = u32::try_from(v.len()).map_err(|_| Error::LengthOverflow)?;
315 self.u32(len)?;
316 self.raw(v)?;
317 self.align()
318 }
319
320 /// Writes a length-prefixed string.
321 ///
322 /// # Errors
323 ///
324 /// Returns the same errors as [`Writer::var_bytes`].
325 pub fn var_str(&mut self, v: &str) -> Result<()> {
326 self.var_bytes(v.as_bytes())
327 }
328
329 /// Overwrites a `u32` that was already written, at absolute offset `at`.
330 ///
331 /// This exists so a record can reserve its length field, write its payload, and then fill the
332 /// length in once it is known.
333 ///
334 /// # Errors
335 ///
336 /// Returns [`Error::BufferFull`] if `at` is not inside what has been written.
337 pub fn patch_u32(&mut self, at: usize, v: u32) -> Result<()> {
338 if at + 4 > self.pos {
339 return Err(Error::BufferFull {
340 needed: at + 4,
341 available: self.pos,
342 });
343 }
344 self.buf[at..at + 4].copy_from_slice(&v.to_le_bytes());
345 Ok(())
346 }
347}