pack_io/codec.rs
1//! The codec primitives: the [`Encode`] / [`Decode`] behaviour traits, the
2//! concrete in-memory [`Encoder`] / [`Decoder`] types, the [`Config`] struct,
3//! and the Tier-1 [`encode`] / [`decode`] free functions.
4//!
5//! ## Layering
6//!
7//! - **Tier 1** — the [`encode`] / [`decode`] free functions. One line each
8//! direction, no setup, no type parameters beyond the target type.
9//! - **Tier 2** — concrete encoder / decoder types. The in-memory pair
10//! ([`Encoder`] + [`Decoder`]) lives in this module; the streaming pair
11//! ([`crate::IoEncoder`] + [`crate::IoDecoder`]) lives in
12//! [`crate::io`] and is `std`-gated. All four implement the [`Encode`] /
13//! [`Decode`] behaviour traits, so [`Serialize`] / [`Deserialize`] impls
14//! work through any of them.
15//! - **Tier 3** — implementing the [`Serialize`] / [`Deserialize`] traits
16//! directly on your own types. Generic over `E: Encode` / `D: Decode`, so
17//! one impl works for both in-memory and streaming codecs.
18//!
19//! ## Safety contract for decoders
20//!
21//! Every method on [`Decode`] is total: it either returns the requested
22//! value (advancing the read cursor) or returns a [`SerialError`]. It never
23//! panics, never reads past the input, and never allocates more memory than
24//! the [`Config::max_alloc`] cap permits.
25
26use alloc::vec;
27use alloc::vec::Vec;
28
29use crate::error::{Result, SerialError};
30use crate::traits::{Deserialize, Serialize};
31use crate::varint;
32
33/// Configuration for a decode session.
34///
35/// At construction time the codec validates the configuration; an invalid
36/// config (currently: `max_alloc == 0`) is rejected before any bytes are read.
37/// Validation happens once, in [`Decoder::with_config`] /
38/// [`crate::IoDecoder::with_config`], not on every operation.
39///
40/// `Config` is `#[non_exhaustive]` so the project can add knobs in a MINOR
41/// release without breaking downstream code. Build instances with
42/// [`Config::new`] / [`Config::with_max_alloc`] or via [`Default`].
43///
44/// # Examples
45///
46/// ```
47/// use pack_io::{Config, Decoder};
48///
49/// // Refuse to allocate more than 16 KiB for any single length-prefixed
50/// // value (a `String`, a `Vec<u8>`, a collection element count, …).
51/// // Hostile producers that send multi-gigabyte length prefixes fail fast.
52/// let cfg = Config::new().with_max_alloc(16 * 1024);
53/// let dec = Decoder::with_config(&[], cfg).expect("non-zero cap");
54/// drop(dec);
55/// ```
56#[non_exhaustive]
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub struct Config {
59 /// Maximum number of bytes the decoder may allocate for any single
60 /// length-prefixed value (a `String`, a `Vec<u8>`, a collection element
61 /// count, …).
62 ///
63 /// The default is 1 GiB, which is enough that well-formed inputs are
64 /// never rejected on size, while still defending against the obvious
65 /// hostile-length-prefix DoS. Tighten this in any context that accepts
66 /// untrusted input from a low-budget producer.
67 pub max_alloc: usize,
68}
69
70impl Default for Config {
71 fn default() -> Self {
72 Self::new()
73 }
74}
75
76impl Config {
77 /// Default configuration: `max_alloc = 1 GiB`.
78 ///
79 /// 1 GiB is large enough to be irrelevant for well-formed inputs and
80 /// small enough to refuse the obvious `length = u64::MAX` attack before
81 /// allocating a single byte.
82 ///
83 /// # Examples
84 ///
85 /// ```
86 /// let cfg = pack_io::Config::new();
87 /// assert_eq!(cfg.max_alloc, 1 << 30);
88 /// ```
89 #[must_use]
90 pub const fn new() -> Self {
91 Self { max_alloc: 1 << 30 }
92 }
93
94 /// Replace `max_alloc` and return the updated config.
95 ///
96 /// # Examples
97 ///
98 /// ```
99 /// let cfg = pack_io::Config::new().with_max_alloc(4096);
100 /// assert_eq!(cfg.max_alloc, 4096);
101 /// ```
102 #[must_use]
103 pub const fn with_max_alloc(mut self, max_alloc: usize) -> Self {
104 self.max_alloc = max_alloc;
105 self
106 }
107
108 /// Validate the configuration. Returns an error if any field is
109 /// nonsensical.
110 pub(crate) fn validate(self) -> Result<Self> {
111 if self.max_alloc == 0 {
112 return Err(SerialError::InvalidLength {
113 declared: 0,
114 remaining: 0,
115 });
116 }
117 Ok(self)
118 }
119}
120
121// ---------------------------------------------------------------------------
122// Encode / Decode behaviour traits
123// ---------------------------------------------------------------------------
124
125/// Sink that a [`Serialize`] implementation writes its wire-format bytes
126/// into.
127///
128/// Implemented by every concrete encoder in the crate ([`Encoder`] for the
129/// in-memory case, [`crate::IoEncoder`] for `std::io::Write` streams). User
130/// code rarely implements `Encode` directly — `Serialize` impls are written
131/// generically over `E: Encode` so a single impl works for every encoder
132/// flavour.
133///
134/// # Examples
135///
136/// ```
137/// use pack_io::{Encode, Encoder, Result};
138///
139/// // A helper that writes a length-prefixed list of `u32`s into any encoder.
140/// fn write_u32_list<E: Encode>(enc: &mut E, items: &[u32]) -> Result<()> {
141/// enc.write_varint_u64(items.len() as u64)?;
142/// for item in items {
143/// enc.write_varint_u64(u64::from(*item))?;
144/// }
145/// Ok(())
146/// }
147///
148/// let mut enc = Encoder::new();
149/// write_u32_list(&mut enc, &[1, 2, 3]).unwrap();
150/// ```
151pub trait Encode {
152 /// Append a single byte.
153 ///
154 /// # Errors
155 ///
156 /// Returns the encoder's underlying error variant (I/O failure for
157 /// streaming encoders; never errors for the in-memory [`Encoder`]).
158 fn write_byte(&mut self, byte: u8) -> Result<()>;
159
160 /// Append a slice of bytes.
161 ///
162 /// # Errors
163 ///
164 /// Same as [`Encode::write_byte`].
165 fn write_bytes(&mut self, bytes: &[u8]) -> Result<()>;
166
167 /// Hint that the caller is about to write `additional` more bytes.
168 ///
169 /// In-memory encoders MAY pre-allocate the requested capacity to avoid
170 /// intermediate `Vec` growth. Streaming encoders typically ignore the
171 /// hint. The default implementation is a no-op.
172 #[inline]
173 fn reserve(&mut self, additional: usize) {
174 let _ = additional;
175 }
176
177 /// Append a `u64` as an unsigned LEB128 varint (1–10 bytes).
178 ///
179 /// # Errors
180 ///
181 /// Same as [`Encode::write_bytes`].
182 #[inline]
183 fn write_varint_u64(&mut self, value: u64) -> Result<()> {
184 let mut buf = [0u8; varint::MAX_VARINT_LEN_U64];
185 let n = varint::write_u64(value, &mut buf);
186 self.write_bytes(&buf[..n])
187 }
188
189 /// Append a `u128` as an unsigned LEB128 varint (1–19 bytes).
190 ///
191 /// # Errors
192 ///
193 /// Same as [`Encode::write_bytes`].
194 #[inline]
195 fn write_varint_u128(&mut self, value: u128) -> Result<()> {
196 let mut buf = [0u8; varint::MAX_VARINT_LEN_U128];
197 let n = varint::write_u128(value, &mut buf);
198 self.write_bytes(&buf[..n])
199 }
200}
201
202/// Source that a [`Deserialize`] implementation reads its wire-format bytes
203/// from.
204///
205/// Implemented by every concrete decoder in the crate ([`Decoder`] for the
206/// in-memory case, [`crate::IoDecoder`] for `std::io::Read` streams). User
207/// code rarely implements `Decode` directly — `Deserialize` impls are
208/// written generically over `D: Decode`.
209///
210/// All methods are **total**: on any byte sequence they either succeed
211/// (advancing the cursor) or return a [`SerialError`]. They never panic,
212/// never read past the input, and never allocate more memory than
213/// [`Decode::max_alloc`] permits.
214pub trait Decode {
215 /// Read the next byte, advancing the cursor.
216 ///
217 /// # Errors
218 ///
219 /// Returns [`SerialError::UnexpectedEof`] if the input is exhausted.
220 /// Streaming decoders MAY return an I/O-flavoured error variant.
221 fn read_byte(&mut self) -> Result<u8>;
222
223 /// Fill `out` with exactly `out.len()` bytes, advancing the cursor.
224 ///
225 /// # Errors
226 ///
227 /// Returns [`SerialError::UnexpectedEof`] on short read.
228 fn read_into(&mut self, out: &mut [u8]) -> Result<()>;
229
230 /// Maximum number of bytes the decoder will allocate for a single
231 /// length-prefixed value. Mirrors [`Config::max_alloc`].
232 fn max_alloc(&self) -> usize;
233
234 /// Read a LEB128 varint as a `u64`.
235 ///
236 /// # Errors
237 ///
238 /// Returns [`SerialError::VarintOverflow`] for an overlong encoding,
239 /// or [`SerialError::UnexpectedEof`] for a truncated one.
240 #[inline]
241 fn read_varint_u64(&mut self) -> Result<u64> {
242 let mut result: u64 = 0;
243 let mut shift: u32 = 0;
244 for consumed in 1..=varint::MAX_VARINT_LEN_U64 {
245 let byte = self.read_byte()?;
246 // The 10th byte may only set bit 0 — anything else overflows u64.
247 if consumed == varint::MAX_VARINT_LEN_U64 && (byte & 0xfe) != 0 {
248 return Err(SerialError::VarintOverflow);
249 }
250 result |= u64::from(byte & 0x7f) << shift;
251 if byte & 0x80 == 0 {
252 return Ok(result);
253 }
254 shift += 7;
255 }
256 Err(SerialError::VarintOverflow)
257 }
258
259 /// Read a LEB128 varint as a `u128`.
260 ///
261 /// # Errors
262 ///
263 /// See [`Decode::read_varint_u64`].
264 #[inline]
265 fn read_varint_u128(&mut self) -> Result<u128> {
266 let mut result: u128 = 0;
267 let mut shift: u32 = 0;
268 for consumed in 1..=varint::MAX_VARINT_LEN_U128 {
269 let byte = self.read_byte()?;
270 // The 19th byte may only set the low two bits.
271 if consumed == varint::MAX_VARINT_LEN_U128 && (byte & 0xfc) != 0 {
272 return Err(SerialError::VarintOverflow);
273 }
274 result |= u128::from(byte & 0x7f) << shift;
275 if byte & 0x80 == 0 {
276 return Ok(result);
277 }
278 shift += 7;
279 }
280 Err(SerialError::VarintOverflow)
281 }
282
283 /// Read a length-prefixed byte run, allocating a fresh `Vec<u8>`.
284 ///
285 /// The length is read as a varint, validated against
286 /// [`Decode::max_alloc`], then the corresponding number of bytes is
287 /// read from the underlying source.
288 ///
289 /// # Errors
290 ///
291 /// - [`SerialError::InvalidLength`] if the prefix exceeds `max_alloc`.
292 /// - [`SerialError::UnexpectedEof`] if the source runs out before the
293 /// declared length is satisfied.
294 #[inline]
295 fn read_length_prefixed(&mut self) -> Result<Vec<u8>> {
296 let declared = self.read_varint_u64()?;
297 let max = self.max_alloc() as u64;
298 if declared > max {
299 return Err(SerialError::InvalidLength {
300 declared,
301 remaining: 0,
302 });
303 }
304 let len = declared as usize;
305 let mut buf = vec![0u8; len];
306 self.read_into(&mut buf)?;
307 Ok(buf)
308 }
309}
310
311// ---------------------------------------------------------------------------
312// In-memory Encoder
313// ---------------------------------------------------------------------------
314
315/// In-memory encoder. Writes into an owned `Vec<u8>`; the buffer can be
316/// reused across encodes by calling [`Encoder::take`] to swap it out.
317///
318/// Implements [`Encode`], so [`Serialize`] impls written generically over
319/// `E: Encode` work directly through it.
320///
321/// # Examples
322///
323/// ```
324/// use pack_io::Encoder;
325///
326/// let mut enc = Encoder::new();
327/// enc.write(&7_u64).unwrap();
328/// enc.write(&"hello").unwrap();
329/// let bytes = enc.into_inner();
330/// assert!(bytes.len() > 0);
331/// ```
332#[derive(Debug, Default)]
333pub struct Encoder {
334 out: Vec<u8>,
335}
336
337impl Encoder {
338 /// Construct an encoder with an empty output buffer.
339 ///
340 /// # Examples
341 ///
342 /// ```
343 /// let enc = pack_io::Encoder::new();
344 /// assert!(enc.as_bytes().is_empty());
345 /// ```
346 #[must_use]
347 pub fn new() -> Self {
348 Self { out: Vec::new() }
349 }
350
351 /// Construct an encoder backed by `buffer`. The encoder appends to the
352 /// buffer rather than allocating its own — callers that re-use a single
353 /// `Vec<u8>` across many encodes avoid the per-call allocation.
354 ///
355 /// # Examples
356 ///
357 /// ```
358 /// use pack_io::Encoder;
359 ///
360 /// let buf = Vec::with_capacity(64);
361 /// let mut enc = Encoder::into_buffer(buf);
362 /// enc.write(&42_u64).unwrap();
363 /// let buf = enc.into_inner();
364 /// assert!(!buf.is_empty());
365 /// ```
366 #[must_use]
367 pub fn into_buffer(buffer: Vec<u8>) -> Self {
368 Self { out: buffer }
369 }
370
371 /// Borrow the encoded bytes accumulated so far.
372 #[inline]
373 #[must_use]
374 pub fn as_bytes(&self) -> &[u8] {
375 &self.out
376 }
377
378 /// Consume the encoder and return its underlying buffer.
379 #[inline]
380 #[must_use]
381 pub fn into_inner(self) -> Vec<u8> {
382 self.out
383 }
384
385 /// Swap the encoder's buffer with a fresh empty one, returning the bytes
386 /// written so far. Useful for "encode then send" loops that want to
387 /// re-use the encoder.
388 #[must_use]
389 pub fn take(&mut self) -> Vec<u8> {
390 core::mem::take(&mut self.out)
391 }
392
393 /// Encode `value`, appending its bytes to the internal buffer.
394 ///
395 /// # Errors
396 ///
397 /// Propagates any error returned by the type's [`Serialize`]
398 /// implementation. Primitive impls in this crate never error on an
399 /// in-memory encoder.
400 #[inline]
401 pub fn write<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
402 value.serialize(self)
403 }
404}
405
406impl Encode for Encoder {
407 #[inline]
408 fn write_byte(&mut self, byte: u8) -> Result<()> {
409 self.out.push(byte);
410 Ok(())
411 }
412
413 #[inline]
414 fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
415 self.out.extend_from_slice(bytes);
416 Ok(())
417 }
418
419 #[inline]
420 fn reserve(&mut self, additional: usize) {
421 self.out.reserve(additional);
422 }
423}
424
425// ---------------------------------------------------------------------------
426// In-memory Decoder
427// ---------------------------------------------------------------------------
428
429/// In-memory decoder. Borrows from an input slice and advances a position
430/// pointer as values are read. Bounds-checked on every operation.
431///
432/// Implements [`Decode`], so [`Deserialize`] impls written generically over
433/// `D: Decode` work directly through it.
434///
435/// # Examples
436///
437/// ```
438/// use pack_io::{Encoder, Decoder};
439///
440/// let mut enc = Encoder::new();
441/// enc.write(&7_u64).unwrap();
442/// enc.write(&true).unwrap();
443/// let bytes = enc.into_inner();
444///
445/// let mut dec = Decoder::new(&bytes);
446/// let n: u64 = dec.read().unwrap();
447/// let b: bool = dec.read().unwrap();
448/// assert_eq!(n, 7);
449/// assert!(b);
450/// assert!(dec.is_empty());
451/// ```
452#[derive(Debug)]
453pub struct Decoder<'a> {
454 input: &'a [u8],
455 pos: usize,
456 config: Config,
457}
458
459impl<'a> Decoder<'a> {
460 /// Construct a decoder over `bytes`.
461 #[inline]
462 #[must_use]
463 pub fn new(bytes: &'a [u8]) -> Self {
464 Self {
465 input: bytes,
466 pos: 0,
467 config: Config::default(),
468 }
469 }
470
471 /// Construct a decoder with the supplied configuration.
472 ///
473 /// # Errors
474 ///
475 /// Returns [`SerialError::InvalidLength`] if `config.max_alloc == 0`.
476 pub fn with_config(bytes: &'a [u8], config: Config) -> Result<Self> {
477 Ok(Self {
478 input: bytes,
479 pos: 0,
480 config: config.validate()?,
481 })
482 }
483
484 /// Bytes consumed so far from the start of the input.
485 #[inline]
486 #[must_use]
487 pub fn position(&self) -> usize {
488 self.pos
489 }
490
491 /// Number of bytes remaining in the input.
492 #[inline]
493 #[must_use]
494 pub fn remaining(&self) -> usize {
495 self.input.len().saturating_sub(self.pos)
496 }
497
498 /// True when there are no more bytes to read.
499 #[inline]
500 #[must_use]
501 pub fn is_empty(&self) -> bool {
502 self.remaining() == 0
503 }
504
505 /// Decode a value of type `T` from the current position.
506 ///
507 /// # Errors
508 ///
509 /// Returns any [`SerialError`] surfaced by `T::deserialize`.
510 #[inline]
511 pub fn read<T: Deserialize>(&mut self) -> Result<T> {
512 T::deserialize(self)
513 }
514
515 /// Read a length-prefixed byte run as a **borrowed** slice of the
516 /// underlying input — no allocation, no copy.
517 ///
518 /// The borrowed slice has the same lifetime `'a` as the decoder's
519 /// input buffer, which lets caller-side `&'a str` / `&'a [u8]` decode
520 /// paths return a borrow directly into that buffer. This is the seam
521 /// the zero-copy [`crate::DeserializeView`] surface plugs into for
522 /// `&'a str` and `&'a [u8]`.
523 ///
524 /// # Errors
525 ///
526 /// - [`SerialError::InvalidLength`] if the prefix exceeds the
527 /// configured `max_alloc`, OR exceeds the remaining input.
528 /// - [`SerialError::UnexpectedEof`] is folded into `InvalidLength` for
529 /// this method, since the buffer length is known up front and a
530 /// declared length running off the end is logically a length-prefix
531 /// error, not a streaming EOF.
532 #[inline]
533 pub fn read_length_prefixed_borrowed(&mut self) -> Result<&'a [u8]> {
534 let declared = <Self as Decode>::read_varint_u64(self)?;
535 let max = self.config.max_alloc as u64;
536 if declared > max {
537 return Err(SerialError::InvalidLength {
538 declared,
539 remaining: self.remaining(),
540 });
541 }
542 let len = declared as usize;
543 let remaining = self.remaining();
544 if len > remaining {
545 return Err(SerialError::InvalidLength {
546 declared,
547 remaining,
548 });
549 }
550 let start = self.pos;
551 let end = start + len;
552 let slice = &self.input[start..end];
553 self.pos = end;
554 Ok(slice)
555 }
556}
557
558impl Decode for Decoder<'_> {
559 #[inline]
560 fn read_byte(&mut self) -> Result<u8> {
561 match self.input.get(self.pos) {
562 Some(&b) => {
563 self.pos += 1;
564 Ok(b)
565 }
566 None => Err(SerialError::UnexpectedEof {
567 needed: 1,
568 remaining: 0,
569 }),
570 }
571 }
572
573 #[inline]
574 fn read_into(&mut self, out: &mut [u8]) -> Result<()> {
575 let n = out.len();
576 let remaining = self.remaining();
577 if n > remaining {
578 return Err(SerialError::UnexpectedEof {
579 needed: n,
580 remaining,
581 });
582 }
583 let start = self.pos;
584 let end = start + n;
585 out.copy_from_slice(&self.input[start..end]);
586 self.pos = end;
587 Ok(())
588 }
589
590 #[inline]
591 fn max_alloc(&self) -> usize {
592 self.config.max_alloc
593 }
594
595 /// In-memory specialisation: validates length against the actual buffer
596 /// length too, not just `max_alloc`. Catches truncated inputs without
597 /// allocating.
598 #[inline]
599 fn read_length_prefixed(&mut self) -> Result<Vec<u8>> {
600 let declared = self.read_varint_u64()?;
601 let max = self.config.max_alloc as u64;
602 if declared > max {
603 return Err(SerialError::InvalidLength {
604 declared,
605 remaining: self.remaining(),
606 });
607 }
608 let len = declared as usize;
609 let remaining = self.remaining();
610 if len > remaining {
611 return Err(SerialError::InvalidLength {
612 declared,
613 remaining,
614 });
615 }
616 let start = self.pos;
617 let end = start + len;
618 let slice = &self.input[start..end];
619 self.pos = end;
620 Ok(slice.to_vec())
621 }
622}
623
624// ---------------------------------------------------------------------------
625// Tier-1 free functions
626// ---------------------------------------------------------------------------
627
628/// Encode `value` into a freshly allocated `Vec<u8>`.
629///
630/// This is the **Tier-1** entry point — the one-line surface for the common
631/// case. Allocates one buffer sized to fit the encoded value.
632///
633/// # Examples
634///
635/// ```
636/// let bytes = pack_io::encode(&42_u64).unwrap();
637/// let back: u64 = pack_io::decode(&bytes).unwrap();
638/// assert_eq!(back, 42);
639/// ```
640///
641/// # Errors
642///
643/// Propagates any error returned by the type's [`Serialize`] implementation.
644/// The built-in primitive and collection impls never error on an in-memory
645/// encoder.
646#[inline]
647pub fn encode<T: Serialize + ?Sized>(value: &T) -> Result<Vec<u8>> {
648 let mut enc = Encoder::new();
649 value.serialize(&mut enc)?;
650 Ok(enc.into_inner())
651}
652
653/// Peek the schema version of a payload produced by a `#[pack_io(version = N)]`
654/// type without consuming the buffer.
655///
656/// Reads only the leading varint and returns it as `u32`, leaving the
657/// caller free to dispatch decode to the right `T` based on what they find.
658/// On a non-versioned payload (no `#[pack_io(version = N)]` on the type)
659/// this returns whatever the first varint of the encoding happens to be —
660/// callers should only use it on payloads they know are versioned.
661///
662/// # Examples
663///
664/// ```
665/// # #[cfg(feature = "derive")] {
666/// use pack_io::{encode, peek_version, Serialize, Deserialize};
667///
668/// #[derive(Serialize, Deserialize)]
669/// #[pack_io(version = 2)]
670/// struct Msg { id: u64 }
671///
672/// let bytes = encode(&Msg { id: 7 }).unwrap();
673/// assert_eq!(peek_version(&bytes).unwrap(), 2);
674/// # }
675/// ```
676///
677/// # Errors
678///
679/// - [`SerialError::UnexpectedEof`] if `bytes` is empty or the leading
680/// varint is truncated.
681/// - [`SerialError::VarintOverflow`] / [`SerialError::IntegerOutOfRange`]
682/// if the leading varint does not fit in `u32`.
683#[inline]
684pub fn peek_version(bytes: &[u8]) -> Result<u32> {
685 let mut dec = Decoder::new(bytes);
686 let v = dec.read_varint_u64()?;
687 u32::try_from(v).map_err(|_| SerialError::IntegerOutOfRange)
688}
689
690/// Decode a value of type `T` from `bytes`, requiring the input to be fully
691/// consumed.
692///
693/// This is the **Tier-1** entry point — the one-line surface for the common
694/// case. After the value has been read, the decoder checks that no bytes
695/// remain; trailing input is reported as [`SerialError::TrailingBytes`].
696/// Callers that want to read several values from a single buffer should use
697/// [`Decoder`] directly.
698///
699/// # Examples
700///
701/// ```
702/// let bytes = pack_io::encode(&"hello").unwrap();
703/// let back: String = pack_io::decode(&bytes).unwrap();
704/// assert_eq!(back, "hello");
705/// ```
706///
707/// # Errors
708///
709/// - Returns [`SerialError::TrailingBytes`] when extra bytes follow the value.
710/// - Propagates any [`SerialError`] from the type's [`Deserialize`] impl.
711#[inline]
712pub fn decode<T: Deserialize>(bytes: &[u8]) -> Result<T> {
713 let mut dec = Decoder::new(bytes);
714 let value = T::deserialize(&mut dec)?;
715 let remaining = dec.remaining();
716 if remaining != 0 {
717 return Err(SerialError::TrailingBytes { remaining });
718 }
719 Ok(value)
720}
721
722#[cfg(test)]
723mod tests {
724 use super::*;
725
726 #[test]
727 fn config_default_has_one_gib_cap() {
728 let cfg = Config::default();
729 assert_eq!(cfg.max_alloc, 1 << 30);
730 }
731
732 #[test]
733 fn decoder_with_zero_cap_is_rejected() {
734 let cfg = Config::new().with_max_alloc(0);
735 let err = Decoder::with_config(&[], cfg).expect_err("zero cap is invalid");
736 assert!(matches!(err, SerialError::InvalidLength { .. }));
737 }
738
739 #[test]
740 fn encoder_into_buffer_reuses_caller_vec() {
741 let mut buf = Vec::with_capacity(64);
742 buf.push(0xff);
743 let mut enc = Encoder::into_buffer(buf);
744 enc.write(&7_u64).unwrap();
745 let out = enc.into_inner();
746 assert_eq!(out[0], 0xff);
747 assert!(out.len() > 1);
748 }
749
750 #[test]
751 fn encoder_take_returns_buffer_and_resets() {
752 let mut enc = Encoder::new();
753 enc.write(&1_u64).unwrap();
754 let first = enc.take();
755 assert!(!first.is_empty());
756 assert!(enc.as_bytes().is_empty());
757
758 enc.write(&2_u64).unwrap();
759 let second = enc.take();
760 assert_eq!(second, [0x02]);
761 }
762
763 #[test]
764 fn decode_rejects_trailing_bytes() {
765 let mut bytes = encode(&7_u8).unwrap();
766 bytes.push(0xff);
767 let err = decode::<u8>(&bytes).expect_err("trailing bytes should fail");
768 assert!(matches!(err, SerialError::TrailingBytes { remaining: 1 }));
769 }
770
771 #[test]
772 fn decoder_read_past_end_returns_unexpected_eof() {
773 let mut dec = Decoder::new(&[0x01]);
774 let _: u8 = dec.read().unwrap();
775 let err = dec.read::<u8>().expect_err("past end should fail");
776 assert!(matches!(err, SerialError::UnexpectedEof { .. }));
777 }
778
779 #[test]
780 fn decoder_length_prefix_above_cap_is_rejected() {
781 let cfg = Config::new().with_max_alloc(4);
782 let bytes = [0x05, b'h', b'e', b'l', b'l', b'o'];
783 let mut dec = Decoder::with_config(&bytes, cfg).expect("non-zero cap");
784 let err = dec
785 .read_length_prefixed()
786 .expect_err("length > cap should fail");
787 assert!(matches!(
788 err,
789 SerialError::InvalidLength { declared: 5, .. }
790 ));
791 }
792
793 #[test]
794 fn decoder_length_prefix_overflowing_remaining_is_rejected() {
795 let bytes = [0x10, b'a', b'b'];
796 let mut dec = Decoder::new(&bytes);
797 let err = dec
798 .read_length_prefixed()
799 .expect_err("length > remaining should fail");
800 assert!(matches!(err, SerialError::InvalidLength { .. }));
801 }
802
803 #[test]
804 fn decoder_position_advances_with_reads() {
805 let bytes = [0x01, 0x02, 0x03];
806 let mut dec = Decoder::new(&bytes);
807 assert_eq!(dec.position(), 0);
808 let _ = dec.read_byte().unwrap();
809 assert_eq!(dec.position(), 1);
810 let mut buf = [0u8; 2];
811 dec.read_into(&mut buf).unwrap();
812 assert_eq!(dec.position(), 3);
813 assert!(dec.is_empty());
814 }
815
816 #[test]
817 fn read_into_short_read_is_rejected() {
818 let mut dec = Decoder::new(&[0x01, 0x02]);
819 let mut buf = [0u8; 4];
820 let err = dec.read_into(&mut buf).expect_err("short read");
821 assert!(matches!(err, SerialError::UnexpectedEof { .. }));
822 }
823}