Skip to main content

weaveffi/abi/
buffer.rs

1//! The WeaveFFI value-buffer protocol: the by-value serialization format
2//! records, rich enums, optionals, lists, maps, and error payloads use to
3//! cross the C ABI.
4//!
5//! A *buffered* value crosses the boundary as one `(const uint8_t*, size_t)`
6//! slot pair containing the value serialized in this module's format, rather
7//! than as an opaque object pointer or parallel arrays. Parameters are
8//! borrowed for the duration of the call (the consumer owns and frees its own
9//! encoding); returns are producer-allocated and released by the consumer
10//! with `{prefix}_free_bytes` after decoding.
11//!
12//! # Encoding
13//!
14//! All multi-byte values are **little-endian**. There is no padding and no
15//! alignment; values are packed back to back.
16//!
17//! | IDL type            | Encoding                                            |
18//! |---------------------|-----------------------------------------------------|
19//! | `bool`              | 1 byte: `0` or `1`                                  |
20//! | `i8`/`u8`           | 1 byte                                              |
21//! | `i16`/`u16`         | 2 bytes                                             |
22//! | `i32`/`u32`         | 4 bytes                                             |
23//! | `i64`/`u64`         | 8 bytes                                             |
24//! | `f32`               | 4 bytes (IEEE 754 bits)                             |
25//! | `f64`               | 8 bytes (IEEE 754 bits)                             |
26//! | enum (C-style)      | `i32` discriminant                                  |
27//! | interface           | `u64` object token carrying one strong reference    |
28//! | `string`            | `u32` byte length + UTF-8 bytes (no NUL terminator) |
29//! | `bytes`             | `u32` length + raw bytes                            |
30//! | `T?`                | 1 byte flag (`0` absent, `1` present) + value       |
31//! | `[T]`               | `u32` count + each element                          |
32//! | `{K:V}`             | `u32` count + alternating key, value                |
33//! | record              | each field in declaration order                     |
34//! | rich enum           | `i32` tag + active variant's fields in order        |
35//! | error payload       | the matched code's fields in declaration order      |
36//!
37//! Because the format is compositional, arbitrary nesting (`{string:[T?]}`,
38//! records containing records, objects inside lists, and so on) works with
39//! no per-shape special cases. Iterators and callback interfaces never appear
40//! inside a buffer; validation rejects them in buffered positions.
41//!
42//! An interface object is encoded as a token (see [`object`](crate::abi::object))
43//! that carries one strong reference: the writer clones the object before
44//! encoding and the reader adopts the reference. Because adopting is a
45//! side effect, a buffer holding object tokens must be decoded exactly once,
46//! and only from a buffer whose tokens are genuine. That's why
47//! [`BufferValue::read_value`] and [`decode_value`] are `unsafe`: no safe
48//! function can turn an arbitrary `u64` into an object reference. A reader
49//! built with [`BufferReader::token_free`] refuses every token instead, which
50//! makes decoding through it sound for any input.
51//!
52//! A map's encoding never repeats a key; decoding one that does fails, so a
53//! value can't silently disappear between the two sides.
54//!
55//! Encoded lengths and counts are `u32`, capping any single string, byte
56//! buffer, or collection at `u32::MAX` entries; [`BufferWriter`] panics past
57//! that bound rather than truncating.
58//!
59//! Lists of bytes and fixed-width numbers (every integer and float type, but
60//! not `bool`, whose bytes must be validated) encode and decode with a single
61//! copy on little-endian targets, and [`encode_value`] sizes its allocation
62//! exactly up front from [`BufferValue::encoded_len`].
63
64use std::sync::Arc;
65
66/// An error produced while decoding a value buffer.
67///
68/// Consumers treat a decode failure as a producer/consumer contract violation
69/// (both sides are generated from the same IDL), so this surfaces through the
70/// same channel as a producer panic: a trap, not a typed domain error.
71#[derive(Debug, Clone, PartialEq, Eq)]
72pub struct BufferDecodeError {
73    /// What the reader was trying to decode when the buffer ran out or held
74    /// invalid data.
75    pub context: &'static str,
76}
77
78impl std::fmt::Display for BufferDecodeError {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        write!(f, "malformed WeaveFFI value buffer: {}", self.context)
81    }
82}
83
84impl std::error::Error for BufferDecodeError {}
85
86/// Serializes values into the WeaveFFI buffer format.
87///
88/// The `#[weaveffi::module]` expansion writes record fields, enum payloads,
89/// collection elements, and error payloads through one of these, then hands
90/// the finished bytes across the ABI (via
91/// [`lower_bytes`](crate::abi::lower_bytes) for returns, or borrowed directly for
92/// callback arguments).
93#[derive(Debug, Default)]
94pub struct BufferWriter {
95    buf: Vec<u8>,
96}
97
98impl BufferWriter {
99    /// Create an empty writer.
100    #[must_use]
101    pub fn new() -> Self {
102        Self::default()
103    }
104
105    /// Create an empty writer with room for `capacity` bytes.
106    #[must_use]
107    pub fn with_capacity(capacity: usize) -> Self {
108        Self {
109            buf: Vec::with_capacity(capacity),
110        }
111    }
112
113    /// Consume the writer and return the encoded bytes.
114    #[must_use]
115    pub fn finish(self) -> Vec<u8> {
116        self.buf
117    }
118
119    /// Append already-encoded bytes verbatim.
120    pub fn write_raw(&mut self, bytes: &[u8]) {
121        self.buf.extend_from_slice(bytes);
122    }
123
124    /// Write a `bool` as one byte (`0` or `1`).
125    pub fn write_bool(&mut self, v: bool) {
126        self.buf.push(u8::from(v));
127    }
128
129    /// Write an `i8`.
130    pub fn write_i8(&mut self, v: i8) {
131        self.buf.extend_from_slice(&v.to_le_bytes());
132    }
133
134    /// Write a `u8`.
135    pub fn write_u8(&mut self, v: u8) {
136        self.buf.push(v);
137    }
138
139    /// Write an `i16` little-endian.
140    pub fn write_i16(&mut self, v: i16) {
141        self.buf.extend_from_slice(&v.to_le_bytes());
142    }
143
144    /// Write a `u16` little-endian.
145    pub fn write_u16(&mut self, v: u16) {
146        self.buf.extend_from_slice(&v.to_le_bytes());
147    }
148
149    /// Write an `i32` little-endian. Also the encoding of C-style enum values
150    /// and rich-enum tags.
151    pub fn write_i32(&mut self, v: i32) {
152        self.buf.extend_from_slice(&v.to_le_bytes());
153    }
154
155    /// Write a `u32` little-endian.
156    pub fn write_u32(&mut self, v: u32) {
157        self.buf.extend_from_slice(&v.to_le_bytes());
158    }
159
160    /// Write an `i64` little-endian.
161    pub fn write_i64(&mut self, v: i64) {
162        self.buf.extend_from_slice(&v.to_le_bytes());
163    }
164
165    /// Write a `u64` little-endian. Also the encoding of object tokens.
166    pub fn write_u64(&mut self, v: u64) {
167        self.buf.extend_from_slice(&v.to_le_bytes());
168    }
169
170    /// Write an `f32` as its IEEE 754 bits, little-endian.
171    pub fn write_f32(&mut self, v: f32) {
172        self.buf.extend_from_slice(&v.to_le_bytes());
173    }
174
175    /// Write an `f64` as its IEEE 754 bits, little-endian.
176    pub fn write_f64(&mut self, v: f64) {
177        self.buf.extend_from_slice(&v.to_le_bytes());
178    }
179
180    /// Write a length or element count as a `u32`.
181    ///
182    /// # Panics
183    ///
184    /// Panics when `len` exceeds `u32::MAX`; truncating would corrupt the
185    /// stream, and a value that large cannot round-trip through the format.
186    pub fn write_len(&mut self, len: usize) {
187        let len = u32::try_from(len).expect("WeaveFFI buffer length exceeds u32::MAX");
188        self.write_u32(len);
189    }
190
191    /// Write a string as a `u32` byte length followed by its UTF-8 bytes.
192    /// Interior NUL bytes round-trip unchanged (the format is not
193    /// NUL-terminated).
194    ///
195    /// # Panics
196    ///
197    /// Panics when the string is longer than `u32::MAX` bytes.
198    pub fn write_string(&mut self, v: &str) {
199        self.write_bytes(v.as_bytes());
200    }
201
202    /// Write a byte buffer as a `u32` length followed by the raw bytes.
203    ///
204    /// # Panics
205    ///
206    /// Panics when the buffer is longer than `u32::MAX` bytes.
207    pub fn write_bytes(&mut self, v: &[u8]) {
208        self.write_len(v.len());
209        self.buf.extend_from_slice(v);
210    }
211
212    /// Write an optional's presence flag: `0` for absent, `1` for present.
213    /// When `present`, the caller writes the inner value next.
214    pub fn write_option_flag(&mut self, present: bool) {
215        self.buf.push(u8::from(present));
216    }
217}
218
219/// Decodes values from the WeaveFFI buffer format.
220///
221/// Every `read_*` method returns [`BufferDecodeError`] when the buffer is
222/// exhausted or holds invalid data, so a malformed buffer can never cause an
223/// out-of-bounds read.
224#[derive(Debug)]
225pub struct BufferReader<'a> {
226    data: &'a [u8],
227    pos: usize,
228    tokens: bool,
229}
230
231impl<'a> BufferReader<'a> {
232    /// Wrap an encoded buffer for reading. Object tokens in it are adopted
233    /// by [`BufferValue::read_value`], whose contract covers them.
234    #[must_use]
235    pub fn new(data: &'a [u8]) -> Self {
236        Self {
237            data,
238            pos: 0,
239            tokens: true,
240        }
241    }
242
243    /// Wrap an encoded buffer whose object tokens must not be adopted:
244    /// reading an interface value fails instead. Decoding through such a
245    /// reader is sound for any input, which is how the runtime reads a
246    /// callback's error payload (see
247    /// [`ForeignError::domain`](crate::abi::ForeignError::domain)).
248    #[must_use]
249    pub fn token_free(data: &'a [u8]) -> Self {
250        Self {
251            data,
252            pos: 0,
253            tokens: false,
254        }
255    }
256
257    /// Whether this reader may adopt object tokens (it wasn't built with
258    /// [`token_free`](Self::token_free)).
259    #[must_use]
260    pub fn adopts_tokens(&self) -> bool {
261        self.tokens
262    }
263
264    /// The number of bytes not yet consumed.
265    #[must_use]
266    pub fn remaining(&self) -> usize {
267        self.data.len() - self.pos
268    }
269
270    fn take(&mut self, n: usize, context: &'static str) -> Result<&'a [u8], BufferDecodeError> {
271        if self.remaining() < n {
272            return Err(BufferDecodeError { context });
273        }
274        let slice = &self.data[self.pos..self.pos + n];
275        self.pos += n;
276        Ok(slice)
277    }
278
279    /// Read a `bool`.
280    ///
281    /// # Errors
282    ///
283    /// Returns an error when the buffer is exhausted or the byte is not `0`
284    /// or `1`.
285    pub fn read_bool(&mut self) -> Result<bool, BufferDecodeError> {
286        match self.take(1, "bool")?[0] {
287            0 => Ok(false),
288            1 => Ok(true),
289            _ => Err(BufferDecodeError {
290                context: "bool byte out of range",
291            }),
292        }
293    }
294
295    /// Read an `i8`.
296    ///
297    /// # Errors
298    ///
299    /// Returns an error when the buffer is exhausted.
300    pub fn read_i8(&mut self) -> Result<i8, BufferDecodeError> {
301        Ok(i8::from_le_bytes([self.take(1, "i8")?[0]]))
302    }
303
304    /// Read a `u8`.
305    ///
306    /// # Errors
307    ///
308    /// Returns an error when the buffer is exhausted.
309    pub fn read_u8(&mut self) -> Result<u8, BufferDecodeError> {
310        Ok(self.take(1, "u8")?[0])
311    }
312
313    /// Read an `i16` little-endian.
314    ///
315    /// # Errors
316    ///
317    /// Returns an error when the buffer is exhausted.
318    pub fn read_i16(&mut self) -> Result<i16, BufferDecodeError> {
319        let b = self.take(2, "i16")?;
320        Ok(i16::from_le_bytes([b[0], b[1]]))
321    }
322
323    /// Read a `u16` little-endian.
324    ///
325    /// # Errors
326    ///
327    /// Returns an error when the buffer is exhausted.
328    pub fn read_u16(&mut self) -> Result<u16, BufferDecodeError> {
329        let b = self.take(2, "u16")?;
330        Ok(u16::from_le_bytes([b[0], b[1]]))
331    }
332
333    /// Read an `i32` little-endian. Also decodes C-style enum values and
334    /// rich-enum tags.
335    ///
336    /// # Errors
337    ///
338    /// Returns an error when the buffer is exhausted.
339    pub fn read_i32(&mut self) -> Result<i32, BufferDecodeError> {
340        let b = self.take(4, "i32")?;
341        Ok(i32::from_le_bytes([b[0], b[1], b[2], b[3]]))
342    }
343
344    /// Read a `u32` little-endian.
345    ///
346    /// # Errors
347    ///
348    /// Returns an error when the buffer is exhausted.
349    pub fn read_u32(&mut self) -> Result<u32, BufferDecodeError> {
350        let b = self.take(4, "u32")?;
351        Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
352    }
353
354    /// Read an `i64` little-endian.
355    ///
356    /// # Errors
357    ///
358    /// Returns an error when the buffer is exhausted.
359    pub fn read_i64(&mut self) -> Result<i64, BufferDecodeError> {
360        let b = self.take(8, "i64")?;
361        Ok(i64::from_le_bytes([
362            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
363        ]))
364    }
365
366    /// Read a `u64` little-endian. Also decodes object tokens.
367    ///
368    /// # Errors
369    ///
370    /// Returns an error when the buffer is exhausted.
371    pub fn read_u64(&mut self) -> Result<u64, BufferDecodeError> {
372        let b = self.take(8, "u64")?;
373        Ok(u64::from_le_bytes([
374            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
375        ]))
376    }
377
378    /// Read an `f32` from its IEEE 754 bits, little-endian.
379    ///
380    /// # Errors
381    ///
382    /// Returns an error when the buffer is exhausted.
383    pub fn read_f32(&mut self) -> Result<f32, BufferDecodeError> {
384        let b = self.take(4, "f32")?;
385        Ok(f32::from_le_bytes([b[0], b[1], b[2], b[3]]))
386    }
387
388    /// Read an `f64` from its IEEE 754 bits, little-endian.
389    ///
390    /// # Errors
391    ///
392    /// Returns an error when the buffer is exhausted.
393    pub fn read_f64(&mut self) -> Result<f64, BufferDecodeError> {
394        let b = self.take(8, "f64")?;
395        Ok(f64::from_le_bytes([
396            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
397        ]))
398    }
399
400    /// Read the byte length of a string or byte buffer (a `u32`).
401    ///
402    /// # Errors
403    ///
404    /// Returns an error when the buffer is exhausted or the decoded length
405    /// exceeds the bytes remaining, which would make the follow-up read fail
406    /// anyway; rejecting here gives a clearer error.
407    pub fn read_len(&mut self) -> Result<usize, BufferDecodeError> {
408        let len = self.read_count()?;
409        if len > self.remaining() {
410            return Err(BufferDecodeError {
411                context: "length prefix exceeds remaining buffer",
412            });
413        }
414        Ok(len)
415    }
416
417    /// Read a collection's element count (a `u32`).
418    ///
419    /// Unlike [`read_len`](Self::read_len) this doesn't bound the count by
420    /// the bytes remaining: an element's encoding can be empty (a record with
421    /// no fields), so a large count is legitimate. Decoders bound their
422    /// preallocation by [`remaining`](Self::remaining) instead, and a hostile
423    /// count fails as soon as the elements run out.
424    ///
425    /// # Errors
426    ///
427    /// Returns an error when the buffer is exhausted.
428    pub fn read_count(&mut self) -> Result<usize, BufferDecodeError> {
429        Ok(self.read_u32()? as usize)
430    }
431
432    /// Read `n` raw bytes.
433    ///
434    /// # Errors
435    ///
436    /// Returns an error when fewer than `n` bytes remain.
437    pub fn read_raw(&mut self, n: usize) -> Result<&'a [u8], BufferDecodeError> {
438        self.take(n, "raw bytes")
439    }
440
441    /// Read a string: `u32` byte length + UTF-8 bytes.
442    ///
443    /// # Errors
444    ///
445    /// Returns an error when the buffer is exhausted or the bytes are not
446    /// valid UTF-8.
447    pub fn read_string(&mut self) -> Result<String, BufferDecodeError> {
448        let len = self.read_len()?;
449        let bytes = self.take(len, "string bytes")?;
450        std::str::from_utf8(bytes)
451            .map(str::to_owned)
452            .map_err(|_| BufferDecodeError {
453                context: "string is not valid UTF-8",
454            })
455    }
456
457    /// Read a byte buffer: `u32` length + raw bytes.
458    ///
459    /// # Errors
460    ///
461    /// Returns an error when the buffer is exhausted.
462    pub fn read_bytes(&mut self) -> Result<Vec<u8>, BufferDecodeError> {
463        let len = self.read_len()?;
464        Ok(self.take(len, "byte buffer")?.to_vec())
465    }
466
467    /// Read an optional's presence flag.
468    ///
469    /// # Errors
470    ///
471    /// Returns an error when the buffer is exhausted or the flag byte is not
472    /// `0` or `1`.
473    pub fn read_option_flag(&mut self) -> Result<bool, BufferDecodeError> {
474        match self.take(1, "option flag")?[0] {
475            0 => Ok(false),
476            1 => Ok(true),
477            _ => Err(BufferDecodeError {
478                context: "option flag byte out of range",
479            }),
480        }
481    }
482
483    /// Assert the whole buffer was consumed. Called after decoding a complete
484    /// value to catch trailing garbage.
485    ///
486    /// # Errors
487    ///
488    /// Returns an error when unconsumed bytes remain.
489    pub fn expect_end(&self) -> Result<(), BufferDecodeError> {
490        if self.remaining() != 0 {
491            return Err(BufferDecodeError {
492                context: "trailing bytes after value",
493            });
494        }
495        Ok(())
496    }
497}
498
499/// Proof that a type's buffer encoding is exactly its little-endian
500/// in-memory representation, which lets lists of it encode and decode with
501/// one copy.
502///
503/// Only this crate can construct it, so only the built-in integer and float
504/// implementations of [`BufferValue`] can opt into the fast path; a type with
505/// invalid bit patterns (`bool`, an enum) can never be copied in unchecked.
506#[derive(Debug, Clone, Copy)]
507pub struct FixedWidth(());
508
509/// A value that can serialize itself into (and decode itself from) the
510/// WeaveFFI buffer format.
511///
512/// The `#[weaveffi::record]`, `#[weaveffi::enumeration]`, and
513/// `#[weaveffi::error]` expansions implement this for annotated types, and
514/// blanket implementations below cover primitives, `String`, `Option<T>`,
515/// `Vec<T>` (bytes are `Vec<u8>`), the map types, and `Arc<T>` (an interface
516/// object token), so nested composites compose automatically.
517pub trait BufferValue: Sized {
518    /// `Some` when this type's encoding is its little-endian memory layout
519    /// (see [`FixedWidth`]). Leave the default.
520    const FIXED_WIDTH: Option<FixedWidth> = None;
521
522    /// The exact number of bytes [`write_value`](Self::write_value) appends,
523    /// used to size encodings up front. The default of `0` is a valid (if
524    /// slower) hint; every built-in and generated implementation is exact.
525    fn encoded_len(&self) -> usize {
526        0
527    }
528
529    /// Append this value's encoding to `w`.
530    fn write_value(&self, w: &mut BufferWriter);
531
532    /// Decode one value of this type from `r`.
533    ///
534    /// # Errors
535    ///
536    /// Returns an error when the buffer is exhausted or holds invalid data
537    /// for this type.
538    ///
539    /// # Safety
540    ///
541    /// Unless `r` was built with [`BufferReader::token_free`], every object
542    /// token the value contains must carry one strong reference to a live
543    /// object of the token's type that hasn't been adopted yet; reading
544    /// adopts it. Generated thunks satisfy this because the ABI requires
545    /// every token a consumer writes to come from a fresh `_clone`, and they
546    /// decode each buffer exactly once.
547    unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError>;
548}
549
550/// Marks a type that crosses the C ABI as a value buffer: a
551/// `#[weaveffi::record]` or a rich `#[weaveffi::enumeration]`.
552///
553/// The `#[weaveffi::module]` expansion asserts it for every type a module
554/// names but doesn't declare in its own module tree, because such a type is
555/// lowered as a value buffer without the macro seeing its declaration. A
556/// C-style enum, an interface, or a callback interface from another tree
557/// would cross differently in the generated header, so it must fail to
558/// compile instead of silently mismatching.
559#[diagnostic::on_unimplemented(
560    message = "`{Self}` is not a WeaveFFI record or rich enum; declare C-style enums and interfaces in the module tree that uses them",
561    label = "declared outside this module tree",
562    note = "a `#[weaveffi::module]` only sees the declarations inside its own tree, so it can pass a type from another tree only as a value buffer (a record or rich enum)",
563    note = "nest the modules under one `#[weaveffi::module]` root (as inner `mod`s) so the macro can see the declaration"
564)]
565pub trait ByValue {}
566
567macro_rules! scalar_buffer_value {
568    ($($t:ty => ($write:ident, $read:ident)),* $(,)?) => {
569        $(
570            impl BufferValue for $t {
571                fn encoded_len(&self) -> usize {
572                    std::mem::size_of::<$t>()
573                }
574                fn write_value(&self, w: &mut BufferWriter) {
575                    w.$write(*self);
576                }
577                unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
578                    r.$read()
579                }
580            }
581        )*
582    };
583}
584
585macro_rules! fixed_width_buffer_value {
586    ($($t:ty => ($write:ident, $read:ident)),* $(,)?) => {
587        $(
588            impl BufferValue for $t {
589                const FIXED_WIDTH: Option<FixedWidth> = if cfg!(target_endian = "little") {
590                    Some(FixedWidth(()))
591                } else {
592                    None
593                };
594                fn encoded_len(&self) -> usize {
595                    std::mem::size_of::<$t>()
596                }
597                fn write_value(&self, w: &mut BufferWriter) {
598                    w.$write(*self);
599                }
600                unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
601                    r.$read()
602                }
603            }
604        )*
605    };
606}
607
608scalar_buffer_value! {
609    bool => (write_bool, read_bool),
610}
611
612fixed_width_buffer_value! {
613    i8 => (write_i8, read_i8),
614    u8 => (write_u8, read_u8),
615    i16 => (write_i16, read_i16),
616    u16 => (write_u16, read_u16),
617    i32 => (write_i32, read_i32),
618    u32 => (write_u32, read_u32),
619    i64 => (write_i64, read_i64),
620    u64 => (write_u64, read_u64),
621    f32 => (write_f32, read_f32),
622    f64 => (write_f64, read_f64),
623}
624
625impl BufferValue for String {
626    fn encoded_len(&self) -> usize {
627        4 + self.len()
628    }
629    fn write_value(&self, w: &mut BufferWriter) {
630        w.write_string(self);
631    }
632    unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
633        r.read_string()
634    }
635}
636
637/// An interface object inside a buffer: a `u64` token carrying one strong
638/// reference. Writing clones the `Arc`; reading adopts the reference, so a
639/// buffer holding tokens must be decoded exactly once (the generated thunks
640/// guarantee this). A zero token is a contract violation and decodes as an
641/// error, and so does any token read through a
642/// [`token_free`](BufferReader::token_free) reader.
643impl<T> BufferValue for Arc<T> {
644    fn encoded_len(&self) -> usize {
645        8
646    }
647    fn write_value(&self, w: &mut BufferWriter) {
648        w.write_u64(crate::abi::object::object_to_token(self));
649    }
650    unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
651        if !r.tokens {
652            return Err(BufferDecodeError {
653                context: "object token in a buffer that may not carry objects",
654            });
655        }
656        let token = r.read_u64()?;
657        // SAFETY: the caller guarantees every token in an adopting reader
658        // carries one unadopted reference to a live `T`.
659        unsafe { crate::abi::object::object_from_token(token) }.ok_or(BufferDecodeError {
660            context: "null object token",
661        })
662    }
663}
664
665impl<T: BufferValue> BufferValue for Option<T> {
666    fn encoded_len(&self) -> usize {
667        1 + self.as_ref().map_or(0, BufferValue::encoded_len)
668    }
669    fn write_value(&self, w: &mut BufferWriter) {
670        match self {
671            Some(v) => {
672                w.write_option_flag(true);
673                v.write_value(w);
674            }
675            None => w.write_option_flag(false),
676        }
677    }
678    unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
679        if r.read_option_flag()? {
680            // SAFETY: forwarded from the caller.
681            Ok(Some(unsafe { T::read_value(r) }?))
682        } else {
683            Ok(None)
684        }
685    }
686}
687
688impl<T: BufferValue> BufferValue for Vec<T> {
689    fn encoded_len(&self) -> usize {
690        if T::FIXED_WIDTH.is_some() {
691            return 4 + std::mem::size_of_val(self.as_slice());
692        }
693        4 + self.iter().map(BufferValue::encoded_len).sum::<usize>()
694    }
695
696    fn write_value(&self, w: &mut BufferWriter) {
697        w.write_len(self.len());
698        if let Some(proof) = T::FIXED_WIDTH {
699            w.write_raw(fixed_width_bytes(proof, self));
700            return;
701        }
702        for item in self {
703            item.write_value(w);
704        }
705    }
706
707    unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
708        let count = r.read_count()?;
709        if let Some(proof) = T::FIXED_WIDTH {
710            let size = count
711                .checked_mul(std::mem::size_of::<T>())
712                .ok_or(BufferDecodeError {
713                    context: "list length overflows",
714                })?;
715            let bytes = r.take(size, "fixed-width list")?;
716            return Ok(fixed_width_from_bytes(proof, bytes, count));
717        }
718        let mut out = Vec::with_capacity(count.min(r.remaining()));
719        for _ in 0..count {
720            // SAFETY: forwarded from the caller.
721            out.push(unsafe { T::read_value(r) }?);
722        }
723        Ok(out)
724    }
725}
726
727/// View a fixed-width slice as its encoded bytes.
728fn fixed_width_bytes<T: BufferValue>(_proof: FixedWidth, items: &[T]) -> &[u8] {
729    // SAFETY: `FixedWidth` is only constructed for the integer and float
730    // types on little-endian targets, which have no padding and whose memory
731    // layout is exactly their encoding, so every byte is initialized.
732    unsafe { std::slice::from_raw_parts(items.as_ptr().cast::<u8>(), std::mem::size_of_val(items)) }
733}
734
735/// Copy `count` fixed-width elements out of their encoded bytes.
736fn fixed_width_from_bytes<T: BufferValue>(
737    _proof: FixedWidth,
738    bytes: &[u8],
739    count: usize,
740) -> Vec<T> {
741    let mut out = Vec::<T>::with_capacity(count);
742    // SAFETY: `FixedWidth` guarantees every bit pattern of `T` is valid and
743    // that its encoding is its memory layout; `bytes` holds exactly `count`
744    // elements, the destination has room for them, and a byte-wise copy has
745    // no alignment requirement.
746    unsafe {
747        std::ptr::copy_nonoverlapping(bytes.as_ptr(), out.as_mut_ptr().cast::<u8>(), bytes.len());
748        out.set_len(count);
749    }
750    out
751}
752
753/// The error a map encoding that repeats a key decodes to.
754const DUPLICATE_KEY: BufferDecodeError = BufferDecodeError {
755    context: "duplicate map key",
756};
757
758impl<K: BufferValue + Ord, V: BufferValue> BufferValue for std::collections::BTreeMap<K, V> {
759    fn encoded_len(&self) -> usize {
760        4 + self
761            .iter()
762            .map(|(k, v)| k.encoded_len() + v.encoded_len())
763            .sum::<usize>()
764    }
765    fn write_value(&self, w: &mut BufferWriter) {
766        w.write_len(self.len());
767        for (k, v) in self {
768            k.write_value(w);
769            v.write_value(w);
770        }
771    }
772    unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
773        let len = r.read_count()?;
774        let mut out = Self::new();
775        for _ in 0..len {
776            // SAFETY: forwarded from the caller.
777            let (k, v) = unsafe { (K::read_value(r)?, V::read_value(r)?) };
778            if out.insert(k, v).is_some() {
779                return Err(DUPLICATE_KEY);
780            }
781        }
782        Ok(out)
783    }
784}
785
786impl<K: BufferValue + std::hash::Hash + Eq, V: BufferValue> BufferValue
787    for std::collections::HashMap<K, V>
788{
789    fn encoded_len(&self) -> usize {
790        4 + self
791            .iter()
792            .map(|(k, v)| k.encoded_len() + v.encoded_len())
793            .sum::<usize>()
794    }
795    fn write_value(&self, w: &mut BufferWriter) {
796        w.write_len(self.len());
797        for (k, v) in self {
798            k.write_value(w);
799            v.write_value(w);
800        }
801    }
802    unsafe fn read_value(r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
803        let len = r.read_count()?;
804        let mut out = Self::with_capacity(len.min(r.remaining()));
805        for _ in 0..len {
806            // SAFETY: forwarded from the caller.
807            let (k, v) = unsafe { (K::read_value(r)?, V::read_value(r)?) };
808            if out.insert(k, v).is_some() {
809                return Err(DUPLICATE_KEY);
810            }
811        }
812        Ok(out)
813    }
814}
815
816/// Encode one [`BufferValue`] into a fresh byte buffer, allocated once at
817/// the size [`BufferValue::encoded_len`] reports.
818#[must_use]
819pub fn encode_value<T: BufferValue>(value: &T) -> Vec<u8> {
820    let mut w = BufferWriter::with_capacity(value.encoded_len());
821    value.write_value(&mut w);
822    w.finish()
823}
824
825/// Decode one [`BufferValue`] from an encoded buffer, requiring the buffer to
826/// be fully consumed.
827///
828/// # Errors
829///
830/// Returns an error when the buffer is malformed for `T` or holds trailing
831/// bytes.
832///
833/// # Safety
834///
835/// Same contract as [`BufferValue::read_value`]: every object token in
836/// `data` must carry an unadopted reference to a live object of its type.
837/// A buffer holding object tokens may be decoded only once.
838pub unsafe fn decode_value<T: BufferValue>(data: &[u8]) -> Result<T, BufferDecodeError> {
839    let mut r = BufferReader::new(data);
840    // SAFETY: forwarded from the caller.
841    let value = unsafe { T::read_value(&mut r) }?;
842    r.expect_end()?;
843    Ok(value)
844}
845
846#[cfg(test)]
847mod tests {
848    use super::*;
849    use std::collections::BTreeMap;
850
851    /// Decode a buffer these tests encoded themselves.
852    fn decode<T: BufferValue>(data: &[u8]) -> Result<T, BufferDecodeError> {
853        // SAFETY: every token in these buffers was written by `encode_value`
854        // and is decoded once.
855        unsafe { decode_value(data) }
856    }
857
858    fn roundtrip<T: BufferValue + PartialEq + std::fmt::Debug>(value: T) {
859        let bytes = encode_value(&value);
860        let back: T = decode(&bytes).unwrap();
861        assert_eq!(back, value);
862    }
863
864    #[test]
865    fn scalars_roundtrip() {
866        roundtrip(true);
867        roundtrip(false);
868        roundtrip(-5i8);
869        roundtrip(200u8);
870        roundtrip(-1234i16);
871        roundtrip(54321u16);
872        roundtrip(-7i32);
873        roundtrip(4_000_000_000u32);
874        roundtrip(i64::MIN);
875        roundtrip(u64::MAX);
876        roundtrip(1.5f32);
877        roundtrip(-2.25f64);
878    }
879
880    #[test]
881    fn strings_roundtrip_including_interior_nul() {
882        roundtrip(String::new());
883        roundtrip("hello".to_string());
884        roundtrip("emoji \u{1F980} and\0nul".to_string());
885    }
886
887    #[test]
888    fn options_roundtrip() {
889        roundtrip::<Option<i32>>(None);
890        roundtrip(Some(42i32));
891        roundtrip(Some("text".to_string()));
892        roundtrip::<Option<Option<i64>>>(Some(None));
893        roundtrip::<Option<Option<i64>>>(Some(Some(9)));
894    }
895
896    #[test]
897    fn collections_roundtrip() {
898        roundtrip(vec![1u8, 2, 3]);
899        roundtrip(vec!["a".to_string(), String::new(), "ccc".to_string()]);
900        roundtrip(vec![vec![1i32, 2], vec![], vec![3]]);
901        roundtrip(vec![Some(1i32), None, Some(3)]);
902        let mut m = BTreeMap::new();
903        m.insert("a".to_string(), vec![1i64, 2]);
904        m.insert("b".to_string(), vec![]);
905        roundtrip(m);
906    }
907
908    #[test]
909    fn object_tokens_transfer_one_reference() {
910        let obj = Arc::new(String::from("shared"));
911        let bytes = encode_value(&vec![Some(Arc::clone(&obj)), None, Some(Arc::clone(&obj))]);
912        assert_eq!(Arc::strong_count(&obj), 3);
913        let back: Vec<Option<Arc<String>>> = decode(&bytes).unwrap();
914        assert_eq!(Arc::strong_count(&obj), 3);
915        assert!(Arc::ptr_eq(back[0].as_ref().unwrap(), &obj));
916        assert!(back[1].is_none());
917        drop(back);
918        assert_eq!(Arc::strong_count(&obj), 1);
919        let zero = [0u8; 8];
920        assert!(decode::<Arc<String>>(&zero).is_err());
921    }
922
923    #[test]
924    fn duplicate_map_keys_are_rejected() {
925        let mut w = BufferWriter::new();
926        w.write_len(2);
927        for v in [1i32, 2] {
928            w.write_string("k");
929            w.write_i32(v);
930        }
931        let bytes = w.finish();
932        let err = decode::<BTreeMap<String, i32>>(&bytes).unwrap_err();
933        assert_eq!(err.context, "duplicate map key");
934        assert!(decode::<std::collections::HashMap<String, i32>>(&bytes).is_err());
935    }
936
937    #[test]
938    fn token_free_readers_refuse_objects() {
939        let obj = Arc::new(5u8);
940        let bytes = encode_value(&obj);
941        let mut r = BufferReader::token_free(&bytes);
942        assert!(!r.adopts_tokens());
943        // SAFETY: a token-free reader never adopts.
944        assert!(unsafe { Arc::<u8>::read_value(&mut r) }.is_err());
945        // The token still carries its reference; adopt it to balance.
946        let back: Arc<u8> = decode(&bytes).unwrap();
947        assert!(Arc::ptr_eq(&back, &obj));
948    }
949
950    #[test]
951    fn known_byte_layout() {
952        // Lock the wire format: [count=2][len=1]'a'[len=0] for `["a", ""]`.
953        let bytes = encode_value(&vec!["a".to_string(), String::new()]);
954        assert_eq!(bytes, [2, 0, 0, 0, 1, 0, 0, 0, b'a', 0, 0, 0, 0].as_slice());
955    }
956
957    #[test]
958    fn truncated_buffer_is_rejected() {
959        let bytes = encode_value(&"hello".to_string());
960        let err = decode::<String>(&bytes[..bytes.len() - 1]).unwrap_err();
961        assert!(err.to_string().contains("malformed"));
962    }
963
964    #[test]
965    fn trailing_bytes_are_rejected() {
966        let mut bytes = encode_value(&7i32);
967        bytes.push(0);
968        assert!(decode::<i32>(&bytes).is_err());
969    }
970
971    #[test]
972    fn hostile_length_prefix_is_rejected() {
973        // A length claiming more elements than bytes remain must fail fast
974        // instead of attempting a huge allocation.
975        let bytes = [0xFF, 0xFF, 0xFF, 0xFF];
976        assert!(decode::<Vec<u8>>(&bytes).is_err());
977    }
978
979    #[test]
980    fn invalid_bool_and_flag_bytes_are_rejected() {
981        assert!(decode::<bool>(&[2]).is_err());
982        assert!(decode::<Option<i32>>(&[9]).is_err());
983    }
984
985    #[test]
986    fn invalid_utf8_is_rejected() {
987        let bytes = [2, 0, 0, 0, 0xFF, 0xFE];
988        assert!(decode::<String>(&bytes).is_err());
989    }
990
991    #[derive(Debug, PartialEq)]
992    struct NoFields;
993
994    impl BufferValue for NoFields {
995        fn write_value(&self, _w: &mut BufferWriter) {}
996        unsafe fn read_value(_r: &mut BufferReader<'_>) -> Result<Self, BufferDecodeError> {
997            Ok(NoFields)
998        }
999    }
1000
1001    #[test]
1002    fn zero_sized_elements_allow_counts_beyond_the_remaining_bytes() {
1003        roundtrip(vec![NoFields, NoFields, NoFields]);
1004        assert_eq!(encode_value(&vec![NoFields, NoFields]), [2, 0, 0, 0]);
1005    }
1006
1007    #[test]
1008    fn encoded_len_is_exact() {
1009        fn check<T: BufferValue>(v: T) {
1010            let bytes = encode_value(&v);
1011            assert_eq!(bytes.len(), v.encoded_len());
1012            assert_eq!(bytes.capacity(), bytes.len());
1013        }
1014        check(vec![1u16, 2, 3]);
1015        check(vec![1.5f64]);
1016        check(vec![true, false]);
1017        check(Some("text".to_string()));
1018        check(vec![Some(vec![1i64]), None]);
1019        let mut m = BTreeMap::new();
1020        m.insert("k".to_string(), vec![Some(1u8)]);
1021        check(m);
1022    }
1023
1024    #[test]
1025    fn fixed_width_lists_use_the_scalar_layout() {
1026        let v = vec![1i32, -2, 0x0102_0304];
1027        let mut slow = BufferWriter::new();
1028        slow.write_len(v.len());
1029        for x in &v {
1030            slow.write_i32(*x);
1031        }
1032        assert_eq!(encode_value(&v), slow.finish());
1033        roundtrip(v);
1034        roundtrip(vec![f32::MIN, 0.0, f32::MAX]);
1035        roundtrip(Vec::<u64>::new());
1036    }
1037
1038    #[test]
1039    fn truncated_fixed_width_list_is_rejected() {
1040        let mut bytes = encode_value(&vec![7u32, 8]);
1041        bytes.pop();
1042        assert!(decode::<Vec<u32>>(&bytes).is_err());
1043        let huge = [0xFF, 0xFF, 0xFF, 0xFF];
1044        assert!(decode::<Vec<u64>>(&huge).is_err());
1045        assert!(decode::<Vec<String>>(&huge).is_err());
1046    }
1047}