Skip to main content

wire_codec/
traits.rs

1//! Core traits implemented by every encodable value.
2//!
3//! [`Encode`] writes a value into a [`WriteBuf`]; [`Decode`] reads one out of a
4//! [`ReadBuf`]. The traits are deliberately minimal so callers can compose them
5//! with any framing strategy in the [`framing`][`crate::framing`] module.
6//!
7//! # Provided implementations
8//!
9//! | Type | Wire form |
10//! | ---- | --------- |
11//! | `u8`, `i8` | one byte |
12//! | `bool` | one byte, `0` or `1`; any other byte decodes as [`Error::InvalidEncoding`] |
13//! | `[u8; N]` | `N` raw bytes (copied on decode) |
14//! | `&'de [u8; N]` | `N` raw bytes (zero-copy decode) |
15//! | `[u8]` | raw bytes, encode only (the length must be framed separately) |
16//! | [`Be<T>`] / [`Le<T>`] | `T` in big / little endian, for every integer from `u16` to `i128`, and `f32` / `f64` |
17//! | [`Varint<T>`] | LEB128 varint for `u16`, `u32`, `u64`, `usize`; zigzag varint for `i32`, `i64` |
18//! | `(A, B)` up to `(A, B, C, D, E, F)` | the elements in order |
19//!
20//! Multi-byte integers have no plain `Encode` impl on purpose: the byte order
21//! is part of the wire format, so it must be chosen explicitly with a
22//! wrapper.
23//!
24//! Tuples restore the cursor to where the tuple started if any element
25//! fails. They check the total `encoded_size` against the remaining room
26//! first, so a short buffer is reported as [`Error::BufferFull`] before
27//! anything is written, and before any element gets the chance to report
28//! a different error. If a later element fails for another reason (a
29//! packed field out of range, say), the bytes of the earlier elements remain
30//! behind the restored cursor.
31
32use crate::buf::{ReadBuf, WriteBuf};
33use crate::error::{Error, Result};
34use crate::varint;
35
36/// A value that can be written to a [`WriteBuf`].
37///
38/// Implementors must guarantee that [`Encode::encoded_size`] returns the exact
39/// number of bytes [`Encode::encode`] writes on success.
40///
41/// # Example
42///
43/// ```
44/// use wire_codec::{Encode, Result, WriteBuf};
45///
46/// struct Tagged {
47///     tag: u8,
48///     value: u32,
49/// }
50///
51/// impl Encode for Tagged {
52///     fn encoded_size(&self) -> usize { 5 }
53///     fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
54///         buf.write_u8(self.tag)?;
55///         buf.write_u32_be(self.value)
56///     }
57/// }
58///
59/// let mut out = [0u8; 5];
60/// let mut buf = WriteBuf::new(&mut out);
61/// Tagged { tag: 0x01, value: 0xCAFEBABE }.encode(&mut buf).unwrap();
62/// assert_eq!(&out, &[0x01, 0xCA, 0xFE, 0xBA, 0xBE]);
63/// ```
64pub trait Encode {
65    /// Number of bytes [`Encode::encode`] will write on success.
66    #[must_use]
67    fn encoded_size(&self) -> usize;
68
69    /// Write `self` into `buf`, advancing its write position.
70    ///
71    /// # Errors
72    ///
73    /// Returns an error if `buf` lacks capacity for [`Encode::encoded_size`]
74    /// bytes or if a sub-encoder reports an invariant violation.
75    fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()>;
76}
77
78/// A value that can be read from a [`ReadBuf`].
79///
80/// The lifetime parameter `'de` ties the decoded value to the borrowed input,
81/// enabling zero-copy decoding of borrowed payloads (`&'de [u8]`, `&'de str`).
82///
83/// # Example
84///
85/// ```
86/// use wire_codec::{Decode, ReadBuf, Result};
87///
88/// struct Tagged {
89///     tag: u8,
90///     value: u32,
91/// }
92///
93/// impl<'de> Decode<'de> for Tagged {
94///     fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
95///         let tag = buf.read_u8()?;
96///         let value = buf.read_u32_be()?;
97///         Ok(Self { tag, value })
98///     }
99/// }
100///
101/// let mut buf = ReadBuf::new(&[0x01, 0xCA, 0xFE, 0xBA, 0xBE]);
102/// let tagged = Tagged::decode(&mut buf).unwrap();
103/// assert_eq!(tagged.tag, 0x01);
104/// assert_eq!(tagged.value, 0xCAFEBABE);
105/// ```
106pub trait Decode<'de>: Sized {
107    /// Read a value of `Self` from `buf`, advancing its read position.
108    ///
109    /// # Errors
110    ///
111    /// Returns an error if `buf` is exhausted before the value finishes, or if
112    /// the encoded bytes violate the codec's structural rules.
113    fn decode(buf: &mut ReadBuf<'de>) -> Result<Self>;
114}
115
116impl Encode for u8 {
117    #[inline]
118    fn encoded_size(&self) -> usize {
119        1
120    }
121    #[inline]
122    fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
123        buf.write_u8(*self)
124    }
125}
126
127impl<'de> Decode<'de> for u8 {
128    #[inline]
129    fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
130        buf.read_u8()
131    }
132}
133
134impl Encode for i8 {
135    #[inline]
136    fn encoded_size(&self) -> usize {
137        1
138    }
139    #[inline]
140    fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
141        buf.write_i8(*self)
142    }
143}
144
145impl<'de> Decode<'de> for i8 {
146    #[inline]
147    fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
148        buf.read_i8()
149    }
150}
151
152impl Encode for bool {
153    #[inline]
154    fn encoded_size(&self) -> usize {
155        1
156    }
157    #[inline]
158    fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
159        buf.write_u8(u8::from(*self))
160    }
161}
162
163/// Strict: only `0` and `1` are accepted, so every value has one encoding.
164impl<'de> Decode<'de> for bool {
165    #[inline]
166    fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
167        let value = match buf.peek_u8()? {
168            0 => false,
169            1 => true,
170            _ => return Err(Error::InvalidEncoding),
171        };
172        buf.consume(1);
173        Ok(value)
174    }
175}
176
177impl Encode for [u8] {
178    #[inline]
179    fn encoded_size(&self) -> usize {
180        self.len()
181    }
182    #[inline]
183    fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
184        buf.write_bytes(self)
185    }
186}
187
188impl<const N: usize> Encode for [u8; N] {
189    #[inline]
190    fn encoded_size(&self) -> usize {
191        N
192    }
193    #[inline]
194    fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
195        buf.write_bytes(self)
196    }
197}
198
199impl<'de, const N: usize> Decode<'de> for [u8; N] {
200    #[inline]
201    fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
202        buf.read_array()
203    }
204}
205
206impl<'de, const N: usize> Decode<'de> for &'de [u8; N] {
207    #[inline]
208    fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
209        buf.read_array_ref()
210    }
211}
212
213/// Big-endian wrapper: encodes and decodes `T` most significant byte first.
214///
215/// # Example
216///
217/// ```
218/// use wire_codec::{Be, Decode, Encode, ReadBuf, WriteBuf};
219///
220/// let mut out = [0u8; 4];
221/// let mut buf = WriteBuf::new(&mut out);
222/// Be(0xCAFE_u16).encode(&mut buf).unwrap();
223/// Be(-2_i16).encode(&mut buf).unwrap();
224/// assert_eq!(out, [0xCA, 0xFE, 0xFF, 0xFE]);
225///
226/// let mut r = ReadBuf::new(&out);
227/// assert_eq!(Be::<u16>::decode(&mut r).unwrap().0, 0xCAFE);
228/// assert_eq!(Be::<i16>::decode(&mut r).unwrap(), Be(-2));
229/// ```
230#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
231pub struct Be<T>(pub T);
232
233/// Little-endian wrapper: encodes and decodes `T` least significant byte
234/// first.
235///
236/// # Example
237///
238/// ```
239/// use wire_codec::{Decode, Encode, Le, ReadBuf, WriteBuf};
240///
241/// let mut out = [0u8; 4];
242/// let mut buf = WriteBuf::new(&mut out);
243/// Le(1.0_f32).encode(&mut buf).unwrap();
244/// assert_eq!(out, [0x00, 0x00, 0x80, 0x3F]);
245/// assert_eq!(Le::<f32>::decode(&mut ReadBuf::new(&out)).unwrap(), Le(1.0));
246/// ```
247#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
248pub struct Le<T>(pub T);
249
250/// LEB128 varint wrapper. Signed integers use the zigzag mapping, matching
251/// protobuf's `sint32` / `sint64`.
252///
253/// Decoding is lenient about overlong encodings, like
254/// [`varint::decode_u64`]. Call the `varint::decode_*_canonical` functions
255/// directly when canonical form must be enforced.
256///
257/// # Example
258///
259/// ```
260/// use wire_codec::{Decode, Encode, ReadBuf, Varint, WriteBuf};
261///
262/// let mut out = [0u8; 8];
263/// let mut buf = WriteBuf::new(&mut out);
264/// Varint(300_u32).encode(&mut buf).unwrap();
265/// Varint(-1_i64).encode(&mut buf).unwrap();
266/// assert_eq!(buf.written(), &[0xAC, 0x02, 0x01]);
267/// assert_eq!(Varint(300_u32).encoded_size(), 2);
268///
269/// let mut r = ReadBuf::new(&out[..3]);
270/// assert_eq!(Varint::<u32>::decode(&mut r).unwrap(), Varint(300));
271/// assert_eq!(Varint::<i64>::decode(&mut r).unwrap(), Varint(-1));
272/// ```
273#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
274pub struct Varint<T>(pub T);
275
276macro_rules! fixed_width_impls {
277    ($($ty:ty: $read_be:ident, $write_be:ident, $read_le:ident, $write_le:ident;)*) => {$(
278        impl Encode for Be<$ty> {
279            #[inline]
280            fn encoded_size(&self) -> usize {
281                core::mem::size_of::<$ty>()
282            }
283            #[inline]
284            fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
285                buf.$write_be(self.0)
286            }
287        }
288
289        impl<'de> Decode<'de> for Be<$ty> {
290            #[inline]
291            fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
292                buf.$read_be().map(Be)
293            }
294        }
295
296        impl Encode for Le<$ty> {
297            #[inline]
298            fn encoded_size(&self) -> usize {
299                core::mem::size_of::<$ty>()
300            }
301            #[inline]
302            fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
303                buf.$write_le(self.0)
304            }
305        }
306
307        impl<'de> Decode<'de> for Le<$ty> {
308            #[inline]
309            fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
310                buf.$read_le().map(Le)
311            }
312        }
313    )*};
314}
315
316fixed_width_impls! {
317    u16: read_u16_be, write_u16_be, read_u16_le, write_u16_le;
318    u32: read_u32_be, write_u32_be, read_u32_le, write_u32_le;
319    u64: read_u64_be, write_u64_be, read_u64_le, write_u64_le;
320    u128: read_u128_be, write_u128_be, read_u128_le, write_u128_le;
321    i16: read_i16_be, write_i16_be, read_i16_le, write_i16_le;
322    i32: read_i32_be, write_i32_be, read_i32_le, write_i32_le;
323    i64: read_i64_be, write_i64_be, read_i64_le, write_i64_le;
324    i128: read_i128_be, write_i128_be, read_i128_le, write_i128_le;
325    f32: read_f32_be, write_f32_be, read_f32_le, write_f32_le;
326    f64: read_f64_be, write_f64_be, read_f64_le, write_f64_le;
327}
328
329macro_rules! varint_impls {
330    ($($ty:ty: $len:path, $encode:path, $decode:path;)*) => {$(
331        impl Encode for Varint<$ty> {
332            #[inline]
333            fn encoded_size(&self) -> usize {
334                $len(self.0)
335            }
336            #[inline]
337            fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
338                $encode(self.0, buf)
339            }
340        }
341
342        impl<'de> Decode<'de> for Varint<$ty> {
343            #[inline]
344            fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
345                $decode(buf).map(Varint)
346            }
347        }
348    )*};
349}
350
351varint_impls! {
352    u16: varint::encoded_len_u16, varint::encode_u16, varint::decode_u16;
353    u32: varint::encoded_len_u32, varint::encode_u32, varint::decode_u32;
354    u64: varint::encoded_len_u64, varint::encode_u64, varint::decode_u64;
355    usize: varint::encoded_len_usize, varint::encode_usize, varint::decode_usize;
356    i32: varint::encoded_len_i32, varint::encode_i32, varint::decode_i32;
357    i64: varint::encoded_len_i64, varint::encode_i64, varint::decode_i64;
358}
359
360macro_rules! tuple_impls {
361    ($(($($name:ident $idx:tt),+);)*) => {$(
362        impl<$($name: Encode),+> Encode for ($($name,)+) {
363            #[inline]
364            fn encoded_size(&self) -> usize {
365                0 $(+ self.$idx.encoded_size())+
366            }
367            #[inline]
368            fn encode(&self, buf: &mut WriteBuf<'_>) -> Result<()> {
369                // `encoded_size` is exact by contract: check the room once so
370                // a short buffer writes nothing at all.
371                if self.encoded_size() > buf.remaining() {
372                    return Err(Error::BufferFull);
373                }
374                let start = buf.position();
375                let result = (|| {
376                    $(self.$idx.encode(buf)?;)+
377                    Ok(())
378                })();
379                if result.is_err() {
380                    buf.rewind(start);
381                }
382                result
383            }
384        }
385
386        impl<'de, $($name: Decode<'de>),+> Decode<'de> for ($($name,)+) {
387            #[inline]
388            fn decode(buf: &mut ReadBuf<'de>) -> Result<Self> {
389                let mut scratch = buf.clone();
390                let value = ($($name::decode(&mut scratch)?,)+);
391                *buf = scratch;
392                Ok(value)
393            }
394        }
395    )*};
396}
397
398tuple_impls! {
399    (A 0, B 1);
400    (A 0, B 1, C 2);
401    (A 0, B 1, C 2, D 3);
402    (A 0, B 1, C 2, D 3, E 4);
403    (A 0, B 1, C 2, D 3, E 4, F 5);
404}
405
406#[cfg(test)]
407mod tests {
408    use super::*;
409
410    /// An element that always fails to encode, for atomicity tests.
411    struct Rejects;
412
413    impl Encode for Rejects {
414        fn encoded_size(&self) -> usize {
415            1
416        }
417        fn encode(&self, _buf: &mut WriteBuf<'_>) -> Result<()> {
418            Err(Error::InvalidEncoding)
419        }
420    }
421
422    fn round_trip<T>(value: T) -> T
423    where
424        T: Encode + for<'de> Decode<'de> + PartialEq + core::fmt::Debug,
425    {
426        let mut out = [0u8; 64];
427        let mut buf = WriteBuf::new(&mut out);
428        value.encode(&mut buf).unwrap();
429        let n = buf.position();
430        assert_eq!(n, value.encoded_size(), "encoded_size must be exact");
431        let mut r = ReadBuf::new(&out[..n]);
432        let decoded = T::decode(&mut r).unwrap();
433        assert!(r.is_empty());
434        decoded
435    }
436
437    #[test]
438    fn primitive_round_trips() {
439        assert_eq!(round_trip(0xABu8), 0xAB);
440        assert_eq!(round_trip(-5i8), -5);
441        assert!(round_trip(true));
442        assert!(!round_trip(false));
443        assert_eq!(round_trip([1u8, 2, 3]), [1, 2, 3]);
444    }
445
446    #[test]
447    fn wrapper_round_trips() {
448        assert_eq!(round_trip(Be(u16::MAX)), Be(u16::MAX));
449        assert_eq!(round_trip(Le(0x0102_0304_u32)), Le(0x0102_0304));
450        assert_eq!(round_trip(Be(u64::MAX - 1)), Be(u64::MAX - 1));
451        assert_eq!(round_trip(Le(u128::MAX / 3)), Le(u128::MAX / 3));
452        assert_eq!(round_trip(Be(i32::MIN)), Be(i32::MIN));
453        assert_eq!(round_trip(Le(i64::MIN)), Le(i64::MIN));
454        assert_eq!(round_trip(Be(i128::MIN)), Be(i128::MIN));
455        assert_eq!(round_trip(Le(-3i16)), Le(-3));
456        assert_eq!(round_trip(Be(2.5f64)), Be(2.5));
457        assert_eq!(round_trip(Le(-0.5f64)), Le(-0.5));
458        assert_eq!(round_trip(Be(9.0f32)), Be(9.0));
459        for v in [0u16, 300, u16::MAX] {
460            assert_eq!(round_trip(Varint(v)), Varint(v));
461        }
462        for v in [0usize, 1 << 20, usize::MAX] {
463            assert_eq!(round_trip(Varint(v)), Varint(v));
464        }
465        assert_eq!(round_trip(Varint(u32::MAX)), Varint(u32::MAX));
466        assert_eq!(round_trip(Varint(u64::MAX)), Varint(u64::MAX));
467        assert_eq!(round_trip(Varint(i32::MIN)), Varint(i32::MIN));
468        assert_eq!(round_trip(Varint(i64::MAX)), Varint(i64::MAX));
469    }
470
471    #[test]
472    fn byte_order_is_explicit() {
473        let mut out = [0u8; 4];
474        let mut buf = WriteBuf::new(&mut out);
475        Be(0x0102u16).encode(&mut buf).unwrap();
476        Le(0x0102u16).encode(&mut buf).unwrap();
477        assert_eq!(out, [0x01, 0x02, 0x02, 0x01]);
478    }
479
480    #[test]
481    fn tuples_encode_in_order() {
482        let value = (1u8, Be(0x0203u16), Varint(300u32), true);
483        let mut out = [0u8; 16];
484        let mut buf = WriteBuf::new(&mut out);
485        value.encode(&mut buf).unwrap();
486        assert_eq!(buf.written(), &[1, 2, 3, 0xAC, 0x02, 1]);
487        assert_eq!(round_trip(value), value);
488        assert_eq!(round_trip((1u8, 2u8)), (1, 2));
489        assert_eq!(round_trip((1u8, 2u8, 3u8)), (1, 2, 3));
490        assert_eq!(round_trip((1u8, 2u8, 3u8, 4u8, 5u8)), (1, 2, 3, 4, 5));
491        assert_eq!(
492            round_trip((1u8, 2u8, 3u8, 4u8, 5u8, 6u8)),
493            (1, 2, 3, 4, 5, 6)
494        );
495    }
496
497    #[test]
498    fn tuple_decode_and_encode_are_atomic() {
499        // Second element is short: the cursor must not keep the first byte.
500        let mut r = ReadBuf::new(&[7, 0x01]);
501        assert_eq!(<(u8, Be<u16>)>::decode(&mut r), Err(Error::UnexpectedEof));
502        assert_eq!(r.position(), 0);
503
504        let mut out = [0xEEu8; 2];
505        let mut buf = WriteBuf::new(&mut out);
506        assert_eq!((1u8, Be(2u16)).encode(&mut buf), Err(Error::BufferFull));
507        assert_eq!(buf.position(), 0);
508        assert_eq!(out, [0xEE, 0xEE], "a short buffer writes nothing");
509
510        // A later element failing for another reason restores the cursor.
511        let mut out = [0u8; 4];
512        let mut buf = WriteBuf::new(&mut out);
513        assert_eq!((1u8, Rejects).encode(&mut buf), Err(Error::InvalidEncoding));
514        assert_eq!(buf.position(), 0);
515    }
516
517    #[test]
518    fn bool_is_strict() {
519        let mut r = ReadBuf::new(&[2]);
520        assert_eq!(bool::decode(&mut r), Err(Error::InvalidEncoding));
521        assert_eq!(r.position(), 0);
522        assert_eq!(
523            bool::decode(&mut ReadBuf::new(&[])),
524            Err(Error::UnexpectedEof)
525        );
526    }
527
528    #[test]
529    fn byte_slices_and_array_refs() {
530        let mut out = [0u8; 8];
531        let mut buf = WriteBuf::new(&mut out);
532        let raw: &[u8] = b"wire";
533        assert_eq!(raw.encoded_size(), 4);
534        raw.encode(&mut buf).unwrap();
535        assert_eq!(buf.written(), b"wire");
536
537        let data = *b"abcdef";
538        let mut r = ReadBuf::new(&data);
539        let head = <&[u8; 4]>::decode(&mut r).unwrap();
540        assert_eq!(head, b"abcd");
541        assert_eq!(<[u8; 4]>::decode(&mut r), Err(Error::UnexpectedEof));
542    }
543
544    #[test]
545    fn encode_errors_propagate() {
546        let mut out = [0u8; 1];
547        let mut buf = WriteBuf::new(&mut out);
548        assert_eq!(Be(1u32).encode(&mut buf), Err(Error::BufferFull));
549        assert_eq!(Le(1u32).encode(&mut buf), Err(Error::BufferFull));
550        assert_eq!(Varint(300u32).encode(&mut buf), Err(Error::BufferFull));
551        assert_eq!(buf.position(), 0);
552        let mut r = ReadBuf::new(&[0x80]);
553        assert_eq!(Varint::<u64>::decode(&mut r), Err(Error::UnexpectedEof));
554        assert_eq!(Le::<u16>::decode(&mut r), Err(Error::UnexpectedEof));
555        assert_eq!(Be::<u16>::decode(&mut r), Err(Error::UnexpectedEof));
556    }
557}