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 // Fast path for the overwhelmingly common case: value fits in a
185 // single byte. Skips the stack buffer + write_bytes round-trip.
186 if value < 0x80 {
187 return self.write_byte(value as u8);
188 }
189 let mut buf = [0u8; varint::MAX_VARINT_LEN_U64];
190 let n = varint::write_u64(value, &mut buf);
191 self.write_bytes(&buf[..n])
192 }
193
194 /// Append a `u128` as an unsigned LEB128 varint (1–19 bytes).
195 ///
196 /// # Errors
197 ///
198 /// Same as [`Encode::write_bytes`].
199 #[inline]
200 fn write_varint_u128(&mut self, value: u128) -> Result<()> {
201 let mut buf = [0u8; varint::MAX_VARINT_LEN_U128];
202 let n = varint::write_u128(value, &mut buf);
203 self.write_bytes(&buf[..n])
204 }
205}
206
207/// Source that a [`Deserialize`] implementation reads its wire-format bytes
208/// from.
209///
210/// Implemented by every concrete decoder in the crate ([`Decoder`] for the
211/// in-memory case, [`crate::IoDecoder`] for `std::io::Read` streams). User
212/// code rarely implements `Decode` directly — `Deserialize` impls are
213/// written generically over `D: Decode`.
214///
215/// All methods are **total**: on any byte sequence they either succeed
216/// (advancing the cursor) or return a [`SerialError`]. They never panic,
217/// never read past the input, and never allocate more memory than
218/// [`Decode::max_alloc`] permits.
219pub trait Decode {
220 /// Read the next byte, advancing the cursor.
221 ///
222 /// # Errors
223 ///
224 /// Returns [`SerialError::UnexpectedEof`] if the input is exhausted.
225 /// Streaming decoders MAY return an I/O-flavoured error variant.
226 fn read_byte(&mut self) -> Result<u8>;
227
228 /// Fill `out` with exactly `out.len()` bytes, advancing the cursor.
229 ///
230 /// # Errors
231 ///
232 /// Returns [`SerialError::UnexpectedEof`] on short read.
233 fn read_into(&mut self, out: &mut [u8]) -> Result<()>;
234
235 /// Maximum number of bytes the decoder will allocate for a single
236 /// length-prefixed value. Mirrors [`Config::max_alloc`].
237 fn max_alloc(&self) -> usize;
238
239 /// Read a LEB128 varint as a `u64`.
240 ///
241 /// # Errors
242 ///
243 /// Returns [`SerialError::VarintOverflow`] for an overlong encoding,
244 /// or [`SerialError::UnexpectedEof`] for a truncated one.
245 #[inline]
246 fn read_varint_u64(&mut self) -> Result<u64> {
247 // Fast path for single-byte varints (values 0..=127, the
248 // overwhelmingly common case for length prefixes and small ints).
249 let first = self.read_byte()?;
250 if first < 0x80 {
251 return Ok(u64::from(first));
252 }
253 let mut result: u64 = u64::from(first & 0x7f);
254 let mut shift: u32 = 7;
255 for consumed in 2..=varint::MAX_VARINT_LEN_U64 {
256 let byte = self.read_byte()?;
257 // The 10th byte may only set bit 0 — anything else overflows u64.
258 if consumed == varint::MAX_VARINT_LEN_U64 && (byte & 0xfe) != 0 {
259 return Err(SerialError::VarintOverflow);
260 }
261 result |= u64::from(byte & 0x7f) << shift;
262 if byte & 0x80 == 0 {
263 return Ok(result);
264 }
265 shift += 7;
266 }
267 Err(SerialError::VarintOverflow)
268 }
269
270 /// Read a LEB128 varint as a `u128`.
271 ///
272 /// # Errors
273 ///
274 /// See [`Decode::read_varint_u64`].
275 #[inline]
276 fn read_varint_u128(&mut self) -> Result<u128> {
277 let mut result: u128 = 0;
278 let mut shift: u32 = 0;
279 for consumed in 1..=varint::MAX_VARINT_LEN_U128 {
280 let byte = self.read_byte()?;
281 // The 19th byte may only set the low two bits.
282 if consumed == varint::MAX_VARINT_LEN_U128 && (byte & 0xfc) != 0 {
283 return Err(SerialError::VarintOverflow);
284 }
285 result |= u128::from(byte & 0x7f) << shift;
286 if byte & 0x80 == 0 {
287 return Ok(result);
288 }
289 shift += 7;
290 }
291 Err(SerialError::VarintOverflow)
292 }
293
294 /// Read a length-prefixed byte run, allocating a fresh `Vec<u8>`.
295 ///
296 /// The length is read as a varint, validated against
297 /// [`Decode::max_alloc`], then the corresponding number of bytes is
298 /// read from the underlying source.
299 ///
300 /// # Errors
301 ///
302 /// - [`SerialError::InvalidLength`] if the prefix exceeds `max_alloc`.
303 /// - [`SerialError::UnexpectedEof`] if the source runs out before the
304 /// declared length is satisfied.
305 #[inline]
306 fn read_length_prefixed(&mut self) -> Result<Vec<u8>> {
307 let declared = self.read_varint_u64()?;
308 let max = self.max_alloc() as u64;
309 if declared > max {
310 return Err(SerialError::InvalidLength {
311 declared,
312 remaining: 0,
313 });
314 }
315 let len = declared as usize;
316 let mut buf = vec![0u8; len];
317 self.read_into(&mut buf)?;
318 Ok(buf)
319 }
320}
321
322// ---------------------------------------------------------------------------
323// In-memory Encoder
324// ---------------------------------------------------------------------------
325
326/// In-memory encoder. Writes into an owned `Vec<u8>`; the buffer can be
327/// reused across encodes by calling [`Encoder::take`] to swap it out.
328///
329/// Implements [`Encode`], so [`Serialize`] impls written generically over
330/// `E: Encode` work directly through it.
331///
332/// # Examples
333///
334/// ```
335/// use pack_io::Encoder;
336///
337/// let mut enc = Encoder::new();
338/// enc.write(&7_u64).unwrap();
339/// enc.write(&"hello").unwrap();
340/// let bytes = enc.into_inner();
341/// assert!(bytes.len() > 0);
342/// ```
343#[derive(Debug, Default)]
344pub struct Encoder {
345 out: Vec<u8>,
346}
347
348impl Encoder {
349 /// Construct an encoder with an empty output buffer.
350 ///
351 /// # Examples
352 ///
353 /// ```
354 /// let enc = pack_io::Encoder::new();
355 /// assert!(enc.as_bytes().is_empty());
356 /// ```
357 #[must_use]
358 pub fn new() -> Self {
359 Self { out: Vec::new() }
360 }
361
362 /// Construct an encoder with an output buffer pre-allocated to
363 /// `capacity` bytes.
364 ///
365 /// Choose this over [`Encoder::new`] when the encoded size is roughly
366 /// known: a single `Vec::with_capacity` up front avoids the four to
367 /// eight grow-and-copy reallocations that a zero-capacity `Vec`
368 /// performs while doubling to the final size.
369 ///
370 /// `capacity` is a hint — the encoder still grows the buffer if the
371 /// encoded value exceeds it. Setting it slightly too high is harmless;
372 /// setting it slightly too low costs at most one growth.
373 ///
374 /// The Tier-1 [`crate::encode`] free function uses a small default
375 /// capacity internally so most one-shot encodes never grow at all.
376 ///
377 /// # Examples
378 ///
379 /// ```
380 /// let enc = pack_io::Encoder::with_capacity(256);
381 /// assert!(enc.as_bytes().is_empty());
382 /// ```
383 #[must_use]
384 pub fn with_capacity(capacity: usize) -> Self {
385 Self {
386 out: Vec::with_capacity(capacity),
387 }
388 }
389
390 /// Construct an encoder backed by `buffer`. The encoder appends to the
391 /// buffer rather than allocating its own — callers that re-use a single
392 /// `Vec<u8>` across many encodes avoid the per-call allocation.
393 ///
394 /// # Examples
395 ///
396 /// ```
397 /// use pack_io::Encoder;
398 ///
399 /// let buf = Vec::with_capacity(64);
400 /// let mut enc = Encoder::into_buffer(buf);
401 /// enc.write(&42_u64).unwrap();
402 /// let buf = enc.into_inner();
403 /// assert!(!buf.is_empty());
404 /// ```
405 #[must_use]
406 pub fn into_buffer(buffer: Vec<u8>) -> Self {
407 Self { out: buffer }
408 }
409
410 /// Borrow the encoded bytes accumulated so far.
411 #[inline]
412 #[must_use]
413 pub fn as_bytes(&self) -> &[u8] {
414 &self.out
415 }
416
417 /// Consume the encoder and return its underlying buffer.
418 #[inline]
419 #[must_use]
420 pub fn into_inner(self) -> Vec<u8> {
421 self.out
422 }
423
424 /// Swap the encoder's buffer with a fresh empty one, returning the bytes
425 /// written so far. Useful for "encode then send" loops that want to
426 /// re-use the encoder.
427 #[must_use]
428 pub fn take(&mut self) -> Vec<u8> {
429 core::mem::take(&mut self.out)
430 }
431
432 /// Encode `value`, appending its bytes to the internal buffer.
433 ///
434 /// # Errors
435 ///
436 /// Propagates any error returned by the type's [`Serialize`]
437 /// implementation. Primitive impls in this crate never error on an
438 /// in-memory encoder.
439 #[inline]
440 pub fn write<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<()> {
441 value.serialize(self)
442 }
443}
444
445impl Encode for Encoder {
446 #[inline(always)]
447 fn write_byte(&mut self, byte: u8) -> Result<()> {
448 self.out.push(byte);
449 Ok(())
450 }
451
452 #[inline(always)]
453 fn write_bytes(&mut self, bytes: &[u8]) -> Result<()> {
454 self.out.extend_from_slice(bytes);
455 Ok(())
456 }
457
458 #[inline(always)]
459 fn reserve(&mut self, additional: usize) {
460 self.out.reserve(additional);
461 }
462
463 /// Override of [`Encode::write_varint_u64`] specialised for the in-memory
464 /// encoder. Pushes each varint byte directly onto the underlying `Vec`,
465 /// reserving the full max-width up front so the loop never re-checks
466 /// capacity. Avoids the stack-buffer + `extend_from_slice` round-trip
467 /// the default impl would perform.
468 #[inline]
469 fn write_varint_u64(&mut self, value: u64) -> Result<()> {
470 if value < 0x80 {
471 self.out.push(value as u8);
472 return Ok(());
473 }
474 // Up to 10 bytes for u64. Reserve once, then push without further
475 // capacity checks.
476 self.out.reserve(varint::MAX_VARINT_LEN_U64);
477 let mut n = value;
478 while n >= 0x80 {
479 self.out.push((n as u8) | 0x80);
480 n >>= 7;
481 }
482 self.out.push(n as u8);
483 Ok(())
484 }
485
486 /// Same specialisation as [`Encode::write_varint_u64`], widened to 128
487 /// bits.
488 #[inline]
489 fn write_varint_u128(&mut self, value: u128) -> Result<()> {
490 if value < 0x80 {
491 self.out.push(value as u8);
492 return Ok(());
493 }
494 self.out.reserve(varint::MAX_VARINT_LEN_U128);
495 let mut n = value;
496 while n >= 0x80 {
497 self.out.push((n as u8) | 0x80);
498 n >>= 7;
499 }
500 self.out.push(n as u8);
501 Ok(())
502 }
503}
504
505// ---------------------------------------------------------------------------
506// In-memory Decoder
507// ---------------------------------------------------------------------------
508
509/// In-memory decoder. Borrows from an input slice and advances a position
510/// pointer as values are read. Bounds-checked on every operation.
511///
512/// Implements [`Decode`], so [`Deserialize`] impls written generically over
513/// `D: Decode` work directly through it.
514///
515/// # Examples
516///
517/// ```
518/// use pack_io::{Encoder, Decoder};
519///
520/// let mut enc = Encoder::new();
521/// enc.write(&7_u64).unwrap();
522/// enc.write(&true).unwrap();
523/// let bytes = enc.into_inner();
524///
525/// let mut dec = Decoder::new(&bytes);
526/// let n: u64 = dec.read().unwrap();
527/// let b: bool = dec.read().unwrap();
528/// assert_eq!(n, 7);
529/// assert!(b);
530/// assert!(dec.is_empty());
531/// ```
532#[derive(Debug)]
533pub struct Decoder<'a> {
534 input: &'a [u8],
535 pos: usize,
536 config: Config,
537}
538
539impl<'a> Decoder<'a> {
540 /// Construct a decoder over `bytes`.
541 #[inline]
542 #[must_use]
543 pub fn new(bytes: &'a [u8]) -> Self {
544 Self {
545 input: bytes,
546 pos: 0,
547 config: Config::default(),
548 }
549 }
550
551 /// Construct a decoder with the supplied configuration.
552 ///
553 /// # Errors
554 ///
555 /// Returns [`SerialError::InvalidLength`] if `config.max_alloc == 0`.
556 pub fn with_config(bytes: &'a [u8], config: Config) -> Result<Self> {
557 Ok(Self {
558 input: bytes,
559 pos: 0,
560 config: config.validate()?,
561 })
562 }
563
564 /// Bytes consumed so far from the start of the input.
565 #[inline]
566 #[must_use]
567 pub fn position(&self) -> usize {
568 self.pos
569 }
570
571 /// Number of bytes remaining in the input.
572 #[inline]
573 #[must_use]
574 pub fn remaining(&self) -> usize {
575 self.input.len().saturating_sub(self.pos)
576 }
577
578 /// True when there are no more bytes to read.
579 #[inline]
580 #[must_use]
581 pub fn is_empty(&self) -> bool {
582 self.remaining() == 0
583 }
584
585 /// Decode a value of type `T` from the current position.
586 ///
587 /// # Errors
588 ///
589 /// Returns any [`SerialError`] surfaced by `T::deserialize`.
590 #[inline]
591 pub fn read<T: Deserialize>(&mut self) -> Result<T> {
592 T::deserialize(self)
593 }
594
595 /// Read a length-prefixed byte run as a **borrowed** slice of the
596 /// underlying input — no allocation, no copy.
597 ///
598 /// The borrowed slice has the same lifetime `'a` as the decoder's
599 /// input buffer, which lets caller-side `&'a str` / `&'a [u8]` decode
600 /// paths return a borrow directly into that buffer. This is the seam
601 /// the zero-copy [`crate::DeserializeView`] surface plugs into for
602 /// `&'a str` and `&'a [u8]`.
603 ///
604 /// # Errors
605 ///
606 /// - [`SerialError::InvalidLength`] if the prefix exceeds the
607 /// configured `max_alloc`, OR exceeds the remaining input.
608 /// - [`SerialError::UnexpectedEof`] is folded into `InvalidLength` for
609 /// this method, since the buffer length is known up front and a
610 /// declared length running off the end is logically a length-prefix
611 /// error, not a streaming EOF.
612 #[inline]
613 pub fn read_length_prefixed_borrowed(&mut self) -> Result<&'a [u8]> {
614 let declared = <Self as Decode>::read_varint_u64(self)?;
615 let max = self.config.max_alloc as u64;
616 if declared > max {
617 return Err(SerialError::InvalidLength {
618 declared,
619 remaining: self.remaining(),
620 });
621 }
622 let len = declared as usize;
623 let remaining = self.remaining();
624 if len > remaining {
625 return Err(SerialError::InvalidLength {
626 declared,
627 remaining,
628 });
629 }
630 let start = self.pos;
631 let end = start + len;
632 let slice = &self.input[start..end];
633 self.pos = end;
634 Ok(slice)
635 }
636}
637
638impl Decode for Decoder<'_> {
639 #[inline]
640 fn read_byte(&mut self) -> Result<u8> {
641 match self.input.get(self.pos) {
642 Some(&b) => {
643 self.pos += 1;
644 Ok(b)
645 }
646 None => Err(SerialError::UnexpectedEof {
647 needed: 1,
648 remaining: 0,
649 }),
650 }
651 }
652
653 #[inline]
654 fn read_into(&mut self, out: &mut [u8]) -> Result<()> {
655 let n = out.len();
656 let remaining = self.remaining();
657 if n > remaining {
658 return Err(SerialError::UnexpectedEof {
659 needed: n,
660 remaining,
661 });
662 }
663 let start = self.pos;
664 let end = start + n;
665 out.copy_from_slice(&self.input[start..end]);
666 self.pos = end;
667 Ok(())
668 }
669
670 #[inline]
671 fn max_alloc(&self) -> usize {
672 self.config.max_alloc
673 }
674
675 /// In-memory specialisation: validates length against the actual buffer
676 /// length too, not just `max_alloc`. Catches truncated inputs without
677 /// allocating.
678 #[inline]
679 fn read_length_prefixed(&mut self) -> Result<Vec<u8>> {
680 let declared = self.read_varint_u64()?;
681 let max = self.config.max_alloc as u64;
682 if declared > max {
683 return Err(SerialError::InvalidLength {
684 declared,
685 remaining: self.remaining(),
686 });
687 }
688 let len = declared as usize;
689 let remaining = self.remaining();
690 if len > remaining {
691 return Err(SerialError::InvalidLength {
692 declared,
693 remaining,
694 });
695 }
696 let start = self.pos;
697 let end = start + len;
698 let slice = &self.input[start..end];
699 self.pos = end;
700 Ok(slice.to_vec())
701 }
702}
703
704// ---------------------------------------------------------------------------
705// Tier-1 free functions
706// ---------------------------------------------------------------------------
707
708/// Encode `value` into a freshly allocated `Vec<u8>`.
709///
710/// This is the **Tier-1** entry point — the one-line surface for the common
711/// case. Allocates one buffer sized to fit the encoded value.
712///
713/// # Examples
714///
715/// ```
716/// let bytes = pack_io::encode(&42_u64).unwrap();
717/// let back: u64 = pack_io::decode(&bytes).unwrap();
718/// assert_eq!(back, 42);
719/// ```
720///
721/// # Errors
722///
723/// Propagates any error returned by the type's [`Serialize`] implementation.
724/// The built-in primitive and collection impls never error on an in-memory
725/// encoder.
726#[inline]
727pub fn encode<T: Serialize + ?Sized>(value: &T) -> Result<Vec<u8>> {
728 // Pre-reserve enough to hold a typical small-to-medium message in a
729 // single allocation. A zero-capacity `Vec` doubles 8+ times before
730 // hitting 512 bytes, with each doubling memcpy-ing the prior contents
731 // — accounting for a large fraction of the encode-time gap vs codecs
732 // that pre-size their output buffer. 512 bytes covers most network
733 // messages without growth; larger payloads pay at most one or two
734 // doublings instead of the eight-plus a fresh `Vec` would.
735 let mut enc = Encoder::with_capacity(512);
736 value.serialize(&mut enc)?;
737 Ok(enc.into_inner())
738}
739
740/// Peek the schema version of a payload produced by a `#[pack_io(version = N)]`
741/// type without consuming the buffer.
742///
743/// Reads only the leading varint and returns it as `u32`, leaving the
744/// caller free to dispatch decode to the right `T` based on what they find.
745/// On a non-versioned payload (no `#[pack_io(version = N)]` on the type)
746/// this returns whatever the first varint of the encoding happens to be —
747/// callers should only use it on payloads they know are versioned.
748///
749/// # Examples
750///
751/// ```
752/// # #[cfg(feature = "derive")] {
753/// use pack_io::{encode, peek_version, Serialize, Deserialize};
754///
755/// #[derive(Serialize, Deserialize)]
756/// #[pack_io(version = 2)]
757/// struct Msg { id: u64 }
758///
759/// let bytes = encode(&Msg { id: 7 }).unwrap();
760/// assert_eq!(peek_version(&bytes).unwrap(), 2);
761/// # }
762/// ```
763///
764/// # Errors
765///
766/// - [`SerialError::UnexpectedEof`] if `bytes` is empty or the leading
767/// varint is truncated.
768/// - [`SerialError::VarintOverflow`] / [`SerialError::IntegerOutOfRange`]
769/// if the leading varint does not fit in `u32`.
770#[inline]
771pub fn peek_version(bytes: &[u8]) -> Result<u32> {
772 let mut dec = Decoder::new(bytes);
773 let v = dec.read_varint_u64()?;
774 u32::try_from(v).map_err(|_| SerialError::IntegerOutOfRange)
775}
776
777/// Decode a value of type `T` from `bytes`, requiring the input to be fully
778/// consumed.
779///
780/// This is the **Tier-1** entry point — the one-line surface for the common
781/// case. After the value has been read, the decoder checks that no bytes
782/// remain; trailing input is reported as [`SerialError::TrailingBytes`].
783/// Callers that want to read several values from a single buffer should use
784/// [`Decoder`] directly.
785///
786/// # Examples
787///
788/// ```
789/// let bytes = pack_io::encode(&"hello").unwrap();
790/// let back: String = pack_io::decode(&bytes).unwrap();
791/// assert_eq!(back, "hello");
792/// ```
793///
794/// # Errors
795///
796/// - Returns [`SerialError::TrailingBytes`] when extra bytes follow the value.
797/// - Propagates any [`SerialError`] from the type's [`Deserialize`] impl.
798#[inline]
799pub fn decode<T: Deserialize>(bytes: &[u8]) -> Result<T> {
800 let mut dec = Decoder::new(bytes);
801 let value = T::deserialize(&mut dec)?;
802 let remaining = dec.remaining();
803 if remaining != 0 {
804 return Err(SerialError::TrailingBytes { remaining });
805 }
806 Ok(value)
807}
808
809#[cfg(test)]
810mod tests {
811 use super::*;
812
813 #[test]
814 fn config_default_has_one_gib_cap() {
815 let cfg = Config::default();
816 assert_eq!(cfg.max_alloc, 1 << 30);
817 }
818
819 #[test]
820 fn decoder_with_zero_cap_is_rejected() {
821 let cfg = Config::new().with_max_alloc(0);
822 let err = Decoder::with_config(&[], cfg).expect_err("zero cap is invalid");
823 assert!(matches!(err, SerialError::InvalidLength { .. }));
824 }
825
826 #[test]
827 fn encoder_into_buffer_reuses_caller_vec() {
828 let mut buf = Vec::with_capacity(64);
829 buf.push(0xff);
830 let mut enc = Encoder::into_buffer(buf);
831 enc.write(&7_u64).unwrap();
832 let out = enc.into_inner();
833 assert_eq!(out[0], 0xff);
834 assert!(out.len() > 1);
835 }
836
837 #[test]
838 fn encoder_take_returns_buffer_and_resets() {
839 let mut enc = Encoder::new();
840 enc.write(&1_u64).unwrap();
841 let first = enc.take();
842 assert!(!first.is_empty());
843 assert!(enc.as_bytes().is_empty());
844
845 enc.write(&2_u64).unwrap();
846 let second = enc.take();
847 assert_eq!(second, [0x02]);
848 }
849
850 #[test]
851 fn decode_rejects_trailing_bytes() {
852 let mut bytes = encode(&7_u8).unwrap();
853 bytes.push(0xff);
854 let err = decode::<u8>(&bytes).expect_err("trailing bytes should fail");
855 assert!(matches!(err, SerialError::TrailingBytes { remaining: 1 }));
856 }
857
858 #[test]
859 fn decoder_read_past_end_returns_unexpected_eof() {
860 let mut dec = Decoder::new(&[0x01]);
861 let _: u8 = dec.read().unwrap();
862 let err = dec.read::<u8>().expect_err("past end should fail");
863 assert!(matches!(err, SerialError::UnexpectedEof { .. }));
864 }
865
866 #[test]
867 fn decoder_length_prefix_above_cap_is_rejected() {
868 let cfg = Config::new().with_max_alloc(4);
869 let bytes = [0x05, b'h', b'e', b'l', b'l', b'o'];
870 let mut dec = Decoder::with_config(&bytes, cfg).expect("non-zero cap");
871 let err = dec
872 .read_length_prefixed()
873 .expect_err("length > cap should fail");
874 assert!(matches!(
875 err,
876 SerialError::InvalidLength { declared: 5, .. }
877 ));
878 }
879
880 #[test]
881 fn decoder_length_prefix_overflowing_remaining_is_rejected() {
882 let bytes = [0x10, b'a', b'b'];
883 let mut dec = Decoder::new(&bytes);
884 let err = dec
885 .read_length_prefixed()
886 .expect_err("length > remaining should fail");
887 assert!(matches!(err, SerialError::InvalidLength { .. }));
888 }
889
890 #[test]
891 fn decoder_position_advances_with_reads() {
892 let bytes = [0x01, 0x02, 0x03];
893 let mut dec = Decoder::new(&bytes);
894 assert_eq!(dec.position(), 0);
895 let _ = dec.read_byte().unwrap();
896 assert_eq!(dec.position(), 1);
897 let mut buf = [0u8; 2];
898 dec.read_into(&mut buf).unwrap();
899 assert_eq!(dec.position(), 3);
900 assert!(dec.is_empty());
901 }
902
903 #[test]
904 fn read_into_short_read_is_rejected() {
905 let mut dec = Decoder::new(&[0x01, 0x02]);
906 let mut buf = [0u8; 4];
907 let err = dec.read_into(&mut buf).expect_err("short read");
908 assert!(matches!(err, SerialError::UnexpectedEof { .. }));
909 }
910}