Skip to main content

buffa/
message.rs

1//! The core [`Message`] trait and [`DecodeOptions`] builder.
2//!
3//! Every generated message type implements [`Message`], which provides
4//! encode/decode/merge methods and a two-pass serialization model
5//! (`compute_size` populates a [`SizeCache`](crate::SizeCache), `write_to`
6//! consumes it) that avoids the exponential-time problem affecting naïve
7//! length-delimited encoders.
8
9use crate::encode_sink::EncodeSink;
10use bytes::Buf;
11
12use crate::error::{DecodeError, EncodeError};
13use crate::message_field::DefaultInstance;
14
15/// Default recursion depth limit for decoding nested messages.
16///
17/// Protobuf implementations are required to enforce a recursion limit to
18/// prevent stack overflow from deeply nested messages in untrusted input.
19/// This value (100) matches the limit used by the official protobuf
20/// implementations and the protobuf conformance suite.
21///
22/// Pass this constant as the depth when constructing a [`DecodeContext`] for
23/// a top-level [`Message::merge`] call.  The provided convenience methods
24/// ([`Message::decode`], [`Message::decode_from_slice`],
25/// [`Message::merge_from_slice`]) use this limit automatically.
26pub const RECURSION_LIMIT: u32 = 100;
27
28/// Default limit on unknown fields decoded per top-level decode: 1,000,000.
29///
30/// Bounds the number of [`UnknownField`](crate::UnknownField) values the
31/// decoder will materialize in a single top-level decode, independent of
32/// the input size. Without this bound, wire data can force allocation far
33/// in excess of its own size: every 2-byte unknown varint field
34/// materialises a ~40-byte `UnknownField`, a ~20× amplification, so a
35/// 64 MiB payload of unknown fields would otherwise force over 1 GiB of
36/// heap. The count limit caps that overhead at roughly `limit × 40` bytes
37/// (~40 MB at the default); unknown length-delimited *payload* bytes are
38/// not counted against the limit because they are already bounded by the
39/// input size, which [`DecodeOptions::with_max_message_size`] governs.
40///
41/// A million unknown fields is far more than any realistic
42/// forward-compatibility scenario needs. Raise the limit with
43/// [`DecodeOptions::with_unknown_field_limit`] if you decode trusted
44/// messages that legitimately carry more (e.g. a proxy forwarding messages
45/// with a huge unpacked repeated field from a much newer schema).
46pub const DEFAULT_UNKNOWN_FIELD_LIMIT: usize = 1_000_000;
47
48/// Default element-memory budget: 32 MiB per top-level decode.
49///
50/// Bounds the memory a single decode may materialize in the elements of
51/// length-delimited containers — repeated message, string and bytes fields, and
52/// map entries — independent of the input size. These amplify the same way unknown fields do, and further: an
53/// empty repeated message element is 2 wire bytes and materializes
54/// `size_of::<T>()` in the `Vec` it lands in, measured at 256 bytes for a
55/// message of a few `Vec`/`String` fields — a 128x ratio, so 4 MiB of such
56/// elements would otherwise force ~512 MiB. Empty `bytes` and `string`
57/// elements amplify 16x and 12x by the same route.
58///
59/// A map entry is charged for both halves, key and value: an omitted message
60/// value still materializes in the map, and a few bytes of key buy a distinct
61/// slot, so `map<string, Message>` amplifies exactly as a repeated message does.
62///
63/// Only the element footprint is counted. The *contents* of a string or bytes
64/// element are not, being already bounded by the input size that
65/// [`DecodeOptions::with_max_message_size`] governs, and packed scalars are not
66/// charged at all: their worst case is a 1-byte varint becoming a 4-byte `i32`,
67/// which is not an amplification vector, and bounding them would reject
68/// legitimate columnar payloads that carry millions of elements by design.
69///
70/// 32 MiB of elements is far more than a realistic message carries, and sits
71/// alongside what [`DEFAULT_UNKNOWN_FIELD_LIMIT`] already permits (~38 MiB of
72/// `UnknownField`). Raise it with
73/// [`DecodeOptions::with_element_memory_limit`] for trusted inputs that
74/// legitimately decode into more. Note `Vec` grows by doubling, so peak
75/// resident memory can reach roughly twice the budget; this bounds what is
76/// materialized, not what the allocator reserves.
77pub const DEFAULT_ELEMENT_MEMORY_LIMIT: usize = 32 * 1024 * 1024;
78
79/// Per-decode limits threaded through every merge call.
80///
81/// Carries the remaining recursion depth and a shared unknown-field
82/// allowance. The context is `Copy` — passing it to a callee hands over the
83/// current depth by value, while the unknown-field allowance lives in a
84/// [`Cell`](core::cell::Cell) owned by the top-level decode entry point, so
85/// every field decoded under one entry point draws from the same
86/// allowance.
87///
88/// Constructed automatically by the [`Message`] convenience methods
89/// ([`decode`](Message::decode), [`decode_from_slice`](Message::decode_from_slice),
90/// [`merge_from_slice`](Message::merge_from_slice)) and by [`DecodeOptions`].
91/// Construct one manually only when calling [`Message::merge`] or the other
92/// depth-threading methods directly — and construct a **fresh limit cell
93/// per top-level decode**. Reusing one cell across decode calls makes the
94/// limit cumulative: each call drains it further until every decode fails
95/// with [`DecodeError::UnknownFieldLimitExceeded`].
96///
97/// ```rust
98/// # use buffa::__doctest_fixtures::Person;
99/// use core::cell::Cell;
100/// use buffa::{DecodeContext, Message, DEFAULT_UNKNOWN_FIELD_LIMIT, RECURSION_LIMIT};
101///
102/// # fn example(mut bytes: &[u8]) -> Result<(), buffa::DecodeError> {
103/// let limit = Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT);
104/// let mut msg = Person::default();
105/// msg.merge(&mut bytes, DecodeContext::new(RECURSION_LIMIT, &limit))?;
106/// # Ok(())
107/// # }
108/// ```
109#[derive(Clone, Copy, Debug)]
110pub struct DecodeContext<'a> {
111    depth: u32,
112    unknown_fields_remaining: &'a core::cell::Cell<usize>,
113    element_memory_remaining: Option<&'a core::cell::Cell<usize>>,
114}
115
116impl<'a> DecodeContext<'a> {
117    /// Create a context with `depth` remaining recursion levels and the
118    /// remaining unknown-field allowance stored in `unknown_field_limit`.
119    #[must_use]
120    pub fn new(depth: u32, unknown_field_limit: &'a core::cell::Cell<usize>) -> Self {
121        Self {
122            depth,
123            unknown_fields_remaining: unknown_field_limit,
124            element_memory_remaining: None,
125        }
126    }
127
128    /// Attach the shared element-memory budget in `element_memory_limit`.
129    ///
130    /// Without this the budget is absent and [`register_element_memory`] is a
131    /// no-op, which is what a [`DecodeContext::new`] built elsewhere — older
132    /// generated code, say — gets. buffa's own entry points attach it, so a
133    /// decode through [`DecodeOptions`] or the [`Message`] conveniences is
134    /// bounded by [`DEFAULT_ELEMENT_MEMORY_LIMIT`].
135    ///
136    /// Attach a **fresh cell per top-level decode**, for the same reason the
137    /// unknown-field allowance needs one: a reused cell drains across calls.
138    ///
139    /// [`register_element_memory`]: DecodeContext::register_element_memory
140    #[must_use]
141    pub fn with_element_memory(
142        mut self,
143        element_memory_limit: &'a core::cell::Cell<usize>,
144    ) -> Self {
145        self.element_memory_remaining = Some(element_memory_limit);
146        self
147    }
148
149    /// The remaining recursion depth.
150    #[must_use]
151    pub fn depth(&self) -> u32 {
152        self.depth
153    }
154
155    /// The number of additional unknown fields this decode may materialize.
156    #[must_use]
157    pub fn remaining_unknown_fields(&self) -> usize {
158        self.unknown_fields_remaining.get()
159    }
160
161    /// Consume one level of recursion depth.
162    ///
163    /// # Errors
164    ///
165    /// Returns [`DecodeError::RecursionLimitExceeded`] when the depth budget
166    /// is exhausted.
167    pub fn descend(self) -> Result<Self, DecodeError> {
168        let depth = self
169            .depth
170            .checked_sub(1)
171            .ok_or(DecodeError::RecursionLimitExceeded)?;
172        Ok(Self { depth, ..self })
173    }
174
175    /// Consume one slot of the shared unknown-field allowance.
176    ///
177    /// Call **before** materializing an [`UnknownField`](crate::UnknownField).
178    ///
179    /// # Errors
180    ///
181    /// Returns [`DecodeError::UnknownFieldLimitExceeded`] (leaving the
182    /// allowance unchanged) when no slots remain.
183    pub fn register_unknown_field(&self) -> Result<(), DecodeError> {
184        let remaining = self.unknown_fields_remaining.get();
185        if remaining == 0 {
186            return Err(DecodeError::UnknownFieldLimitExceeded);
187        }
188        self.unknown_fields_remaining.set(remaining - 1);
189        Ok(())
190    }
191
192    /// The element-memory budget left to this decode, or `None` when no budget
193    /// is attached.
194    #[must_use]
195    pub fn remaining_element_memory(&self) -> Option<usize> {
196        self.element_memory_remaining.map(core::cell::Cell::get)
197    }
198
199    /// Charge `bytes` against the shared element-memory budget.
200    ///
201    /// Call **before** materializing an element of a repeated
202    /// length-delimited field, passing that element's `size_of`. Those are the
203    /// fields where the wire is far cheaper than what it decodes into: an empty
204    /// message element is two bytes and costs `size_of::<T>()`, so a payload
205    /// well inside [`DecodeOptions::with_max_message_size`] can still expand by
206    /// two orders of magnitude. Packed scalars are not charged — their worst
207    /// case is a 1-byte varint becoming a 4-byte `i32`, and bounding them would
208    /// reject legitimate columnar payloads.
209    ///
210    /// No-op when no budget is attached (see
211    /// [`with_element_memory`](DecodeContext::with_element_memory)).
212    ///
213    /// # Errors
214    ///
215    /// Returns [`DecodeError::ElementMemoryLimitExceeded`] (leaving the budget
216    /// unchanged) when `bytes` exceeds what remains.
217    pub fn register_element_memory(&self, bytes: usize) -> Result<(), DecodeError> {
218        let Some(cell) = self.element_memory_remaining else {
219            return Ok(());
220        };
221        let remaining = cell.get();
222        if bytes > remaining {
223            return Err(DecodeError::ElementMemoryLimitExceeded);
224        }
225        cell.set(remaining - bytes);
226        Ok(())
227    }
228}
229
230/// Maximum encoded size of a protobuf message: 2 GiB − 1 (`0x7FFF_FFFF`).
231///
232/// The protobuf specification limits any message — top-level or nested — to
233/// 2 GiB. buffa enforces this symmetrically:
234///
235/// - **Decode** rejects length-delimited payloads declared larger than this
236///   with [`DecodeError::MessageTooLarge`], matching protobuf C++ and Java.
237/// - **Encode** refuses to serialize a message whose encoded size would
238///   exceed it: the panicking entry points ([`Message::encode`] and friends)
239///   panic, the `try_*` twins ([`Message::try_encode`] and friends) return
240///   [`EncodeError::MessageTooLarge`]. Without this check a writer could
241///   produce bytes that no conforming decoder — including buffa's own —
242///   will read back.
243pub const MAX_MESSAGE_BYTES: u32 = 0x7FFF_FFFF;
244
245/// Saturate a `u64` size accumulator to `u32`.
246///
247/// Generated `compute_size` implementations accumulate in `u64` (which
248/// cannot overflow for any message that fits in memory) and saturate to
249/// `u32` once at each message node's return. A saturated value is
250/// necessarily greater than [`MAX_MESSAGE_BYTES`], so any over-limit
251/// message — whether from one huge field or from aggregation — surfaces at
252/// the encode entry points' size check; the byte-exact value is preserved
253/// for every message the wire format can actually represent.
254///
255/// Manual [`Message`] implementations should use the same pattern:
256/// accumulate the encoded size in a `u64` and `saturate_size` it at return.
257#[inline]
258#[must_use]
259pub fn saturate_size(size: u64) -> u32 {
260    u32::try_from(size).unwrap_or(u32::MAX)
261}
262
263/// Validate a computed encode size against [`MAX_MESSAGE_BYTES`].
264///
265/// The error-returning half of the encode-size funnel: the `try_encode*`
266/// methods (and generated inherent encode entry points, e.g. on lazy view
267/// types) validate their [`compute_size`](Message::compute_size) result
268/// through this before writing anything.
269///
270/// # Errors
271///
272/// Returns [`EncodeError::MessageTooLarge`] if `size` exceeds
273/// [`MAX_MESSAGE_BYTES`].
274#[inline]
275pub fn checked_encode_size(size: u32) -> Result<u32, EncodeError> {
276    if size > MAX_MESSAGE_BYTES {
277        Err(EncodeError::MessageTooLarge)
278    } else {
279        Ok(size)
280    }
281}
282
283/// Debug-build two-pass coherence ledger: asserts `write_to` produced
284/// exactly the byte count `compute_size` declared.
285///
286/// Called by the provided `encode_to_vec` / `encode_to_bytes` entry points
287/// (and their generated lazy-view counterparts) after the write pass. The
288/// write pass is ground truth — leaf writers emit `len as u64` prefixes and
289/// full payloads — so any divergence indicates a size-pass bug (wrong
290/// presence check, traversal drift) in a generated or manual
291/// implementation. Free in release builds.
292#[doc(hidden)]
293#[inline]
294#[track_caller]
295pub fn debug_assert_two_pass(written: usize, declared: usize) {
296    debug_assert_eq!(
297        written, declared,
298        "write_to produced a different byte count than compute_size \
299         declared (two-pass traversal mismatch)"
300    );
301}
302
303/// Panic shim shared by every panicking encode entry point — the provided
304/// `Message` / `ViewEncode` methods, `SizeCachePool`, and generated
305/// lazy-view inherent methods all delegate to their `try_*` twin and route
306/// the `Err` here, so the panicking and fallible paths cannot diverge.
307///
308/// # Panics
309///
310/// Always — that is its entire job: one cold, out-of-line panic site with
311/// the canonical over-limit message.
312#[doc(hidden)]
313#[cold]
314#[inline(never)]
315pub fn encode_size_overflow() -> ! {
316    panic!(
317        "message encoded size exceeds the 2 GiB protobuf limit \
318         (the try_* variant of this method returns this as an error instead)"
319    )
320}
321
322/// The core trait implemented by all protobuf message types.
323///
324/// This trait is implemented by **generated code** — you write a `.proto` file,
325/// codegen emits the Rust struct and its `Message` impl. You should almost
326/// never implement this trait by hand.
327///
328/// # Manual implementation is discouraged
329///
330/// The only reason to implement `Message` yourself is when you need a
331/// custom in-memory representation that codegen cannot produce — for
332/// example, wrapping a `std::ops::Range<i64>` as a leaf message so the
333/// rest of your code uses the natural Rust type. If you just want a message
334/// type, **write a `.proto` file instead.**
335///
336/// Manual implementation is intentionally high-friction:
337/// - You must correctly implement the two-pass serialization contract
338///   (`compute_size` populates the [`SizeCache`](crate::SizeCache) in the
339///   same traversal order that `write_to` consumes it).
340/// - You must implement wire-format decoding in `merge_field`.
341/// - You must implement the [`DefaultInstance`] supertrait, which provides
342///   the lazily-initialized static default that [`MessageField`](crate::MessageField)
343///   dereferences to when unset.
344///
345/// If you still need to do this, see the [custom types section of the
346/// user guide](https://github.com/anthropics/buffa/blob/main/docs/guide.md#custom-type-implementations)
347/// for a complete worked example.
348///
349/// # Serialization model
350///
351/// Serialization is a two-pass process to avoid the exponential-time problem
352/// that affects prost with deeply nested messages:
353///
354/// 1. **`compute_size()`** — walks the message tree and records the encoded
355///    size of every length-delimited sub-message in a [`SizeCache`].
356/// 2. **`write_to()`** — walks the tree again, writing bytes and consuming
357///    cached sizes for length-prefixed sub-messages.
358///
359/// The provided [`encode`](Self::encode) method performs both passes with a
360/// fresh [`SizeCache`] — most callers use that and never touch the cache
361/// directly. `compute_size` / `write_to` take the cache explicitly so that
362/// manual `Message` implementations can thread it through nested-message
363/// recursion.
364///
365/// # Thread safety
366///
367/// `Message` requires `Send + Sync`. Generated structs contain no interior
368/// mutability — serialization state lives in the external [`SizeCache`], not
369/// in the message — so messages can be placed in an `Arc` and shared across
370/// threads freely. `merge` requires `&mut self`, so mutation is exclusive.
371///
372/// # Struct evolution policy
373///
374/// Generated message structs (and their [`MessageView`](crate::MessageView) /
375/// [`LazyMessageView`](crate::LazyMessageView) counterparts) may gain fields
376/// across releases — both when the source `.proto` schema evolves and when
377/// buffa adds internal bookkeeping such as `__buffa_unknown_fields` or the
378/// required-field presence bitmaps. **Exhaustive struct literals and
379/// exhaustive destructuring patterns are not covered by buffa's semver
380/// guarantees**: code that names every field will fail to compile when a field
381/// is added, and that breakage is not considered a breaking change.
382///
383/// The forward-compatible ways to construct a generated struct are:
384///
385/// - decode it from bytes;
386/// - struct-update syntax over the default: `Foo { x, y, ..Default::default() }`;
387/// - start from `Foo::default()` and assign fields (or call generated `with_*`
388///   setters when `generate_with_setters` is enabled).
389///
390/// The structs are deliberately *not* `#[non_exhaustive]`, so struct-update
391/// syntax remains available from downstream crates; this policy is a documented
392/// contract rather than a compiler-enforced one.
393///
394/// [`SizeCache`]: crate::SizeCache
395pub trait Message: DefaultInstance + Clone + PartialEq + Send + Sync {
396    /// Compute the encoded byte size of this message, recording nested
397    /// sub-message sizes in `cache` for `write_to` to consume.
398    ///
399    /// Most callers should use [`encode`](Self::encode) instead, which runs
400    /// both passes with a fresh cache. Manual `Message` implementations call
401    /// this recursively on nested message fields, wrapping each call in
402    /// [`SizeCache::reserve`] / [`SizeCache::set`] for length-delimited
403    /// fields — see the user guide's custom-types section for the pattern.
404    ///
405    /// # Size limit
406    ///
407    /// The protobuf specification limits messages to 2 GiB
408    /// ([`MAX_MESSAGE_BYTES`]). Generated implementations accumulate in
409    /// `u64` and saturate the return value via [`saturate_size`], so an
410    /// over-limit message yields a return greater than [`MAX_MESSAGE_BYTES`]
411    /// rather than a wrapped value; the provided encode methods check this
412    /// and refuse to produce over-limit output. Manual implementations must
413    /// follow the same pattern — if their arithmetic can wrap, over-limit
414    /// messages may encode corrupt bytes that bypass the check.
415    ///
416    /// [`SizeCache::reserve`]: crate::SizeCache::reserve
417    /// [`SizeCache::set`]: crate::SizeCache::set
418    fn compute_size(&self, cache: &mut crate::SizeCache) -> u32;
419
420    /// Write this message's encoded bytes to a buffer, consuming
421    /// nested-message sizes from `cache` (populated by a prior
422    /// `compute_size` call on the same cache).
423    ///
424    /// Most callers should use [`encode`](Self::encode) instead. This is a
425    /// low-level primitive: the 2 GiB size check ([`MAX_MESSAGE_BYTES`])
426    /// lives in the provided encode entry points, so callers driving
427    /// `compute_size` / `write_to` directly must validate the size
428    /// themselves (via [`checked_encode_size`]).
429    fn write_to(&self, cache: &mut crate::SizeCache, buf: &mut impl EncodeSink);
430
431    /// Compute size, then write. This is the primary encoding API.
432    ///
433    /// The sink can be any [`BufMut`](bytes::BufMut) (contiguous output) or
434    /// a [`Rope`](crate::Rope), which captures large `bytes::Bytes` fields
435    /// as reference-counted segments for zero-copy handoff to networking
436    /// code — see [`encode_sink`](crate::encode_sink).
437    ///
438    /// # Panics
439    ///
440    /// Panics if the encoded size exceeds the 2 GiB protobuf limit
441    /// ([`MAX_MESSAGE_BYTES`]) — see [`try_encode`](Self::try_encode) for
442    /// the error-returning variant.
443    #[inline]
444    fn encode(&self, buf: &mut impl EncodeSink) {
445        self.try_encode(buf)
446            .unwrap_or_else(|_| encode_size_overflow())
447    }
448
449    /// Encode, returning an error instead of panicking if the encoded size
450    /// exceeds the 2 GiB protobuf limit ([`MAX_MESSAGE_BYTES`]).
451    ///
452    /// On `Err`, nothing is written to `buf`.
453    ///
454    /// # Errors
455    ///
456    /// Returns [`EncodeError::MessageTooLarge`] if the encoded size exceeds
457    /// [`MAX_MESSAGE_BYTES`].
458    fn try_encode(&self, buf: &mut impl EncodeSink) -> Result<(), EncodeError> {
459        let mut cache = crate::SizeCache::new();
460        checked_encode_size(self.compute_size(&mut cache))?;
461        self.write_to(&mut cache, buf);
462        Ok(())
463    }
464
465    /// Encode using a caller-supplied [`SizeCache`](crate::SizeCache), for
466    /// reuse across many encodes in a hot loop. Clears the cache first.
467    ///
468    /// # Panics
469    ///
470    /// Panics if the encoded size exceeds the 2 GiB protobuf limit
471    /// ([`MAX_MESSAGE_BYTES`]) — see
472    /// [`try_encode_with_cache`](Self::try_encode_with_cache) for the
473    /// error-returning variant.
474    #[inline]
475    fn encode_with_cache(&self, cache: &mut crate::SizeCache, buf: &mut impl EncodeSink) {
476        self.try_encode_with_cache(cache, buf)
477            .unwrap_or_else(|_| encode_size_overflow())
478    }
479
480    /// Encode with a caller-supplied [`SizeCache`](crate::SizeCache),
481    /// returning an error instead of panicking if the encoded size exceeds
482    /// the 2 GiB protobuf limit ([`MAX_MESSAGE_BYTES`]). Clears the cache
483    /// first.
484    ///
485    /// On `Err`, nothing is written to `buf`.
486    ///
487    /// # Errors
488    ///
489    /// Returns [`EncodeError::MessageTooLarge`] if the encoded size exceeds
490    /// [`MAX_MESSAGE_BYTES`].
491    fn try_encode_with_cache(
492        &self,
493        cache: &mut crate::SizeCache,
494        buf: &mut impl EncodeSink,
495    ) -> Result<(), EncodeError> {
496        cache.clear();
497        checked_encode_size(self.compute_size(cache))?;
498        self.write_to(cache, buf);
499        Ok(())
500    }
501
502    /// Encode this message into `buf` only if its encoded size fits within
503    /// `max_bytes`, using a single size pass that is then reused for the write.
504    ///
505    /// This avoids the double tree-walk that `try_encoded_len` + `encode`
506    /// would require: one `compute_size` pass populates the [`SizeCache`];
507    /// the budget check happens before `write_to` runs, so on `Err` nothing
508    /// is written to `buf`.
509    ///
510    /// Returns the encoded body length on success (excludes any length prefix
511    /// you add for framing) — useful for metrics or frame sizing. Note that
512    /// this return type is `u32`, unlike `try_encode`'s `()`. `max_bytes` is
513    /// also `u32` to match the encode-size domain; callers with a `usize`
514    /// budget can cast with `u32::try_from(budget).unwrap_or(u32::MAX)`.
515    ///
516    /// # Errors
517    ///
518    /// - [`EncodeError::MessageTooLarge`] if the encoded size exceeds the
519    ///   2 GiB protobuf limit ([`MAX_MESSAGE_BYTES`]).
520    ///   `MessageTooLarge` takes precedence if both limits are exceeded.
521    /// - [`EncodeError::ExceedsBudget`] if the encoded size is within the
522    ///   protobuf limit but exceeds `max_bytes`.
523    ///
524    /// [`SizeCache`]: crate::SizeCache
525    fn try_encode_bounded(
526        &self,
527        max_bytes: u32,
528        buf: &mut impl EncodeSink,
529    ) -> Result<u32, EncodeError> {
530        let mut cache = crate::SizeCache::new();
531        self.try_encode_bounded_with_cache(max_bytes, &mut cache, buf)
532    }
533
534    /// Like [`try_encode_bounded`](Self::try_encode_bounded) but reuses an
535    /// existing [`SizeCache`], clearing it first.
536    ///
537    /// Prefer [`SizeCachePool::try_encode_bounded`](crate::SizeCachePool::try_encode_bounded)
538    /// for hot-loop use — the pool amortizes the cache's spill allocation.
539    ///
540    /// # Errors
541    ///
542    /// Same as [`try_encode_bounded`](Self::try_encode_bounded).
543    ///
544    /// [`SizeCache`]: crate::SizeCache
545    fn try_encode_bounded_with_cache(
546        &self,
547        max_bytes: u32,
548        cache: &mut crate::SizeCache,
549        buf: &mut impl EncodeSink,
550    ) -> Result<u32, EncodeError> {
551        cache.clear();
552        let len = checked_encode_size(self.compute_size(cache))?;
553        if len > max_bytes {
554            return Err(EncodeError::ExceedsBudget { len, max_bytes });
555        }
556        self.write_to(cache, buf);
557        Ok(len)
558    }
559
560    /// Compute the encoded byte size of this message.
561    ///
562    /// Walks the message tree, discarding the intermediate [`SizeCache`].
563    /// If you also intend to encode, prefer [`encode`](Self::encode) or
564    /// [`encode_to_vec`](Self::encode_to_vec) — they do a single size pass
565    /// and reuse the cache for the write.
566    ///
567    /// # Panics
568    ///
569    /// Panics if the encoded size exceeds the 2 GiB protobuf limit
570    /// ([`MAX_MESSAGE_BYTES`]) — see [`try_encoded_len`](Self::try_encoded_len)
571    /// for the error-returning variant.
572    ///
573    /// [`SizeCache`]: crate::SizeCache
574    #[inline]
575    #[must_use]
576    fn encoded_len(&self) -> u32 {
577        self.try_encoded_len()
578            .unwrap_or_else(|_| encode_size_overflow())
579    }
580
581    /// Compute the encoded byte size, returning an error instead of
582    /// panicking if it exceeds the 2 GiB protobuf limit
583    /// ([`MAX_MESSAGE_BYTES`]).
584    ///
585    /// # Errors
586    ///
587    /// Returns [`EncodeError::MessageTooLarge`] if the encoded size exceeds
588    /// [`MAX_MESSAGE_BYTES`].
589    fn try_encoded_len(&self) -> Result<u32, EncodeError> {
590        checked_encode_size(self.compute_size(&mut crate::SizeCache::new()))
591    }
592
593    /// Encode this message as a length-delimited byte sequence.
594    ///
595    /// # Panics
596    ///
597    /// Panics if the encoded size exceeds the 2 GiB protobuf limit
598    /// ([`MAX_MESSAGE_BYTES`]); the check runs before the length prefix is
599    /// written, so nothing reaches `buf` on failure. See
600    /// [`try_encode_length_delimited`](Self::try_encode_length_delimited)
601    /// for the error-returning variant.
602    #[inline]
603    fn encode_length_delimited(&self, buf: &mut impl EncodeSink) {
604        self.try_encode_length_delimited(buf)
605            .unwrap_or_else(|_| encode_size_overflow())
606    }
607
608    /// Encode as a length-delimited byte sequence, returning an error
609    /// instead of panicking if the encoded size exceeds the 2 GiB protobuf
610    /// limit ([`MAX_MESSAGE_BYTES`]).
611    ///
612    /// On `Err`, nothing is written to `buf`.
613    ///
614    /// # Errors
615    ///
616    /// Returns [`EncodeError::MessageTooLarge`] if the encoded size exceeds
617    /// [`MAX_MESSAGE_BYTES`].
618    fn try_encode_length_delimited(&self, buf: &mut impl EncodeSink) -> Result<(), EncodeError> {
619        let mut cache = crate::SizeCache::new();
620        let len = checked_encode_size(self.compute_size(&mut cache))?;
621        crate::encoding::encode_varint(len as u64, buf);
622        self.write_to(&mut cache, buf);
623        Ok(())
624    }
625
626    /// Encode this message to a new `Vec<u8>`.
627    ///
628    /// # Panics
629    ///
630    /// Panics if the encoded size exceeds the 2 GiB protobuf limit
631    /// ([`MAX_MESSAGE_BYTES`]) — see
632    /// [`try_encode_to_vec`](Self::try_encode_to_vec) for the
633    /// error-returning variant. In debug builds, also panics if a manual
634    /// implementation's `write_to` produces a different byte count than
635    /// its `compute_size` declared.
636    // Direct body rather than delegating to try_encode_to_vec: LLVM does
637    // not fold the Result<Vec<u8>> niche away even under full inlining, so
638    // the delegating form re-checks the capacity sentinel and round-trips
639    // the Vec through a Result temp in every caller — measured +7.5% on
640    // dense-small-message encode (google_message1, quieted metal,
641    // layout-normalized). Same for encode_to_bytes. The unit- and
642    // scalar-returning entry points delegate — their Results stay in
643    // registers and fold cleanly.
644    #[inline]
645    #[must_use]
646    fn encode_to_vec(&self) -> alloc::vec::Vec<u8> {
647        let mut cache = crate::SizeCache::new();
648        let size = match checked_encode_size(self.compute_size(&mut cache)) {
649            Ok(size) => size as usize,
650            Err(_) => encode_size_overflow(),
651        };
652        let mut buf = alloc::vec::Vec::with_capacity(size);
653        self.write_to(&mut cache, &mut buf);
654        debug_assert_two_pass(buf.len(), size);
655        buf
656    }
657
658    /// Encode to a new `Vec<u8>`, returning an error instead of panicking
659    /// if the encoded size exceeds the 2 GiB protobuf limit
660    /// ([`MAX_MESSAGE_BYTES`]).
661    ///
662    /// # Errors
663    ///
664    /// Returns [`EncodeError::MessageTooLarge`] if the encoded size exceeds
665    /// [`MAX_MESSAGE_BYTES`].
666    ///
667    /// # Panics
668    ///
669    /// In debug builds, panics if a manual implementation's `write_to`
670    /// produces a different byte count than its `compute_size` declared.
671    fn try_encode_to_vec(&self) -> Result<alloc::vec::Vec<u8>, EncodeError> {
672        let mut cache = crate::SizeCache::new();
673        let size = checked_encode_size(self.compute_size(&mut cache))? as usize;
674        let mut buf = alloc::vec::Vec::with_capacity(size);
675        self.write_to(&mut cache, &mut buf);
676        debug_assert_two_pass(buf.len(), size);
677        Ok(buf)
678    }
679
680    /// Encode this message to a new [`bytes::Bytes`].
681    ///
682    /// Useful when handing off to networking code (hyper, tonic, axum)
683    /// that expects `Bytes` frame or body payloads. Works in `no_std`.
684    ///
685    /// This is equivalent to `Bytes::from(self.encode_to_vec())` — both
686    /// are zero-copy with respect to the encoded bytes — but saves readers
687    /// from having to know that `From<Vec<u8>> for Bytes` is zero-copy.
688    ///
689    /// # Panics
690    ///
691    /// Panics if the encoded size exceeds the 2 GiB protobuf limit
692    /// ([`MAX_MESSAGE_BYTES`]) — see
693    /// [`try_encode_to_bytes`](Self::try_encode_to_bytes) for the
694    /// error-returning variant. In debug builds, also panics if a manual
695    /// implementation's `write_to` produces a different byte count than
696    /// its `compute_size` declared.
697    // Direct body — see encode_to_vec for why the fat-payload entry points
698    // do not delegate to their try_ twins.
699    #[inline]
700    #[must_use]
701    fn encode_to_bytes(&self) -> bytes::Bytes {
702        let mut cache = crate::SizeCache::new();
703        let size = match checked_encode_size(self.compute_size(&mut cache)) {
704            Ok(size) => size as usize,
705            Err(_) => encode_size_overflow(),
706        };
707        let mut buf = bytes::BytesMut::with_capacity(size);
708        self.write_to(&mut cache, &mut buf);
709        debug_assert_two_pass(buf.len(), size);
710        buf.freeze()
711    }
712
713    /// Encode to a new [`bytes::Bytes`], returning an error instead of
714    /// panicking if the encoded size exceeds the 2 GiB protobuf limit
715    /// ([`MAX_MESSAGE_BYTES`]).
716    ///
717    /// # Errors
718    ///
719    /// Returns [`EncodeError::MessageTooLarge`] if the encoded size exceeds
720    /// [`MAX_MESSAGE_BYTES`].
721    ///
722    /// # Panics
723    ///
724    /// In debug builds, panics if a manual implementation's `write_to`
725    /// produces a different byte count than its `compute_size` declared.
726    fn try_encode_to_bytes(&self) -> Result<bytes::Bytes, EncodeError> {
727        let mut cache = crate::SizeCache::new();
728        let size = checked_encode_size(self.compute_size(&mut cache))? as usize;
729        let mut buf = bytes::BytesMut::with_capacity(size);
730        self.write_to(&mut cache, &mut buf);
731        debug_assert_two_pass(buf.len(), size);
732        Ok(buf.freeze())
733    }
734
735    /// Decode a message from a buffer.
736    fn decode(buf: &mut impl Buf) -> Result<Self, DecodeError>
737    where
738        Self: Sized,
739    {
740        let limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT);
741        let elem_budget = core::cell::Cell::new(DEFAULT_ELEMENT_MEMORY_LIMIT);
742        let mut msg = Self::default();
743        msg.merge(
744            buf,
745            DecodeContext::new(RECURSION_LIMIT, &limit).with_element_memory(&elem_budget),
746        )?;
747        Ok(msg)
748    }
749
750    /// Decode a message from a byte slice.
751    ///
752    /// Convenience wrapper around [`decode`](Self::decode) that avoids the
753    /// `&mut bytes.as_slice()` incantation.
754    fn decode_from_slice(mut data: &[u8]) -> Result<Self, DecodeError>
755    where
756        Self: Sized,
757    {
758        // `mut data` creates a local mutable copy of the fat pointer so that
759        // `Buf::advance` can move the read cursor without affecting the caller.
760        Self::decode(&mut data)
761    }
762
763    /// Decode a length-delimited message from a buffer.
764    ///
765    /// This is a **top-level** entry point.  It reads a varint length prefix,
766    /// then decodes using arithmetic bounds checking, calling
767    /// [`merge_to_limit`](Self::merge_to_limit) with a fresh
768    /// [`RECURSION_LIMIT`] budget.  Any sub-messages inside are decoded via
769    /// [`merge_length_delimited`](Self::merge_length_delimited), which tracks
770    /// and decrements the budget.
771    ///
772    /// Do **not** call this method from within a
773    /// [`merge_to_limit`](Self::merge_to_limit) implementation to decode a
774    /// nested sub-message field; use
775    /// [`merge_length_delimited`](Self::merge_length_delimited) instead so
776    /// that the caller's depth budget is propagated correctly.
777    fn decode_length_delimited(buf: &mut impl Buf) -> Result<Self, DecodeError>
778    where
779        Self: Sized,
780    {
781        // Refuse messages larger than 2 GiB to prevent allocating attacker-
782        // controlled amounts of memory from a crafted length prefix.
783        let len_u64 = crate::encoding::decode_varint(buf)?;
784        if len_u64 > MAX_MESSAGE_BYTES as u64 {
785            return Err(DecodeError::MessageTooLarge);
786        }
787        // Safe on 32-bit: len_u64 <= 2 GiB - 1 < u32::MAX, so the cast never truncates.
788        let len = usize::try_from(len_u64).map_err(|_| DecodeError::MessageTooLarge)?;
789        if buf.remaining() < len {
790            return Err(DecodeError::UnexpectedEof);
791        }
792        // Arithmetic limit: decode `len` bytes from the buffer without
793        // wrapping it in `Take`.  This keeps the buffer type `B` unchanged
794        // through every recursion level, avoiding E0275 for recursive
795        // message types like `google.protobuf.Struct ↔ Value`.
796        let limit = buf.remaining() - len;
797        let field_limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT);
798        let elem_budget = core::cell::Cell::new(DEFAULT_ELEMENT_MEMORY_LIMIT);
799        let mut msg = Self::default();
800        msg.merge_to_limit(
801            buf,
802            DecodeContext::new(RECURSION_LIMIT, &field_limit).with_element_memory(&elem_budget),
803            limit,
804        )?;
805        if buf.remaining() != limit {
806            let remaining = buf.remaining();
807            if remaining > limit {
808                buf.advance(remaining - limit);
809            } else {
810                return Err(DecodeError::UnexpectedEof);
811            }
812        }
813        Ok(msg)
814    }
815
816    /// Processes a single already-decoded tag and its associated field data
817    /// from `buf`.
818    ///
819    /// This is the per-field dispatch method generated for each message type.
820    /// Both [`merge_to_limit`](Self::merge_to_limit) and
821    /// [`merge_group`](Self::merge_group) call this in their respective loops.
822    ///
823    /// `ctx` carries the remaining nesting depth and the shared allocation
824    /// budget.
825    ///
826    /// # Errors
827    ///
828    /// Returns a [`DecodeError`] if:
829    /// - the buffer is truncated or malformed,
830    /// - a wire-type mismatch is detected for a known field,
831    /// - the recursion limit is exceeded, or
832    /// - the allocation budget is exhausted.
833    fn merge_field(
834        &mut self,
835        tag: crate::encoding::Tag,
836        buf: &mut impl Buf,
837        ctx: DecodeContext<'_>,
838    ) -> Result<(), DecodeError>;
839
840    /// Merge fields from a buffer until `buf.remaining()` reaches `limit`.
841    ///
842    /// This is the core decode loop.  [`merge`](Self::merge) delegates to this
843    /// with `limit = 0` (read until exhausted).
844    /// [`merge_length_delimited`](Self::merge_length_delimited) computes
845    /// `limit` from the declared sub-message length and calls this directly.
846    ///
847    /// The caller must ensure `limit <= buf.remaining()`.  The default
848    /// implementations of [`merge`](Self::merge) and
849    /// [`merge_length_delimited`](Self::merge_length_delimited) uphold this
850    /// invariant.
851    ///
852    /// `ctx` carries the remaining nesting depth and the shared allocation
853    /// budget.  Each call to
854    /// [`merge_length_delimited`](Self::merge_length_delimited) consumes one
855    /// depth level before recursing; when the depth reaches zero the call
856    /// returns [`DecodeError::RecursionLimitExceeded`].
857    fn merge_to_limit(
858        &mut self,
859        buf: &mut impl Buf,
860        ctx: DecodeContext<'_>,
861        limit: usize,
862    ) -> Result<(), DecodeError> {
863        while buf.remaining() > limit {
864            let tag = crate::encoding::Tag::decode(buf)?;
865            self.merge_field(tag, buf, ctx)?;
866        }
867        Ok(())
868    }
869
870    /// Merges a group-encoded message from `buf`, reading fields until an
871    /// EndGroup tag with the given `field_number` is encountered.
872    ///
873    /// Proto2 groups use StartGroup/EndGroup wire types instead of
874    /// length-delimited encoding. The opening StartGroup tag has already been
875    /// consumed by the caller; this method reads the group body and the
876    /// closing EndGroup tag.
877    ///
878    /// # Errors
879    ///
880    /// Returns a [`DecodeError`] if:
881    /// - the buffer is truncated before the EndGroup tag,
882    /// - an EndGroup tag is encountered with a mismatched field number,
883    /// - a wire-type mismatch is detected for a known field, or
884    /// - the recursion limit is exceeded.
885    fn merge_group(
886        &mut self,
887        buf: &mut impl Buf,
888        ctx: DecodeContext<'_>,
889        field_number: u32,
890    ) -> Result<(), DecodeError> {
891        let ctx = ctx.descend()?;
892        loop {
893            if !buf.has_remaining() {
894                return Err(DecodeError::UnexpectedEof);
895            }
896            let tag = crate::encoding::Tag::decode(buf)?;
897            if tag.wire_type() == crate::encoding::WireType::EndGroup {
898                return if tag.field_number() == field_number {
899                    Ok(())
900                } else {
901                    Err(DecodeError::InvalidEndGroup(tag.field_number()))
902                };
903            }
904            self.merge_field(tag, buf, ctx)?;
905        }
906    }
907
908    /// Merge fields from a buffer into this message.
909    ///
910    /// Fields that are already set will be overwritten for singular fields,
911    /// or appended for repeated fields, following standard protobuf merge
912    /// semantics.
913    ///
914    /// `ctx` carries the remaining nesting depth and the shared allocation
915    /// budget.  Each call to
916    /// [`merge_length_delimited`](Self::merge_length_delimited) consumes one
917    /// depth level before recursing; when the depth reaches zero the call
918    /// returns [`DecodeError::RecursionLimitExceeded`].  Construct a fresh
919    /// [`DecodeContext`] at the outermost call site, or use the convenience
920    /// methods ([`decode`](Self::decode),
921    /// [`merge_from_slice`](Self::merge_from_slice)) which do this
922    /// automatically.
923    fn merge(&mut self, buf: &mut impl Buf, ctx: DecodeContext<'_>) -> Result<(), DecodeError> {
924        self.merge_to_limit(buf, ctx, 0)
925    }
926
927    /// Merge fields from a byte slice into this message.
928    ///
929    /// Convenience wrapper around [`merge`](Self::merge) that avoids the
930    /// `&mut bytes.as_slice()` incantation.
931    fn merge_from_slice(&mut self, mut data: &[u8]) -> Result<(), DecodeError> {
932        let limit = core::cell::Cell::new(DEFAULT_UNKNOWN_FIELD_LIMIT);
933        let elem_budget = core::cell::Cell::new(DEFAULT_ELEMENT_MEMORY_LIMIT);
934        self.merge(
935            &mut data,
936            DecodeContext::new(RECURSION_LIMIT, &limit).with_element_memory(&elem_budget),
937        )
938    }
939
940    /// Merge fields from a length-delimited sub-message payload into this message.
941    ///
942    /// Reads a varint length prefix, then calls [`merge_to_limit`](Self::merge_to_limit)
943    /// with an arithmetic bound derived from the declared sub-message length.
944    /// The buffer type `B` passes through unchanged at every recursion level,
945    /// avoiding the `E0275` trait-solver recursion limit that occurs with
946    /// `Take<&mut Take<&mut T>>` type growth.
947    ///
948    /// Used by generated code when decoding singular `MessageField<T>` fields
949    /// — the sub-message is merged into the existing value rather than
950    /// replaced, per protobuf merge semantics.
951    ///
952    /// `ctx` carries the remaining nesting depth and the shared allocation
953    /// budget passed down from the enclosing
954    /// [`merge_to_limit`](Self::merge_to_limit) call.  This method consumes
955    /// one depth level before calling the inner `merge_to_limit`; when the
956    /// depth reaches zero it returns
957    /// [`DecodeError::RecursionLimitExceeded`].
958    ///
959    /// Enforces the same 2 GiB safety limit as [`decode_length_delimited`](Self::decode_length_delimited).
960    ///
961    /// # Errors
962    ///
963    /// Returns an error if the buffer is too short, if the declared length
964    /// exceeds 2 GiB, if the recursion limit is reached, or if the inner
965    /// `merge_to_limit` call fails.
966    fn merge_length_delimited(
967        &mut self,
968        buf: &mut impl Buf,
969        ctx: DecodeContext<'_>,
970    ) -> Result<(), DecodeError> {
971        let ctx = ctx.descend()?;
972        let len_u64 = crate::encoding::decode_varint(buf)?;
973        if len_u64 > MAX_MESSAGE_BYTES as u64 {
974            return Err(DecodeError::MessageTooLarge);
975        }
976        let len = usize::try_from(len_u64).map_err(|_| DecodeError::MessageTooLarge)?;
977        if buf.remaining() < len {
978            return Err(DecodeError::UnexpectedEof);
979        }
980        // Arithmetic limit: the sub-message occupies `len` bytes, so the
981        // decode loop should stop when `buf.remaining()` drops to
982        // `remaining - len`.  This avoids wrapping the buffer in `Take`,
983        // which would grow the type at each recursion level and trigger
984        // E0275 for recursive message types like `Struct ↔ Value`.
985        let limit = buf.remaining() - len;
986        self.merge_to_limit(buf, ctx, limit)?;
987        if buf.remaining() != limit {
988            let remaining = buf.remaining();
989            if remaining > limit {
990                // Sub-message consumed fewer bytes than declared; skip the rest.
991                buf.advance(remaining - limit);
992            } else {
993                return Err(DecodeError::UnexpectedEof);
994            }
995        }
996        Ok(())
997    }
998
999    /// Clear all fields to their default values.
1000    fn clear(&mut self);
1001}
1002
1003/// Compile-time access to a generated message's protobuf identifiers.
1004///
1005/// Generic code that needs to *name* a message type — type-erased event
1006/// registries, structured logging, `Any` packing, schema lookups — can
1007/// bound on `T: MessageName` and read [`PACKAGE`], [`NAME`],
1008/// [`FULL_NAME`], or [`TYPE_URL`] without descriptor machinery or runtime
1009/// reflection. All four are `&'static str` literals computed at codegen
1010/// time, so there's no allocation or concatenation at runtime — unlike
1011/// `prost::Name`, whose `full_name()` and `type_url()` are runtime
1012/// `format!` calls.
1013///
1014/// Bring `buffa::MessageName` into scope to use `MyMessage::FULL_NAME`.
1015/// Without the trait in scope, use
1016/// `<MyMessage as buffa::MessageName>::FULL_NAME`.
1017///
1018/// Codegen implements `MessageName` for both the owned message type and
1019/// its zero-copy view type (`MyMessageView<'a>`), so the same generic
1020/// bound dispatches either. The trait has **no** [`Message`] supertrait —
1021/// it doesn't reach into the wire codec and a name-keyed registry should
1022/// be able to register a type without proving it can encode.
1023///
1024/// Hand-written [`Message`] implementations can opt in by also
1025/// implementing `MessageName`; it is a separate trait specifically so
1026/// that omitting it stays non-breaking. For messages that also implement
1027/// [`ExtensionSet`](crate::ExtensionSet), [`FULL_NAME`] is guaranteed
1028/// equal to [`ExtensionSet::PROTO_FQN`](crate::ExtensionSet::PROTO_FQN);
1029/// the inherent `MyMessage::TYPE_URL` const is equal to [`TYPE_URL`].
1030/// All derive from the same `proto_fqn` source in codegen.
1031///
1032/// Because the only items are associated `const`s, this trait is **not**
1033/// object-safe (`dyn MessageName` does not compile). Use it as a generic
1034/// bound (`fn foo<T: MessageName>()`), not a trait object.
1035///
1036/// ```
1037/// # use buffa::MessageName;
1038/// /// A name-keyed registry can register any `MessageName` type — owned
1039/// /// or view — without proving it can encode.
1040/// fn registry_key<T: MessageName>() -> &'static str {
1041///     T::FULL_NAME
1042/// }
1043/// # // No generated types in `buffa` itself; just check it monomorphises.
1044/// # struct Demo;
1045/// # impl MessageName for Demo {
1046/// #     const PACKAGE: &'static str = "demo";
1047/// #     const NAME: &'static str = "Demo";
1048/// #     const FULL_NAME: &'static str = "demo.Demo";
1049/// #     const TYPE_URL: &'static str = "type.googleapis.com/demo.Demo";
1050/// # }
1051/// assert_eq!(registry_key::<Demo>(), "demo.Demo");
1052/// ```
1053///
1054/// [`PACKAGE`]: Self::PACKAGE
1055/// [`NAME`]: Self::NAME
1056/// [`FULL_NAME`]: Self::FULL_NAME
1057/// [`TYPE_URL`]: Self::TYPE_URL
1058pub trait MessageName {
1059    /// The protobuf package the message is declared in.
1060    ///
1061    /// `"my.pkg"` for `package my.pkg;`. Empty string for the unnamed
1062    /// root package. Does not include a leading or trailing dot.
1063    const PACKAGE: &'static str;
1064
1065    /// The unqualified message name, with `.` between nesting levels.
1066    ///
1067    /// `"Foo"` for a top-level message; `"Outer.Inner"` for a message
1068    /// nested inside `Outer`. This is the "type name relative to the
1069    /// package" — what `prost::Name::NAME` calls the same thing — *not*
1070    /// `DescriptorProto.name`, which is only the leaf segment (`"Inner"`)
1071    /// for nested types.
1072    const NAME: &'static str;
1073
1074    /// The fully-qualified protobuf type name with no leading dot.
1075    ///
1076    /// `"my.pkg.Outer.Inner"` for a nested message in package `my.pkg`,
1077    /// or just `"Foo"` for a top-level message in the unnamed root
1078    /// package. Equal to `PACKAGE` + `"."` + `NAME` (with the joining
1079    /// dot omitted when `PACKAGE` is empty); shipped as its own const
1080    /// because consumers almost always want the joined form and the
1081    /// dotted string can't be re-split unambiguously
1082    /// (`foo.Bar.Baz` could be package `foo.Bar` + message `Baz`, or
1083    /// package `foo` + nested `Bar.Baz`).
1084    const FULL_NAME: &'static str;
1085
1086    /// The `google.protobuf.Any.type_url` form for this message.
1087    ///
1088    /// `"type.googleapis.com/" + FULL_NAME`. This is the value the
1089    /// runtime stores in [`Any::type_url`] when packing a message, and
1090    /// the one a generic `Any` registry should key on.
1091    ///
1092    /// [`Any::type_url`]: https://protobuf.dev/programming-guides/proto3/#any
1093    const TYPE_URL: &'static str;
1094}
1095
1096/// Options for configuring message decoding behavior.
1097///
1098/// Use this to set custom recursion depth limits or maximum message sizes
1099/// when decoding from untrusted input.
1100///
1101/// # Scope: the protobuf binary codec
1102///
1103/// Every limit here bounds the binary decoders — owned, view, and the
1104/// reflective `DynamicMessage` codec — and only those. Decoding the same
1105/// message from JSON goes through `serde_json` (or another `Deserializer`)
1106/// straight into the generated `Deserialize` impls, which never see a
1107/// `DecodeOptions`, so none of these limits apply to it. JSON input that must
1108/// be bounded needs a bound imposed by the caller, for example by capping the
1109/// input length before parsing.
1110///
1111/// # Examples
1112///
1113/// ```no_run
1114/// # use buffa::__doctest_fixtures::Person;
1115/// use buffa::DecodeOptions;
1116///
1117/// # fn example(bytes: &[u8]) -> Result<(), buffa::DecodeError> {
1118/// // Restrict recursion depth to 50 and message size to 1 MiB:
1119/// let msg: Person = DecodeOptions::new()
1120///     .with_recursion_limit(50)
1121///     .with_max_message_size(1024 * 1024)
1122///     .decode_from_slice(bytes)?;
1123/// # Ok(())
1124/// # }
1125/// ```
1126#[derive(Debug, Clone)]
1127pub struct DecodeOptions {
1128    recursion_limit: u32,
1129    max_message_size: usize,
1130    unbounded_reader_size: bool,
1131    unknown_field_limit: usize,
1132    element_memory_limit: usize,
1133}
1134
1135/// Default maximum message size: 2 GiB - 1 (matches the sub-message limit
1136/// in `merge_length_delimited` and the encode-side limit — see
1137/// [`MAX_MESSAGE_BYTES`]).
1138const DEFAULT_MAX_MESSAGE_SIZE: usize = MAX_MESSAGE_BYTES as usize;
1139
1140impl Default for DecodeOptions {
1141    fn default() -> Self {
1142        Self::new()
1143    }
1144}
1145
1146impl DecodeOptions {
1147    /// Create new decode options with defaults.
1148    ///
1149    /// Defaults:
1150    /// - `recursion_limit`: 100 (same as [`RECURSION_LIMIT`])
1151    /// - `max_message_size`: 2 GiB - 1
1152    /// - `unknown_field_limit`: 1,000,000 (same as [`DEFAULT_UNKNOWN_FIELD_LIMIT`])
1153    /// - `element_memory_limit`: 32 MiB (same as [`DEFAULT_ELEMENT_MEMORY_LIMIT`])
1154    pub fn new() -> Self {
1155        Self {
1156            recursion_limit: RECURSION_LIMIT,
1157            max_message_size: DEFAULT_MAX_MESSAGE_SIZE,
1158            unbounded_reader_size: false,
1159            unknown_field_limit: DEFAULT_UNKNOWN_FIELD_LIMIT,
1160            element_memory_limit: DEFAULT_ELEMENT_MEMORY_LIMIT,
1161        }
1162    }
1163
1164    /// Set the maximum recursion depth for nested messages.
1165    ///
1166    /// Each nested sub-message consumes one level of depth budget. When
1167    /// the budget reaches zero, decoding returns
1168    /// [`DecodeError::RecursionLimitExceeded`].
1169    ///
1170    /// Default: 100.
1171    #[must_use]
1172    pub fn with_recursion_limit(mut self, limit: u32) -> Self {
1173        self.recursion_limit = limit;
1174        self
1175    }
1176
1177    /// Set the maximum total message size in bytes.
1178    ///
1179    /// If the input buffer or length-delimited payload exceeds this size,
1180    /// decoding returns [`DecodeError::MessageTooLarge`].
1181    ///
1182    /// Values above the protobuf message-size limit (2 GiB - 1) are clamped to
1183    /// that limit. Debug builds assert on out-of-range values so accidental
1184    /// `usize::MAX` sentinels are caught during development. On `std` builds,
1185    /// use `without_reader_size_limit` when EOF-bounded `decode_reader` input
1186    /// intentionally has no byte cap.
1187    ///
1188    /// Calling this re-enables the reader byte cap, overriding any prior
1189    /// `without_reader_size_limit`.
1190    ///
1191    /// This is checked at the top-level decode entry point. Individual
1192    /// sub-messages are still bounded by the internal 2 GiB limit
1193    /// regardless of this setting.
1194    ///
1195    /// Default: 2 GiB - 1 (0x7FFF_FFFF).
1196    #[must_use]
1197    pub fn with_max_message_size(mut self, max_bytes: usize) -> Self {
1198        debug_assert!(
1199            max_bytes <= DEFAULT_MAX_MESSAGE_SIZE,
1200            "DecodeOptions::with_max_message_size clamps values above the protobuf 2 GiB limit; \
1201             on std builds, use DecodeOptions::without_reader_size_limit for intentionally \
1202             unbounded reader input — there is no unbounded slice/Buf path"
1203        );
1204        self.max_message_size = max_bytes.min(DEFAULT_MAX_MESSAGE_SIZE);
1205        self.unbounded_reader_size = false;
1206        self
1207    }
1208
1209    /// Remove the byte cap for EOF-bounded [`decode_reader`](Self::decode_reader)
1210    /// input.
1211    ///
1212    /// This is only used by the `std::io::Read` entry point that reads until
1213    /// EOF. Slice-, [`Buf`]-, and view-based entry points remain bounded by
1214    /// the configured [`with_max_message_size`](Self::with_max_message_size)
1215    /// (itself capped at the protobuf 2 GiB - 1 maximum), and length-delimited
1216    /// paths keep the same hard cap because their declared length is
1217    /// attacker-controlled.
1218    ///
1219    /// An unbounded reader can exhaust memory if the source does not end or is
1220    /// larger than available allocation capacity. Prefer
1221    /// [`with_max_message_size`](Self::with_max_message_size) for untrusted
1222    /// input.
1223    #[cfg(feature = "std")]
1224    #[must_use]
1225    pub fn without_reader_size_limit(mut self) -> Self {
1226        self.unbounded_reader_size = true;
1227        self
1228    }
1229
1230    /// Set the maximum number of unknown fields decoded per decode call.
1231    ///
1232    /// Each decoded unknown field occupies a ~40-byte
1233    /// [`UnknownField`](crate::UnknownField) slot regardless of its wire
1234    /// size (a minimal field is 2 wire bytes — a ~20× amplification), so an
1235    /// input-size cap alone does not bound decoder memory; this limit does,
1236    /// at roughly `limit × 40` bytes of slot overhead. Unknown
1237    /// length-delimited *payload* bytes are not counted — they are bounded
1238    /// by the input size, which
1239    /// [`with_max_message_size`](Self::with_max_message_size) governs. When
1240    /// the limit is exceeded, decoding returns
1241    /// [`DecodeError::UnknownFieldLimitExceeded`].
1242    ///
1243    /// Zero-copy view decoding ([`decode_view`](Self::decode_view)) charges
1244    /// one slot per unknown field — including fields nested inside unknown
1245    /// groups — even though views store unknown fields as coalesced spans
1246    /// (~16 bytes per contiguous run): coalescing bounds view memory, while
1247    /// this limit bounds what converting the view to an owned message would
1248    /// materialize. Conversion replays under exactly the budget decoding
1249    /// charged, so a view that decodes within this limit always converts.
1250    ///
1251    /// Default: 1,000,000 ([`DEFAULT_UNKNOWN_FIELD_LIMIT`]).
1252    #[must_use]
1253    pub fn with_unknown_field_limit(mut self, count: usize) -> Self {
1254        self.unknown_field_limit = count;
1255        self
1256    }
1257
1258    /// Set the memory this decode may materialize in the elements of
1259    /// length-delimited containers — repeated message, string and bytes fields,
1260    /// and map entries — shared across the whole decode tree rather than per
1261    /// field or per message.
1262    ///
1263    /// This is not [`with_max_message_size`](Self::with_max_message_size) by
1264    /// another name: that bounds the bytes going *in*, this bounds what they
1265    /// expand *into*. They are not redundant, because the two are not
1266    /// proportional — an empty repeated message element is 2 wire bytes and
1267    /// `size_of::<T>()` of `Vec` footprint (measured at 256 bytes for a message
1268    /// of a few `Vec`/`String` fields), so a payload well inside any input
1269    /// bound can still materialize 128x its own size. Charging is by element
1270    /// footprint, so a budget means the same amount of memory whatever the
1271    /// element size — which a count limit could not offer.
1272    ///
1273    /// Packed scalar fields are never charged; see
1274    /// [`DEFAULT_ELEMENT_MEMORY_LIMIT`] for why, and for the `Vec`-doubling
1275    /// caveat on peak memory.
1276    ///
1277    /// Like every option on [`DecodeOptions`], this bounds the binary decoders
1278    /// only. The same message decoded from JSON is not charged against this
1279    /// budget, and the amplification it guards against is very nearly as large
1280    /// there — `{}` is three JSON bytes for the same element footprint.
1281    ///
1282    /// Default: 32 MiB ([`DEFAULT_ELEMENT_MEMORY_LIMIT`]).
1283    #[must_use]
1284    pub fn with_element_memory_limit(mut self, bytes: usize) -> Self {
1285        self.element_memory_limit = bytes;
1286        self
1287    }
1288
1289    /// Returns the configured element-memory budget.
1290    #[must_use]
1291    pub fn element_memory_limit(&self) -> usize {
1292        self.element_memory_limit
1293    }
1294
1295    /// Returns the configured recursion depth limit.
1296    pub fn recursion_limit(&self) -> u32 {
1297        self.recursion_limit
1298    }
1299
1300    /// Returns the configured unknown-field limit.
1301    pub fn unknown_field_limit(&self) -> usize {
1302        self.unknown_field_limit
1303    }
1304
1305    /// Returns the configured maximum message size in bytes for bounded decode
1306    /// entry points.
1307    ///
1308    /// This returns the configured (clamped) value even when
1309    /// `without_reader_size_limit` is enabled for EOF-bounded reader input —
1310    /// the slice/`Buf`/view paths still honor it. Use
1311    /// `is_reader_size_unbounded` (std only) to inspect the reader flag.
1312    pub fn max_message_size(&self) -> usize {
1313        self.max_message_size
1314    }
1315
1316    /// Returns whether EOF-bounded reader input has no byte cap.
1317    #[cfg(feature = "std")]
1318    pub fn is_reader_size_unbounded(&self) -> bool {
1319        self.unbounded_reader_size
1320    }
1321
1322    /// Decode a message from a buffer.
1323    pub fn decode<M: Message>(&self, buf: &mut impl Buf) -> Result<M, DecodeError> {
1324        if buf.remaining() > self.max_message_size {
1325            return Err(DecodeError::MessageTooLarge);
1326        }
1327        let limit = core::cell::Cell::new(self.unknown_field_limit);
1328        let elem_budget = core::cell::Cell::new(self.element_memory_limit);
1329        let mut msg = M::default();
1330        msg.merge(
1331            buf,
1332            DecodeContext::new(self.recursion_limit, &limit).with_element_memory(&elem_budget),
1333        )?;
1334        Ok(msg)
1335    }
1336
1337    /// Decode a message from a byte slice.
1338    pub fn decode_from_slice<M: Message>(&self, data: &[u8]) -> Result<M, DecodeError> {
1339        if data.len() > self.max_message_size {
1340            return Err(DecodeError::MessageTooLarge);
1341        }
1342        self.decode_from_slice_unchecked_size(data)
1343    }
1344
1345    fn decode_from_slice_unchecked_size<M: Message>(&self, data: &[u8]) -> Result<M, DecodeError> {
1346        let limit = core::cell::Cell::new(self.unknown_field_limit);
1347        let elem_budget = core::cell::Cell::new(self.element_memory_limit);
1348        let mut msg = M::default();
1349        msg.merge(
1350            &mut &*data,
1351            DecodeContext::new(self.recursion_limit, &limit).with_element_memory(&elem_budget),
1352        )?;
1353        Ok(msg)
1354    }
1355
1356    /// Decode a length-delimited message from a buffer.
1357    pub fn decode_length_delimited<M: Message>(
1358        &self,
1359        buf: &mut impl Buf,
1360    ) -> Result<M, DecodeError> {
1361        // Enforce the 2 GiB internal safety cap even if the user sets a
1362        // larger max_message_size, to prevent allocating attacker-controlled
1363        // amounts of memory from a crafted length prefix.
1364        let max = core::cmp::min(
1365            self.max_message_size as u64,
1366            DEFAULT_MAX_MESSAGE_SIZE as u64,
1367        );
1368        let len_u64 = crate::encoding::decode_varint(buf)?;
1369        if len_u64 > max {
1370            return Err(DecodeError::MessageTooLarge);
1371        }
1372        let len = usize::try_from(len_u64).map_err(|_| DecodeError::MessageTooLarge)?;
1373        if buf.remaining() < len {
1374            return Err(DecodeError::UnexpectedEof);
1375        }
1376        let limit = buf.remaining() - len;
1377        let field_limit = core::cell::Cell::new(self.unknown_field_limit);
1378        let elem_budget = core::cell::Cell::new(self.element_memory_limit);
1379        let mut msg = M::default();
1380        msg.merge_to_limit(
1381            buf,
1382            DecodeContext::new(self.recursion_limit, &field_limit)
1383                .with_element_memory(&elem_budget),
1384            limit,
1385        )?;
1386        if buf.remaining() != limit {
1387            let remaining = buf.remaining();
1388            if remaining > limit {
1389                buf.advance(remaining - limit);
1390            } else {
1391                return Err(DecodeError::UnexpectedEof);
1392            }
1393        }
1394        Ok(msg)
1395    }
1396
1397    /// Merge fields from a buffer into an existing message.
1398    pub fn merge<M: Message>(&self, msg: &mut M, buf: &mut impl Buf) -> Result<(), DecodeError> {
1399        if buf.remaining() > self.max_message_size {
1400            return Err(DecodeError::MessageTooLarge);
1401        }
1402        let limit = core::cell::Cell::new(self.unknown_field_limit);
1403        let elem_budget = core::cell::Cell::new(self.element_memory_limit);
1404        msg.merge(
1405            buf,
1406            DecodeContext::new(self.recursion_limit, &limit).with_element_memory(&elem_budget),
1407        )
1408    }
1409
1410    /// Merge fields from a byte slice into an existing message.
1411    pub fn merge_from_slice<M: Message>(
1412        &self,
1413        msg: &mut M,
1414        data: &[u8],
1415    ) -> Result<(), DecodeError> {
1416        if data.len() > self.max_message_size {
1417            return Err(DecodeError::MessageTooLarge);
1418        }
1419        let limit = core::cell::Cell::new(self.unknown_field_limit);
1420        let elem_budget = core::cell::Cell::new(self.element_memory_limit);
1421        msg.merge(
1422            &mut &*data,
1423            DecodeContext::new(self.recursion_limit, &limit).with_element_memory(&elem_budget),
1424        )
1425    }
1426
1427    /// Decode a zero-copy view from a byte slice.
1428    ///
1429    /// Enforces `max_message_size` on the input, and passes the recursion
1430    /// limit and unknown-field limit to the view decoder (views charge the
1431    /// unknown-field limit per field, including fields nested in unknown
1432    /// groups — see
1433    /// [`with_unknown_field_limit`](Self::with_unknown_field_limit)).
1434    ///
1435    /// # Errors
1436    ///
1437    /// Returns [`DecodeError::MessageTooLarge`] for oversized input, or any
1438    /// error from the view decoder (malformed wire data, recursion limit,
1439    /// unknown-field limit).
1440    pub fn decode_view<'a, V: crate::view::MessageView<'a>>(
1441        &self,
1442        buf: &'a [u8],
1443    ) -> Result<V, DecodeError> {
1444        if buf.len() > self.max_message_size {
1445            return Err(DecodeError::MessageTooLarge);
1446        }
1447        let limit = core::cell::Cell::new(self.unknown_field_limit);
1448        let elem_budget = core::cell::Cell::new(self.element_memory_limit);
1449        V::decode_view_with_ctx(
1450            buf,
1451            DecodeContext::new(self.recursion_limit, &limit).with_element_memory(&elem_budget),
1452        )
1453    }
1454
1455    /// Decode a lazy view from a byte slice (see
1456    /// [`LazyMessageView`](crate::view::LazyMessageView)).
1457    ///
1458    /// The budgets remaining at each deferred field's position are recorded
1459    /// and charged when that field is accessed, so the configured limits
1460    /// flow through deferred decoding. Unlike
1461    /// [`decode_view`](Self::decode_view), the unknown-field limit is not
1462    /// enforced globally across the message tree at decode time: each
1463    /// deferred subtree independently replays the allowance recorded at its
1464    /// position, so a full traversal can materialize unknown-field records
1465    /// proportional to input size. Prefer `decode_view` for untrusted input
1466    /// if the global bound matters.
1467    ///
1468    /// # Errors
1469    ///
1470    /// Returns [`DecodeError::MessageTooLarge`] for oversized input, or any
1471    /// error from decoding the message's own fields — including
1472    /// [`DecodeError::RecursionLimitExceeded`] /
1473    /// [`DecodeError::UnknownFieldLimitExceeded`] when the configured limits
1474    /// are exhausted by them. Deferred sub-message bytes surface errors on
1475    /// access instead.
1476    pub fn decode_lazy_view<'a, L: crate::view::LazyMessageView<'a>>(
1477        &self,
1478        buf: &'a [u8],
1479    ) -> Result<L, DecodeError> {
1480        if buf.len() > self.max_message_size {
1481            return Err(DecodeError::MessageTooLarge);
1482        }
1483        let limit = core::cell::Cell::new(self.unknown_field_limit);
1484        let elem_budget = core::cell::Cell::new(self.element_memory_limit);
1485        L::decode_lazy_with_ctx(
1486            buf,
1487            DecodeContext::new(self.recursion_limit, &limit).with_element_memory(&elem_budget),
1488        )
1489    }
1490
1491    /// Decode a message by reading all bytes from a [`std::io::Read`] source.
1492    ///
1493    /// Reads until EOF, enforces the configured reader size limit unless
1494    /// [`without_reader_size_limit`](Self::without_reader_size_limit) was
1495    /// selected, then decodes the buffered bytes. Returns `std::io::Error` to
1496    /// be compatible with `Read`-based error handling.
1497    #[cfg(feature = "std")]
1498    pub fn decode_reader<M: Message>(
1499        &self,
1500        reader: &mut impl std::io::Read,
1501    ) -> Result<M, std::io::Error> {
1502        let bytes = self.read_limited(reader)?;
1503        self.decode_from_slice_unchecked_size::<M>(&bytes)
1504            .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
1505    }
1506
1507    /// Decode a length-delimited message from a [`std::io::Read`] source.
1508    ///
1509    /// Reads a varint length prefix, enforces `max_message_size`, reads
1510    /// exactly that many bytes, then decodes. Useful for reading sequential
1511    /// length-delimited messages from a file or stream.
1512    ///
1513    /// The declared length is treated as untrusted: the read buffer grows
1514    /// as bytes actually arrive rather than being allocated up front, so a
1515    /// source that declares a large length but never delivers the bytes
1516    /// cannot force a large allocation.
1517    #[cfg(feature = "std")]
1518    pub fn decode_length_delimited_reader<M: Message>(
1519        &self,
1520        reader: &mut impl std::io::Read,
1521    ) -> Result<M, std::io::Error> {
1522        use std::io::Read as _;
1523        let len = read_varint(reader)?;
1524        let max = core::cmp::min(
1525            self.max_message_size as u64,
1526            DEFAULT_MAX_MESSAGE_SIZE as u64,
1527        );
1528        if len > max {
1529            return Err(std::io::Error::new(
1530                std::io::ErrorKind::InvalidData,
1531                DecodeError::MessageTooLarge,
1532            ));
1533        }
1534        let len = usize::try_from(len).map_err(|_| {
1535            std::io::Error::new(
1536                std::io::ErrorKind::InvalidData,
1537                DecodeError::MessageTooLarge,
1538            )
1539        })?;
1540        // Pre-size only up to a small bound; `read_to_end` grows the buffer
1541        // geometrically as data is actually delivered, so peak allocation
1542        // tracks delivered bytes, not the wire-declared length.
1543        const INITIAL_CAPACITY_CAP: usize = 64 * 1024;
1544        let mut buf = alloc::vec::Vec::with_capacity(len.min(INITIAL_CAPACITY_CAP));
1545        reader.take(len as u64).read_to_end(&mut buf)?;
1546        if buf.len() < len {
1547            return Err(std::io::Error::new(
1548                std::io::ErrorKind::UnexpectedEof,
1549                DecodeError::UnexpectedEof,
1550            ));
1551        }
1552        self.decode_from_slice::<M>(&buf)
1553            .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
1554    }
1555
1556    /// Read all bytes from a reader up to the configured reader limit.
1557    #[cfg(feature = "std")]
1558    fn read_limited(
1559        &self,
1560        reader: &mut impl std::io::Read,
1561    ) -> Result<alloc::vec::Vec<u8>, std::io::Error> {
1562        use std::io::Read as _;
1563        let mut buf = alloc::vec::Vec::new();
1564        if self.unbounded_reader_size {
1565            reader.read_to_end(&mut buf)?;
1566            return Ok(buf);
1567        }
1568        reader
1569            .take((self.max_message_size as u64).saturating_add(1))
1570            .read_to_end(&mut buf)?;
1571        if buf.len() > self.max_message_size {
1572            return Err(std::io::Error::new(
1573                std::io::ErrorKind::InvalidData,
1574                DecodeError::MessageTooLarge,
1575            ));
1576        }
1577        Ok(buf)
1578    }
1579}
1580
1581/// Read a varint from a `std::io::Read` source, one byte at a time.
1582///
1583/// Mirrors the validation in [`decode_varint_slow`](crate::encoding): a
1584/// 10th byte > `0x01` (overflow bits set, or continuation bit implying an
1585/// 11th byte) is rejected.
1586#[cfg(feature = "std")]
1587fn read_varint(reader: &mut impl std::io::Read) -> Result<u64, std::io::Error> {
1588    let mut value: u64 = 0;
1589    let mut shift: u32 = 0;
1590    loop {
1591        let mut byte = [0u8; 1];
1592        reader.read_exact(&mut byte)?;
1593        let b = byte[0];
1594        if shift < 63 {
1595            value |= ((b & 0x7F) as u64) << shift;
1596            if b < 0x80 {
1597                return Ok(value);
1598            }
1599            shift += 7;
1600        } else {
1601            // 10th byte: only bit 0 maps to bit 63 of the result. A byte
1602            // > 0x01 means either data overflow (bits 1-6 set) or an 11th
1603            // byte (continuation bit 0x80 set).
1604            if b > 0x01 {
1605                return Err(std::io::Error::new(
1606                    std::io::ErrorKind::InvalidData,
1607                    DecodeError::VarintTooLong,
1608                ));
1609            }
1610            value |= (b as u64) << 63;
1611            return Ok(value);
1612        }
1613    }
1614}
1615
1616#[cfg(test)]
1617mod tests {
1618    use super::*;
1619    use crate::encoding::encode_varint;
1620    use crate::error::DecodeError;
1621    use crate::message_field::DefaultInstance;
1622    use crate::SizeCache;
1623
1624    // Minimal hand-written Message for testing merge_length_delimited.
1625    #[derive(Clone, Debug, Default, PartialEq)]
1626    struct FlatMsg {
1627        value: i32,
1628    }
1629
1630    impl DefaultInstance for FlatMsg {
1631        fn default_instance() -> &'static Self {
1632            static INST: crate::__private::OnceBox<FlatMsg> = crate::__private::OnceBox::new();
1633            INST.get_or_init(|| alloc::boxed::Box::new(FlatMsg::default()))
1634        }
1635    }
1636
1637    impl Message for FlatMsg {
1638        fn compute_size(&self, _cache: &mut SizeCache) -> u32 {
1639            if self.value != 0 {
1640                1 + crate::types::int32_encoded_len(self.value) as u32
1641            } else {
1642                0
1643            }
1644        }
1645
1646        fn write_to(&self, _cache: &mut SizeCache, buf: &mut impl EncodeSink) {
1647            if self.value != 0 {
1648                crate::encoding::Tag::new(1, crate::encoding::WireType::Varint).encode(buf);
1649                crate::types::encode_int32(self.value, buf);
1650            }
1651        }
1652
1653        fn merge_field(
1654            &mut self,
1655            tag: crate::encoding::Tag,
1656            buf: &mut impl Buf,
1657            _ctx: DecodeContext<'_>,
1658        ) -> Result<(), DecodeError> {
1659            match tag.field_number() {
1660                1 => {
1661                    self.value = crate::types::decode_int32(buf)?;
1662                }
1663                _ => {
1664                    crate::encoding::skip_field(tag, buf)?;
1665                }
1666            }
1667            Ok(())
1668        }
1669
1670        fn clear(&mut self) {
1671            *self = Self::default();
1672        }
1673    }
1674
1675    fn wire_bytes(msg: &FlatMsg) -> alloc::vec::Vec<u8> {
1676        let mut buf = alloc::vec::Vec::new();
1677        msg.encode_length_delimited(&mut buf);
1678        buf
1679    }
1680
1681    #[test]
1682    fn test_merge_length_delimited_basic() {
1683        let src = FlatMsg { value: 42 };
1684        let mut dst = FlatMsg::default();
1685        dst.merge_length_delimited(
1686            &mut wire_bytes(&src).as_slice(),
1687            crate::test_ctx(RECURSION_LIMIT),
1688        )
1689        .unwrap();
1690        assert_eq!(dst.value, 42);
1691    }
1692
1693    #[test]
1694    fn test_merge_length_delimited_merges_into_existing() {
1695        // Second merge overwrites (proto3 last-wins for scalar fields).
1696        let mut dst = FlatMsg::default();
1697        dst.merge_length_delimited(
1698            &mut wire_bytes(&FlatMsg { value: 1 }).as_slice(),
1699            crate::test_ctx(RECURSION_LIMIT),
1700        )
1701        .unwrap();
1702        assert_eq!(dst.value, 1);
1703        dst.merge_length_delimited(
1704            &mut wire_bytes(&FlatMsg { value: 2 }).as_slice(),
1705            crate::test_ctx(RECURSION_LIMIT),
1706        )
1707        .unwrap();
1708        assert_eq!(dst.value, 2);
1709    }
1710
1711    #[test]
1712    fn test_merge_length_delimited_truncated() {
1713        // Length prefix says 10 bytes but buffer contains only 2.
1714        let mut buf = alloc::vec::Vec::new();
1715        encode_varint(10, &mut buf);
1716        buf.extend_from_slice(&[0x01, 0x01]);
1717        let mut dst = FlatMsg::default();
1718        assert_eq!(
1719            dst.merge_length_delimited(&mut buf.as_slice(), crate::test_ctx(RECURSION_LIMIT)),
1720            Err(DecodeError::UnexpectedEof)
1721        );
1722    }
1723
1724    #[test]
1725    fn test_merge_length_delimited_oversized() {
1726        // Length prefix exceeds the 2 GiB safety limit.
1727        let mut buf = alloc::vec::Vec::new();
1728        encode_varint(0x8000_0000u64, &mut buf); // 2 GiB + 1
1729        let mut dst = FlatMsg::default();
1730        assert_eq!(
1731            dst.merge_length_delimited(&mut buf.as_slice(), crate::test_ctx(RECURSION_LIMIT)),
1732            Err(DecodeError::MessageTooLarge)
1733        );
1734    }
1735
1736    #[test]
1737    fn test_merge_length_delimited_recursion_limit() {
1738        // depth=1 means merge_length_delimited will decrement to 0, then any
1739        // nested call would return RecursionLimitExceeded.  Passing depth=1
1740        // to merge_length_delimited itself is the boundary: it decrements to
1741        // 0 and calls merge with depth=0, which for FlatMsg (a leaf) succeeds.
1742        // Passing depth=0 directly must return RecursionLimitExceeded.
1743        let src = FlatMsg { value: 7 };
1744        let mut dst = FlatMsg::default();
1745        assert_eq!(
1746            dst.merge_length_delimited(&mut wire_bytes(&src).as_slice(), crate::test_ctx(0)),
1747            Err(DecodeError::RecursionLimitExceeded)
1748        );
1749        // depth=1 succeeds: exactly one level is consumed.
1750        dst.merge_length_delimited(&mut wire_bytes(&src).as_slice(), crate::test_ctx(1))
1751            .unwrap();
1752        assert_eq!(dst.value, 7);
1753    }
1754
1755    #[test]
1756    fn test_decode_from_slice_basic() {
1757        let src = FlatMsg { value: 42 };
1758        let bytes = src.encode_to_vec();
1759        let dst = FlatMsg::decode_from_slice(&bytes).unwrap();
1760        assert_eq!(dst.value, 42);
1761    }
1762
1763    #[test]
1764    fn test_encode_to_bytes_matches_encode_to_vec() {
1765        let src = FlatMsg { value: 42 };
1766        let vec = src.encode_to_vec();
1767        let bytes = src.encode_to_bytes();
1768        assert_eq!(vec.as_slice(), bytes.as_ref());
1769        // Round-trip through the Bytes variant.
1770        let dst = FlatMsg::decode_from_slice(&bytes).unwrap();
1771        assert_eq!(dst.value, 42);
1772        // Empty-message case: zero-length buffer is well-defined.
1773        assert!(FlatMsg::default().encode_to_bytes().is_empty());
1774    }
1775
1776    #[test]
1777    fn test_decode_from_slice_empty() {
1778        let dst = FlatMsg::decode_from_slice(&[]).unwrap();
1779        assert_eq!(dst.value, 0);
1780    }
1781
1782    #[test]
1783    fn test_decode_from_slice_invalid_returns_error() {
1784        // A lone 0xFF byte is not a valid varint tag.
1785        let result = FlatMsg::decode_from_slice(&[0xFF]);
1786        assert!(result.is_err());
1787    }
1788
1789    #[test]
1790    fn test_merge_from_slice_basic() {
1791        let src = FlatMsg { value: 7 };
1792        let bytes = src.encode_to_vec();
1793        let mut dst = FlatMsg::default();
1794        dst.merge_from_slice(&bytes).unwrap();
1795        assert_eq!(dst.value, 7);
1796    }
1797
1798    #[test]
1799    fn test_merge_from_slice_last_wins() {
1800        let src1 = FlatMsg { value: 1 };
1801        let src2 = FlatMsg { value: 2 };
1802        let mut dst = FlatMsg::default();
1803        dst.merge_from_slice(&src1.encode_to_vec()).unwrap();
1804        dst.merge_from_slice(&src2.encode_to_vec()).unwrap();
1805        // Proto3 last-wins semantics for scalar fields.
1806        assert_eq!(dst.value, 2);
1807    }
1808
1809    // ── DecodeOptions tests ──────────────────────────────────────────
1810
1811    #[test]
1812    fn test_decode_options_default_works() {
1813        let src = FlatMsg { value: 99 };
1814        let bytes = src.encode_to_vec();
1815        let msg: FlatMsg = DecodeOptions::new().decode_from_slice(&bytes).unwrap();
1816        assert_eq!(msg.value, 99);
1817    }
1818
1819    #[test]
1820    fn test_decode_options_max_message_size_rejects() {
1821        let src = FlatMsg { value: 42 };
1822        let bytes = src.encode_to_vec();
1823        // Set max size to 1 byte — smaller than the encoded message.
1824        let result: Result<FlatMsg, _> = DecodeOptions::new()
1825            .with_max_message_size(1)
1826            .decode_from_slice(&bytes);
1827        assert_eq!(result, Err(DecodeError::MessageTooLarge));
1828    }
1829
1830    #[test]
1831    fn test_decode_options_max_message_size_exact_boundary() {
1832        let src = FlatMsg { value: 42 };
1833        let bytes = src.encode_to_vec();
1834        // Exact size should succeed.
1835        let msg: FlatMsg = DecodeOptions::new()
1836            .with_max_message_size(bytes.len())
1837            .decode_from_slice(&bytes)
1838            .unwrap();
1839        assert_eq!(msg.value, 42);
1840        // One byte less should fail.
1841        let result: Result<FlatMsg, _> = DecodeOptions::new()
1842            .with_max_message_size(bytes.len() - 1)
1843            .decode_from_slice(&bytes);
1844        assert_eq!(result, Err(DecodeError::MessageTooLarge));
1845    }
1846
1847    #[test]
1848    fn test_decode_options_custom_recursion_limit() {
1849        // FlatMsg has no nested messages, so any recursion limit >= 0 works.
1850        // Just verify the API compiles and runs.
1851        let src = FlatMsg { value: 7 };
1852        let bytes = src.encode_to_vec();
1853        let msg: FlatMsg = DecodeOptions::new()
1854            .with_recursion_limit(1)
1855            .decode_from_slice(&bytes)
1856            .unwrap();
1857        assert_eq!(msg.value, 7);
1858    }
1859
1860    #[test]
1861    fn test_decode_options_merge() {
1862        let src = FlatMsg { value: 55 };
1863        let bytes = src.encode_to_vec();
1864        let mut msg = FlatMsg::default();
1865        DecodeOptions::new()
1866            .merge_from_slice(&mut msg, &bytes)
1867            .unwrap();
1868        assert_eq!(msg.value, 55);
1869    }
1870
1871    #[test]
1872    fn test_decode_options_merge_rejects_oversize() {
1873        let src = FlatMsg { value: 55 };
1874        let bytes = src.encode_to_vec();
1875        let mut msg = FlatMsg::default();
1876        let result = DecodeOptions::new()
1877            .with_max_message_size(1)
1878            .merge_from_slice(&mut msg, &bytes);
1879        assert_eq!(result, Err(DecodeError::MessageTooLarge));
1880    }
1881
1882    #[test]
1883    fn test_decode_options_length_delimited() {
1884        let src = FlatMsg { value: 42 };
1885        let mut ld_bytes = alloc::vec::Vec::new();
1886        src.encode_length_delimited(&mut ld_bytes);
1887        let msg: FlatMsg = DecodeOptions::new()
1888            .decode_length_delimited(&mut ld_bytes.as_slice())
1889            .unwrap();
1890        assert_eq!(msg.value, 42);
1891    }
1892
1893    #[test]
1894    fn test_decode_options_length_delimited_rejects_oversize() {
1895        let src = FlatMsg { value: 42 };
1896        let mut ld_bytes = alloc::vec::Vec::new();
1897        src.encode_length_delimited(&mut ld_bytes);
1898        let result: Result<FlatMsg, _> = DecodeOptions::new()
1899            .with_max_message_size(1)
1900            .decode_length_delimited(&mut ld_bytes.as_slice());
1901        assert_eq!(result, Err(DecodeError::MessageTooLarge));
1902    }
1903
1904    #[test]
1905    fn decode_options_getters_return_defaults() {
1906        let opts = DecodeOptions::new();
1907        assert_eq!(opts.recursion_limit(), RECURSION_LIMIT);
1908        assert_eq!(opts.max_message_size(), 0x7FFF_FFFF);
1909        assert_eq!(opts.unknown_field_limit(), DEFAULT_UNKNOWN_FIELD_LIMIT);
1910    }
1911
1912    #[test]
1913    fn decode_options_getters_return_custom_values() {
1914        let opts = DecodeOptions::new()
1915            .with_recursion_limit(42)
1916            .with_max_message_size(1024)
1917            .with_unknown_field_limit(2048);
1918        assert_eq!(opts.recursion_limit(), 42);
1919        assert_eq!(opts.max_message_size(), 1024);
1920        assert_eq!(opts.unknown_field_limit(), 2048);
1921    }
1922
1923    #[cfg(debug_assertions)]
1924    #[test]
1925    #[should_panic(expected = "protobuf 2 GiB limit")]
1926    fn decode_options_max_message_size_above_protobuf_limit_debug_asserts() {
1927        let _ = DecodeOptions::new().with_max_message_size(DEFAULT_MAX_MESSAGE_SIZE + 1);
1928    }
1929
1930    #[cfg(not(debug_assertions))]
1931    #[test]
1932    fn decode_options_max_message_size_above_protobuf_limit_saturates() {
1933        let opts = DecodeOptions::new().with_max_message_size(DEFAULT_MAX_MESSAGE_SIZE + 1);
1934        assert_eq!(opts.max_message_size(), DEFAULT_MAX_MESSAGE_SIZE);
1935    }
1936
1937    #[test]
1938    fn test_decode_options_default_impl() {
1939        // DecodeOptions::default() ≡ DecodeOptions::new().
1940        let opts = DecodeOptions::default();
1941        assert_eq!(opts.recursion_limit(), RECURSION_LIMIT);
1942        assert_eq!(opts.max_message_size(), 0x7FFF_FFFF);
1943        assert_eq!(opts.unknown_field_limit(), DEFAULT_UNKNOWN_FIELD_LIMIT);
1944    }
1945
1946    #[test]
1947    fn test_decode_options_decode_buf() {
1948        // The Buf-taking decode() variant (vs decode_from_slice).
1949        let src = FlatMsg { value: 123 };
1950        let bytes = src.encode_to_vec();
1951        let msg: FlatMsg = DecodeOptions::new().decode(&mut bytes.as_slice()).unwrap();
1952        assert_eq!(msg.value, 123);
1953        // Oversize check on the Buf variant.
1954        let result: Result<FlatMsg, _> = DecodeOptions::new()
1955            .with_max_message_size(1)
1956            .decode(&mut bytes.as_slice());
1957        assert_eq!(result, Err(DecodeError::MessageTooLarge));
1958    }
1959
1960    #[test]
1961    fn test_decode_options_merge_buf() {
1962        // The Buf-taking merge() variant (vs merge_from_slice).
1963        let src = FlatMsg { value: 77 };
1964        let bytes = src.encode_to_vec();
1965        let mut msg = FlatMsg::default();
1966        DecodeOptions::new()
1967            .merge(&mut msg, &mut bytes.as_slice())
1968            .unwrap();
1969        assert_eq!(msg.value, 77);
1970        // Oversize check.
1971        let mut msg = FlatMsg::default();
1972        let result = DecodeOptions::new()
1973            .with_max_message_size(1)
1974            .merge(&mut msg, &mut bytes.as_slice());
1975        assert_eq!(result, Err(DecodeError::MessageTooLarge));
1976    }
1977
1978    // ── Message trait default methods ─────────────────────────────────
1979
1980    #[test]
1981    fn test_message_encode_trait_default() {
1982        // Message::encode(buf) ≡ compute_size() then write_to(buf).
1983        let src = FlatMsg { value: 42 };
1984        let mut buf = alloc::vec::Vec::new();
1985        src.encode(&mut buf);
1986        assert_eq!(buf, src.encode_to_vec());
1987    }
1988
1989    #[test]
1990    fn test_message_decode_length_delimited_trait_default() {
1991        // The trait-level decode_length_delimited (distinct from
1992        // DecodeOptions::decode_length_delimited).
1993        let src = FlatMsg { value: 42 };
1994        let mut ld = alloc::vec::Vec::new();
1995        src.encode_length_delimited(&mut ld);
1996        let got = FlatMsg::decode_length_delimited(&mut ld.as_slice()).unwrap();
1997        assert_eq!(got.value, 42);
1998    }
1999
2000    #[test]
2001    fn test_message_decode_length_delimited_oversize() {
2002        // Length prefix > 2 GiB → MessageTooLarge.
2003        let mut buf = alloc::vec::Vec::new();
2004        encode_varint(0x8000_0000u64, &mut buf);
2005        let result = FlatMsg::decode_length_delimited(&mut buf.as_slice());
2006        assert_eq!(result, Err(DecodeError::MessageTooLarge));
2007    }
2008
2009    #[test]
2010    fn test_message_decode_length_delimited_truncated() {
2011        // Length prefix says 10 bytes, buffer has 2.
2012        let mut buf = alloc::vec::Vec::new();
2013        encode_varint(10, &mut buf);
2014        buf.push(0x08);
2015        buf.push(0x01);
2016        let result = FlatMsg::decode_length_delimited(&mut buf.as_slice());
2017        assert_eq!(result, Err(DecodeError::UnexpectedEof));
2018    }
2019
2020    #[test]
2021    fn test_message_decode_length_delimited_with_trailing() {
2022        // Buffer has two back-to-back length-delimited messages.
2023        // decode_length_delimited should consume exactly the first one
2024        // and leave the buffer positioned at the second.
2025        let a = FlatMsg { value: 1 };
2026        let b = FlatMsg { value: 2 };
2027        let mut buf = alloc::vec::Vec::new();
2028        a.encode_length_delimited(&mut buf);
2029        b.encode_length_delimited(&mut buf);
2030
2031        let mut cur = buf.as_slice();
2032        let first = FlatMsg::decode_length_delimited(&mut cur).unwrap();
2033        assert_eq!(first.value, 1);
2034        let second = FlatMsg::decode_length_delimited(&mut cur).unwrap();
2035        assert_eq!(second.value, 2);
2036        assert!(cur.is_empty());
2037    }
2038
2039    // ── merge_group tests ─────────────────────────────────────────────
2040
2041    /// Build a group body for FlatMsg (field 1 = value) terminated by
2042    /// EndGroup with the given field number.
2043    fn group_bytes(value: i32, group_field_number: u32) -> alloc::vec::Vec<u8> {
2044        use crate::encoding::{Tag, WireType};
2045        let mut buf = alloc::vec::Vec::new();
2046        if value != 0 {
2047            Tag::new(1, WireType::Varint).encode(&mut buf);
2048            crate::types::encode_int32(value, &mut buf);
2049        }
2050        Tag::new(group_field_number, WireType::EndGroup).encode(&mut buf);
2051        buf
2052    }
2053
2054    #[test]
2055    fn test_merge_group_basic() {
2056        let data = group_bytes(42, 5);
2057        let mut dst = FlatMsg::default();
2058        dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5)
2059            .unwrap();
2060        assert_eq!(dst.value, 42);
2061    }
2062
2063    #[test]
2064    fn test_merge_group_empty() {
2065        // Group with no fields — just EndGroup.
2066        let data = group_bytes(0, 3);
2067        let mut dst = FlatMsg::default();
2068        dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 3)
2069            .unwrap();
2070        assert_eq!(dst.value, 0);
2071    }
2072
2073    #[test]
2074    fn test_merge_group_merges_into_existing() {
2075        let data1 = group_bytes(1, 5);
2076        let data2 = group_bytes(2, 5);
2077        let mut dst = FlatMsg::default();
2078        dst.merge_group(&mut data1.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5)
2079            .unwrap();
2080        assert_eq!(dst.value, 1);
2081        dst.merge_group(&mut data2.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5)
2082            .unwrap();
2083        assert_eq!(dst.value, 2);
2084    }
2085
2086    #[test]
2087    fn test_merge_group_recursion_limit_zero() {
2088        // depth=0 should immediately fail with RecursionLimitExceeded
2089        // because merge_group decrements before entering the loop.
2090        let data = group_bytes(42, 5);
2091        let mut dst = FlatMsg::default();
2092        assert_eq!(
2093            dst.merge_group(&mut data.as_slice(), crate::test_ctx(0), 5),
2094            Err(DecodeError::RecursionLimitExceeded)
2095        );
2096    }
2097
2098    #[test]
2099    fn test_merge_group_recursion_limit_one_succeeds() {
2100        // depth=1 succeeds: merge_group decrements to 0, but FlatMsg's
2101        // merge_field doesn't recurse further.
2102        let data = group_bytes(7, 5);
2103        let mut dst = FlatMsg::default();
2104        dst.merge_group(&mut data.as_slice(), crate::test_ctx(1), 5)
2105            .unwrap();
2106        assert_eq!(dst.value, 7);
2107    }
2108
2109    #[test]
2110    fn test_merge_group_mismatched_end() {
2111        // EndGroup with wrong field number.
2112        use crate::encoding::{Tag, WireType};
2113        let mut data = alloc::vec::Vec::new();
2114        Tag::new(99, WireType::EndGroup).encode(&mut data);
2115
2116        let mut dst = FlatMsg::default();
2117        assert_eq!(
2118            dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5),
2119            Err(DecodeError::InvalidEndGroup(99))
2120        );
2121    }
2122
2123    #[test]
2124    fn test_merge_group_truncated() {
2125        // Buffer ends without EndGroup tag.
2126        use crate::encoding::{Tag, WireType};
2127        let mut data = alloc::vec::Vec::new();
2128        Tag::new(1, WireType::Varint).encode(&mut data);
2129        crate::types::encode_int32(42, &mut data);
2130        // No EndGroup.
2131
2132        let mut dst = FlatMsg::default();
2133        assert_eq!(
2134            dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5),
2135            Err(DecodeError::UnexpectedEof)
2136        );
2137    }
2138
2139    #[test]
2140    fn test_merge_group_empty_buffer() {
2141        let mut dst = FlatMsg::default();
2142        assert_eq!(
2143            dst.merge_group(&mut [].as_slice(), crate::test_ctx(RECURSION_LIMIT), 5),
2144            Err(DecodeError::UnexpectedEof)
2145        );
2146    }
2147
2148    #[test]
2149    fn test_merge_group_unknown_fields_skipped() {
2150        // Group body contains an unknown field (field 99) which FlatMsg
2151        // routes to skip_field; the known field (field 1) should still
2152        // be decoded.
2153        use crate::encoding::{Tag, WireType};
2154        let mut data = alloc::vec::Vec::new();
2155        // Unknown varint field 99 = 0
2156        Tag::new(99, WireType::Varint).encode(&mut data);
2157        crate::encoding::encode_varint(0, &mut data);
2158        // Known field 1 = 99
2159        Tag::new(1, WireType::Varint).encode(&mut data);
2160        crate::types::encode_int32(99, &mut data);
2161        // EndGroup(5)
2162        Tag::new(5, WireType::EndGroup).encode(&mut data);
2163
2164        let mut dst = FlatMsg::default();
2165        dst.merge_group(&mut data.as_slice(), crate::test_ctx(RECURSION_LIMIT), 5)
2166            .unwrap();
2167        assert_eq!(dst.value, 99);
2168    }
2169
2170    #[test]
2171    fn test_merge_group_trailing_data_preserved() {
2172        // After the EndGroup tag, trailing data should remain in the buffer.
2173        let mut data = group_bytes(42, 5);
2174        data.extend_from_slice(&[0xDE, 0xAD]);
2175
2176        let mut cur = data.as_slice();
2177        let mut dst = FlatMsg::default();
2178        dst.merge_group(&mut cur, crate::test_ctx(RECURSION_LIMIT), 5)
2179            .unwrap();
2180        assert_eq!(dst.value, 42);
2181        assert_eq!(cur, &[0xDE, 0xAD]);
2182    }
2183
2184    // ── read_varint (std::io::Read) tests ──────────────────────────────
2185
2186    #[cfg(feature = "std")]
2187    mod read_varint_tests {
2188        use super::super::read_varint;
2189        use crate::encoding::encode_varint;
2190
2191        #[test]
2192        fn roundtrip_values() {
2193            let cases: &[u64] = &[0, 1, 127, 128, 300, 1 << 14, 1 << 35, 1 << 63, u64::MAX];
2194            for &v in cases {
2195                let mut buf = Vec::new();
2196                encode_varint(v, &mut buf);
2197                let got = read_varint(&mut buf.as_slice()).unwrap();
2198                assert_eq!(got, v, "roundtrip failed for {v}");
2199            }
2200        }
2201
2202        #[test]
2203        fn rejects_10th_byte_overflow() {
2204            // 9 continuation bytes + 10th byte with overflow bit (0x02).
2205            // Mirrors encoding::tests::test_varint_10th_byte_overflow_rejected.
2206            let mut bad: Vec<u8> = vec![0xFF; 9];
2207            bad.push(0x02);
2208            let err = read_varint(&mut bad.as_slice()).unwrap_err();
2209            assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
2210        }
2211
2212        #[test]
2213        fn rejects_11th_byte() {
2214            // 10 continuation bytes — implies an 11th byte is needed.
2215            let bad: &[u8] = &[0xFF; 10];
2216            let err = read_varint(&mut &bad[..]).unwrap_err();
2217            assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
2218        }
2219
2220        #[test]
2221        fn u64_max_roundtrips() {
2222            // u64::MAX requires 10 bytes with the 10th byte == 0x01.
2223            let mut buf = Vec::new();
2224            encode_varint(u64::MAX, &mut buf);
2225            assert_eq!(buf.len(), 10);
2226            assert_eq!(buf[9], 0x01);
2227            let got = read_varint(&mut buf.as_slice()).unwrap();
2228            assert_eq!(got, u64::MAX);
2229        }
2230
2231        #[test]
2232        fn eof_before_terminator_is_error() {
2233            // Single continuation byte with no follow-up.
2234            let bad: &[u8] = &[0x80];
2235            let err = read_varint(&mut &bad[..]).unwrap_err();
2236            assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
2237        }
2238
2239        #[test]
2240        fn empty_input_is_error() {
2241            let err = read_varint(&mut &[][..]).unwrap_err();
2242            assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
2243        }
2244    }
2245
2246    // ── Encode-side 2 GiB guard tests ──────────────────────────────────
2247
2248    use crate::test_doubles::SizedMsg;
2249
2250    const OVER_LIMIT: u32 = MAX_MESSAGE_BYTES + 1;
2251
2252    #[test]
2253    fn saturate_size_is_exact_below_u32_max_and_saturates_above() {
2254        assert_eq!(saturate_size(0), 0);
2255        assert_eq!(saturate_size(MAX_MESSAGE_BYTES as u64), MAX_MESSAGE_BYTES);
2256        // 2–4 GiB window: exact (this is what makes the guard byte-precise).
2257        assert_eq!(saturate_size(0x8000_0000), 0x8000_0000u32);
2258        assert_eq!(saturate_size(u32::MAX as u64), u32::MAX);
2259        assert_eq!(saturate_size(u32::MAX as u64 + 1), u32::MAX);
2260        assert_eq!(saturate_size(u64::MAX), u32::MAX);
2261    }
2262
2263    #[test]
2264    fn encode_at_exactly_max_size_is_allowed() {
2265        // The guard is strictly-greater-than: a (fake) message of exactly
2266        // MAX_MESSAGE_BYTES passes. `encode` has no write-count ledger, so
2267        // the no-op write_to is fine here.
2268        let msg = SizedMsg {
2269            reported_size: MAX_MESSAGE_BYTES,
2270        };
2271        let mut buf = alloc::vec::Vec::new();
2272        msg.encode(&mut buf);
2273        assert!(msg.try_encode(&mut buf).is_ok());
2274    }
2275
2276    #[test]
2277    #[should_panic(expected = "2 GiB protobuf limit")]
2278    fn encode_over_limit_panics() {
2279        let msg = SizedMsg {
2280            reported_size: OVER_LIMIT,
2281        };
2282        let mut buf = alloc::vec::Vec::new();
2283        msg.encode(&mut buf);
2284    }
2285
2286    #[test]
2287    #[should_panic(expected = "2 GiB protobuf limit")]
2288    fn encoded_len_over_limit_panics() {
2289        let msg = SizedMsg {
2290            reported_size: OVER_LIMIT,
2291        };
2292        let _ = msg.encoded_len();
2293    }
2294
2295    #[test]
2296    #[should_panic(expected = "2 GiB protobuf limit")]
2297    fn encode_with_cache_over_limit_panics() {
2298        let msg = SizedMsg {
2299            reported_size: OVER_LIMIT,
2300        };
2301        let mut cache = SizeCache::new();
2302        let mut buf = alloc::vec::Vec::new();
2303        msg.encode_with_cache(&mut cache, &mut buf);
2304    }
2305
2306    #[test]
2307    #[should_panic(expected = "2 GiB protobuf limit")]
2308    fn encode_to_vec_over_limit_panics() {
2309        let msg = SizedMsg {
2310            reported_size: OVER_LIMIT,
2311        };
2312        let _ = msg.encode_to_vec();
2313    }
2314
2315    #[test]
2316    #[should_panic(expected = "2 GiB protobuf limit")]
2317    fn encode_to_bytes_over_limit_panics() {
2318        let msg = SizedMsg {
2319            reported_size: OVER_LIMIT,
2320        };
2321        let _ = msg.encode_to_bytes();
2322    }
2323
2324    #[test]
2325    #[should_panic(expected = "2 GiB protobuf limit")]
2326    fn encode_length_delimited_over_limit_panics() {
2327        let msg = SizedMsg {
2328            reported_size: OVER_LIMIT,
2329        };
2330        let mut buf = alloc::vec::Vec::new();
2331        msg.encode_length_delimited(&mut buf);
2332    }
2333
2334    #[test]
2335    fn try_encode_over_limit_errors_and_writes_nothing() {
2336        let msg = SizedMsg {
2337            reported_size: OVER_LIMIT,
2338        };
2339        let mut buf = alloc::vec::Vec::new();
2340        assert_eq!(msg.try_encode(&mut buf), Err(EncodeError::MessageTooLarge));
2341        assert!(buf.is_empty(), "no bytes may reach the buffer on Err");
2342        let mut cache = SizeCache::new();
2343        assert_eq!(
2344            msg.try_encode_with_cache(&mut cache, &mut buf),
2345            Err(EncodeError::MessageTooLarge)
2346        );
2347        assert!(buf.is_empty(), "no bytes may reach the buffer on Err");
2348        assert_eq!(
2349            msg.try_encode_length_delimited(&mut buf),
2350            Err(EncodeError::MessageTooLarge)
2351        );
2352        assert!(buf.is_empty(), "not even the length prefix");
2353        assert_eq!(msg.try_encode_to_vec(), Err(EncodeError::MessageTooLarge));
2354        assert_eq!(msg.try_encode_to_bytes(), Err(EncodeError::MessageTooLarge));
2355        assert_eq!(msg.try_encoded_len(), Err(EncodeError::MessageTooLarge));
2356    }
2357
2358    #[test]
2359    fn try_encode_matches_encode_for_normal_messages() {
2360        let msg = FlatMsg { value: 42 };
2361        let mut expected = alloc::vec::Vec::new();
2362        msg.encode(&mut expected);
2363        let mut actual = alloc::vec::Vec::new();
2364        msg.try_encode(&mut actual).unwrap();
2365        assert_eq!(actual, expected);
2366        let mut cache = SizeCache::new();
2367        let mut cached = alloc::vec::Vec::new();
2368        msg.try_encode_with_cache(&mut cache, &mut cached).unwrap();
2369        assert_eq!(cached, expected);
2370        assert_eq!(msg.try_encode_to_vec().unwrap(), expected);
2371        assert_eq!(msg.try_encode_to_bytes().unwrap(), expected);
2372        assert_eq!(msg.try_encoded_len().unwrap(), expected.len() as u32);
2373
2374        let mut ld_expected = alloc::vec::Vec::new();
2375        msg.encode_length_delimited(&mut ld_expected);
2376        let mut ld_actual = alloc::vec::Vec::new();
2377        msg.try_encode_length_delimited(&mut ld_actual).unwrap();
2378        assert_eq!(ld_actual, ld_expected);
2379    }
2380
2381    #[test]
2382    fn try_encode_bounded_within_budget_encodes_and_returns_len() {
2383        let msg = FlatMsg { value: 42 };
2384        let mut expected = alloc::vec::Vec::new();
2385        msg.encode(&mut expected);
2386        let budget = expected.len() as u32;
2387
2388        let mut buf = alloc::vec::Vec::new();
2389        let len = msg.try_encode_bounded(budget, &mut buf).unwrap();
2390        assert_eq!(buf, expected);
2391        assert_eq!(len, budget);
2392
2393        // with_cache variant agrees
2394        let mut cache = SizeCache::new();
2395        let mut buf2 = alloc::vec::Vec::new();
2396        let len2 = msg
2397            .try_encode_bounded_with_cache(budget, &mut cache, &mut buf2)
2398            .unwrap();
2399        assert_eq!(buf2, expected);
2400        assert_eq!(len2, budget);
2401    }
2402
2403    #[test]
2404    fn try_encode_bounded_at_exact_limit_succeeds() {
2405        let msg = FlatMsg { value: 42 };
2406        let exact = msg.encoded_len();
2407        let mut buf = alloc::vec::Vec::new();
2408        assert!(msg.try_encode_bounded(exact, &mut buf).is_ok());
2409    }
2410
2411    #[test]
2412    fn try_encode_bounded_over_budget_errors_and_writes_nothing() {
2413        let msg = FlatMsg { value: 42 };
2414        let len = msg.encoded_len();
2415        let budget = len - 1; // one byte under
2416
2417        let mut buf = alloc::vec::Vec::new();
2418        assert_eq!(
2419            msg.try_encode_bounded(budget, &mut buf),
2420            Err(EncodeError::ExceedsBudget {
2421                len,
2422                max_bytes: budget
2423            })
2424        );
2425        assert!(buf.is_empty(), "nothing written on budget exceeded");
2426    }
2427
2428    /// "Nothing written on `Err`" has to hold for a sink that already has
2429    /// bytes in it, which is how a caller framing several messages uses one
2430    /// buffer. Every other test starts from an empty `Vec`, so the append
2431    /// case — where a partial write would corrupt the *preceding* message
2432    /// rather than produce an obviously empty one — would go unnoticed.
2433    #[test]
2434    fn try_encode_bounded_over_budget_leaves_a_populated_buffer_untouched() {
2435        let msg = FlatMsg { value: 42 };
2436        let len = msg.encoded_len();
2437        let budget = len - 1;
2438
2439        let prefix = b"already framed".to_vec();
2440        let mut buf = prefix.clone();
2441        assert_eq!(
2442            msg.try_encode_bounded(budget, &mut buf),
2443            Err(EncodeError::ExceedsBudget {
2444                len,
2445                max_bytes: budget
2446            })
2447        );
2448        assert_eq!(buf, prefix, "the bytes already in the sink must survive");
2449    }
2450
2451    #[test]
2452    fn try_encode_bounded_zero_budget_with_empty_message_succeeds() {
2453        // A default FlatMsg with value=0 encodes to 0 bytes (all defaults
2454        // are elided in proto3), so budget=0 is exactly satisfied.
2455        let msg = FlatMsg { value: 0 };
2456        let mut buf = alloc::vec::Vec::new();
2457        let len = msg.try_encode_bounded(0, &mut buf).unwrap();
2458        assert_eq!(len, 0);
2459        assert!(buf.is_empty());
2460    }
2461
2462    #[test]
2463    fn try_encode_bounded_over_protobuf_limit_errors_as_too_large() {
2464        let msg = SizedMsg {
2465            reported_size: OVER_LIMIT,
2466        };
2467        let mut buf = alloc::vec::Vec::new();
2468        assert_eq!(
2469            msg.try_encode_bounded(u32::MAX, &mut buf),
2470            Err(EncodeError::MessageTooLarge)
2471        );
2472        assert!(buf.is_empty());
2473    }
2474
2475    #[test]
2476    fn pool_try_encode_bounded_within_budget_encodes_and_returns_len() {
2477        let msg = FlatMsg { value: 42 };
2478        let mut expected = alloc::vec::Vec::new();
2479        msg.encode(&mut expected);
2480        let budget = expected.len() as u32;
2481
2482        let mut pool = crate::SizeCachePool::sequential(64);
2483        let mut buf = alloc::vec::Vec::new();
2484        let len = pool.try_encode_bounded(&msg, budget, &mut buf).unwrap();
2485        assert_eq!(buf, expected);
2486        assert_eq!(len, budget);
2487    }
2488
2489    #[test]
2490    fn pool_try_encode_bounded_over_budget_errors_and_writes_nothing() {
2491        let msg = FlatMsg { value: 42 };
2492        let len = msg.encoded_len();
2493        let budget = len - 1;
2494
2495        let mut pool = crate::SizeCachePool::sequential(64);
2496        let mut buf = alloc::vec::Vec::new();
2497        assert_eq!(
2498            pool.try_encode_bounded(&msg, budget, &mut buf),
2499            Err(EncodeError::ExceedsBudget {
2500                len,
2501                max_bytes: budget
2502            })
2503        );
2504        assert!(buf.is_empty());
2505        // Pool buffer must be returned even on Err.
2506        assert_eq!(pool.try_encode_bounded(&msg, len, &mut buf).unwrap(), len);
2507    }
2508
2509    #[test]
2510    fn pool_try_encode_bounded_over_protobuf_limit_errors_as_too_large() {
2511        let msg = SizedMsg {
2512            reported_size: OVER_LIMIT,
2513        };
2514        let mut pool = crate::SizeCachePool::sequential(64);
2515        let mut buf = alloc::vec::Vec::new();
2516        assert_eq!(
2517            pool.try_encode_bounded(&msg, u32::MAX, &mut buf),
2518            Err(EncodeError::MessageTooLarge)
2519        );
2520        assert!(buf.is_empty());
2521    }
2522
2523    #[test]
2524    #[should_panic(expected = "2 GiB protobuf limit")]
2525    fn pool_encoded_len_over_limit_panics() {
2526        // SizeCachePool::encoded_len documents itself as the pooled
2527        // equivalent of Message::encoded_len — it must share the guard.
2528        let msg = SizedMsg {
2529            reported_size: OVER_LIMIT,
2530        };
2531        let mut pool = crate::SizeCachePool::sequential(1024);
2532        let _ = pool.encoded_len(&msg);
2533    }
2534
2535    #[cfg(debug_assertions)]
2536    #[test]
2537    #[should_panic(expected = "two-pass traversal mismatch")]
2538    fn encode_to_vec_ledger_catches_size_write_disagreement() {
2539        // An under-limit reported size with a no-op write_to: the guard
2540        // passes, then the debug ledger flags the two-pass divergence.
2541        let msg = SizedMsg { reported_size: 3 };
2542        let _ = msg.encode_to_vec();
2543    }
2544
2545    // ── DecodeOptions std::io::Read tests ─────────────────────────────
2546
2547    #[cfg(feature = "std")]
2548    mod reader_tests {
2549        use super::*;
2550
2551        #[test]
2552        fn decode_reader_basic() {
2553            let src = FlatMsg { value: 42 };
2554            let bytes = src.encode_to_vec();
2555            let msg: FlatMsg = DecodeOptions::new()
2556                .decode_reader(&mut bytes.as_slice())
2557                .unwrap();
2558            assert_eq!(msg.value, 42);
2559        }
2560
2561        #[test]
2562        fn decode_reader_rejects_oversize() {
2563            let src = FlatMsg { value: 42 };
2564            let bytes = src.encode_to_vec();
2565            let err = DecodeOptions::new()
2566                .with_max_message_size(1)
2567                .decode_reader::<FlatMsg>(&mut bytes.as_slice())
2568                .unwrap_err();
2569            assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
2570        }
2571
2572        #[test]
2573        fn decode_reader_exact_boundary() {
2574            // max_message_size == encoded length → success.
2575            let src = FlatMsg { value: 42 };
2576            let bytes = src.encode_to_vec();
2577            let msg: FlatMsg = DecodeOptions::new()
2578                .with_max_message_size(bytes.len())
2579                .decode_reader(&mut bytes.as_slice())
2580                .unwrap();
2581            assert_eq!(msg.value, 42);
2582        }
2583
2584        #[test]
2585        fn decode_options_reader_size_unbounded_getter_tracks_builder_order() {
2586            let opts = DecodeOptions::new();
2587            assert!(!opts.is_reader_size_unbounded());
2588
2589            let opts = opts.without_reader_size_limit();
2590            assert!(opts.is_reader_size_unbounded());
2591
2592            let opts = opts.with_max_message_size(1024);
2593            assert!(!opts.is_reader_size_unbounded());
2594        }
2595
2596        #[test]
2597        fn decode_reader_without_size_limit_does_not_overflow() {
2598            let src = FlatMsg { value: 42 };
2599            let bytes = src.encode_to_vec();
2600            let msg: FlatMsg = DecodeOptions::new()
2601                .without_reader_size_limit()
2602                .decode_reader(&mut bytes.as_slice())
2603                .unwrap();
2604            assert_eq!(msg.value, 42);
2605        }
2606
2607        #[test]
2608        fn decode_reader_with_max_message_size_after_without_limit_reenables_limit() {
2609            let src = FlatMsg { value: 42 };
2610            let bytes = src.encode_to_vec();
2611            let opts = DecodeOptions::new()
2612                .without_reader_size_limit()
2613                .with_max_message_size(1);
2614            assert!(!opts.is_reader_size_unbounded());
2615
2616            let err = opts
2617                .decode_reader::<FlatMsg>(&mut bytes.as_slice())
2618                .unwrap_err();
2619            assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
2620        }
2621
2622        #[test]
2623        fn decode_reader_without_size_limit_keeps_slice_limit() {
2624            let src = FlatMsg { value: 42 };
2625            let bytes = src.encode_to_vec();
2626            let opts = DecodeOptions::new()
2627                .with_max_message_size(1)
2628                .without_reader_size_limit();
2629            assert!(opts.is_reader_size_unbounded());
2630
2631            let slice_result: Result<FlatMsg, _> = opts.decode_from_slice(&bytes);
2632            assert_eq!(slice_result, Err(DecodeError::MessageTooLarge));
2633
2634            let msg: FlatMsg = opts.decode_reader(&mut bytes.as_slice()).unwrap();
2635            assert_eq!(msg.value, 42);
2636        }
2637
2638        #[test]
2639        fn decode_reader_propagates_read_error() {
2640            // A reader that errors immediately.
2641            struct ErrReader;
2642            impl std::io::Read for ErrReader {
2643                fn read(&mut self, _: &mut [u8]) -> std::io::Result<usize> {
2644                    Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, "gone"))
2645                }
2646            }
2647            let err = DecodeOptions::new()
2648                .decode_reader::<FlatMsg>(&mut ErrReader)
2649                .unwrap_err();
2650            assert_eq!(err.kind(), std::io::ErrorKind::BrokenPipe);
2651        }
2652
2653        #[test]
2654        fn decode_length_delimited_reader_basic() {
2655            let src = FlatMsg { value: 99 };
2656            let mut ld = Vec::new();
2657            src.encode_length_delimited(&mut ld);
2658            let msg: FlatMsg = DecodeOptions::new()
2659                .decode_length_delimited_reader(&mut ld.as_slice())
2660                .unwrap();
2661            assert_eq!(msg.value, 99);
2662        }
2663
2664        #[test]
2665        fn decode_length_delimited_reader_rejects_oversize_prefix() {
2666            // Length prefix claims more bytes than max_message_size allows.
2667            let src = FlatMsg { value: 99 };
2668            let mut ld = Vec::new();
2669            src.encode_length_delimited(&mut ld);
2670            let err = DecodeOptions::new()
2671                .with_max_message_size(1)
2672                .decode_length_delimited_reader::<FlatMsg>(&mut ld.as_slice())
2673                .unwrap_err();
2674            assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
2675        }
2676
2677        #[test]
2678        fn decode_length_delimited_reader_zero_length() {
2679            // A zero length prefix decodes to the default message and
2680            // consumes only the prefix byte.
2681            let stream = [0x00u8, 0xFF]; // len=0, then unrelated trailing byte
2682            let mut cursor = std::io::Cursor::new(stream);
2683            let msg: FlatMsg = DecodeOptions::new()
2684                .decode_length_delimited_reader(&mut cursor)
2685                .unwrap();
2686            assert_eq!(msg, FlatMsg::default());
2687            assert_eq!(cursor.position(), 1);
2688        }
2689
2690        #[test]
2691        fn decode_length_delimited_reader_truncated_reports_eof() {
2692            // Length prefix declares more bytes than the stream delivers.
2693            let src = FlatMsg { value: 99 };
2694            let mut ld = Vec::new();
2695            src.encode_length_delimited(&mut ld);
2696            ld.truncate(ld.len() - 1);
2697            let err = DecodeOptions::new()
2698                .decode_length_delimited_reader::<FlatMsg>(&mut ld.as_slice())
2699                .unwrap_err();
2700            assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
2701        }
2702
2703        #[test]
2704        fn decode_length_delimited_reader_huge_claim_without_delivery() {
2705            // A 5-byte prefix declaring ~2 GiB followed by EOF must fail with
2706            // UnexpectedEof without allocating the declared length up front —
2707            // the buffer only grows as bytes are actually delivered. (This
2708            // test completes instantly; before the incremental-read fix it
2709            // zero-filled a ~2 GiB buffer first.)
2710            let mut stream = Vec::new();
2711            encode_varint(0x7FFF_FFF0, &mut stream); // just under the cap
2712            let err = DecodeOptions::new()
2713                .decode_length_delimited_reader::<FlatMsg>(&mut stream.as_slice())
2714                .unwrap_err();
2715            assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
2716        }
2717
2718        #[test]
2719        fn decode_length_delimited_without_reader_size_limit_keeps_protobuf_cap() {
2720            let mut stream = Vec::new();
2721            encode_varint(0x8000_0000, &mut stream);
2722            let result: Result<FlatMsg, _> = DecodeOptions::new()
2723                .without_reader_size_limit()
2724                .decode_length_delimited(&mut stream.as_slice());
2725            assert_eq!(result, Err(DecodeError::MessageTooLarge));
2726        }
2727
2728        #[test]
2729        fn decode_length_delimited_reader_without_size_limit_keeps_protobuf_cap() {
2730            let mut stream = Vec::new();
2731            encode_varint(0x8000_0000, &mut stream);
2732            let err = DecodeOptions::new()
2733                .without_reader_size_limit()
2734                .decode_length_delimited_reader::<FlatMsg>(&mut stream.as_slice())
2735                .unwrap_err();
2736            assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
2737        }
2738
2739        #[test]
2740        fn decode_length_delimited_reader_sequential() {
2741            // Two messages in a stream — typical log-file use case.
2742            let a = FlatMsg { value: 10 };
2743            let b = FlatMsg { value: 20 };
2744            let mut stream = Vec::new();
2745            a.encode_length_delimited(&mut stream);
2746            b.encode_length_delimited(&mut stream);
2747
2748            let mut cursor = std::io::Cursor::new(stream);
2749            let first: FlatMsg = DecodeOptions::new()
2750                .decode_length_delimited_reader(&mut cursor)
2751                .unwrap();
2752            assert_eq!(first.value, 10);
2753            let second: FlatMsg = DecodeOptions::new()
2754                .decode_length_delimited_reader(&mut cursor)
2755                .unwrap();
2756            assert_eq!(second.value, 20);
2757        }
2758
2759        #[test]
2760        fn decode_length_delimited_reader_truncated_body() {
2761            // Length prefix says N bytes but reader EOFs early.
2762            let mut buf = Vec::new();
2763            crate::encoding::encode_varint(100, &mut buf);
2764            buf.push(0x08);
2765            let err = DecodeOptions::new()
2766                .decode_length_delimited_reader::<FlatMsg>(&mut buf.as_slice())
2767                .unwrap_err();
2768            assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
2769        }
2770    }
2771}