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}