Skip to main content

DecodeOptions

Struct DecodeOptions 

Source
pub struct DecodeOptions { /* private fields */ }
Expand description

Options for configuring message decoding behavior.

Use this to set custom recursion depth limits or maximum message sizes when decoding from untrusted input.

§Examples

use buffa::DecodeOptions;

// Restrict recursion depth to 50 and message size to 1 MiB:
let msg: Person = DecodeOptions::new()
    .with_recursion_limit(50)
    .with_max_message_size(1024 * 1024)
    .decode_from_slice(bytes)?;

Implementations§

Source§

impl DecodeOptions

Source

pub fn new() -> Self

Create new decode options with defaults.

Defaults:

Source

pub fn with_recursion_limit(self, limit: u32) -> Self

Set the maximum recursion depth for nested messages.

Each nested sub-message consumes one level of depth budget. When the budget reaches zero, decoding returns DecodeError::RecursionLimitExceeded.

Default: 100.

Source

pub fn with_max_message_size(self, max_bytes: usize) -> Self

Set the maximum total message size in bytes.

If the input buffer or length-delimited payload exceeds this size, decoding returns DecodeError::MessageTooLarge.

Values above the protobuf message-size limit (2 GiB - 1) are clamped to that limit. Debug builds assert on out-of-range values so accidental usize::MAX sentinels are caught during development. On std builds, use without_reader_size_limit when EOF-bounded decode_reader input intentionally has no byte cap.

Calling this re-enables the reader byte cap, overriding any prior without_reader_size_limit.

This is checked at the top-level decode entry point. Individual sub-messages are still bounded by the internal 2 GiB limit regardless of this setting.

Default: 2 GiB - 1 (0x7FFF_FFFF).

Source

pub fn without_reader_size_limit(self) -> Self

Available on crate feature std only.

Remove the byte cap for EOF-bounded decode_reader input.

This is only used by the std::io::Read entry point that reads until EOF. Slice-, Buf-, and view-based entry points remain bounded by the configured with_max_message_size (itself capped at the protobuf 2 GiB - 1 maximum), and length-delimited paths keep the same hard cap because their declared length is attacker-controlled.

An unbounded reader can exhaust memory if the source does not end or is larger than available allocation capacity. Prefer with_max_message_size for untrusted input.

Source

pub fn with_unknown_field_limit(self, count: usize) -> Self

Set the maximum number of unknown fields decoded per decode call.

Each decoded unknown field occupies a ~40-byte UnknownField slot regardless of its wire size (a minimal field is 2 wire bytes — a ~20× amplification), so an input-size cap alone does not bound decoder memory; this limit does, at roughly limit × 40 bytes of slot overhead. Unknown length-delimited payload bytes are not counted — they are bounded by the input size, which with_max_message_size governs. When the limit is exceeded, decoding returns DecodeError::UnknownFieldLimitExceeded.

Zero-copy view decoding (decode_view) charges one slot per unknown field — including fields nested inside unknown groups — even though views store unknown fields as coalesced spans (~16 bytes per contiguous run): coalescing bounds view memory, while this limit bounds what converting the view to an owned message would materialize. Conversion replays under exactly the budget decoding charged, so a view that decodes within this limit always converts.

Default: 1,000,000 (DEFAULT_UNKNOWN_FIELD_LIMIT).

Source

pub fn recursion_limit(&self) -> u32

Returns the configured recursion depth limit.

Source

pub fn unknown_field_limit(&self) -> usize

Returns the configured unknown-field limit.

Source

pub fn max_message_size(&self) -> usize

Returns the configured maximum message size in bytes for bounded decode entry points.

This returns the configured (clamped) value even when without_reader_size_limit is enabled for EOF-bounded reader input — the slice/Buf/view paths still honor it. Use is_reader_size_unbounded (std only) to inspect the reader flag.

Source

pub fn is_reader_size_unbounded(&self) -> bool

Available on crate feature std only.

Returns whether EOF-bounded reader input has no byte cap.

Source

pub fn decode<M: Message>(&self, buf: &mut impl Buf) -> Result<M, DecodeError>

Decode a message from a buffer.

Source

pub fn decode_from_slice<M: Message>( &self, data: &[u8], ) -> Result<M, DecodeError>

Decode a message from a byte slice.

Source

pub fn decode_length_delimited<M: Message>( &self, buf: &mut impl Buf, ) -> Result<M, DecodeError>

Decode a length-delimited message from a buffer.

Source

pub fn merge<M: Message>( &self, msg: &mut M, buf: &mut impl Buf, ) -> Result<(), DecodeError>

Merge fields from a buffer into an existing message.

Source

pub fn merge_from_slice<M: Message>( &self, msg: &mut M, data: &[u8], ) -> Result<(), DecodeError>

Merge fields from a byte slice into an existing message.

Source

pub fn decode_view<'a, V: MessageView<'a>>( &self, buf: &'a [u8], ) -> Result<V, DecodeError>

Decode a zero-copy view from a byte slice.

Enforces max_message_size on the input, and passes the recursion limit and unknown-field limit to the view decoder (views charge the unknown-field limit per field, including fields nested in unknown groups — see with_unknown_field_limit).

§Errors

Returns DecodeError::MessageTooLarge for oversized input, or any error from the view decoder (malformed wire data, recursion limit, unknown-field limit).

Source

pub fn decode_lazy_view<'a, L: LazyMessageView<'a>>( &self, buf: &'a [u8], ) -> Result<L, DecodeError>

Decode a lazy view from a byte slice (see LazyMessageView).

The budgets remaining at each deferred field’s position are recorded and charged when that field is accessed, so the configured limits flow through deferred decoding. Unlike decode_view, the unknown-field limit is not enforced globally across the message tree at decode time: each deferred subtree independently replays the allowance recorded at its position, so a full traversal can materialize unknown-field records proportional to input size. Prefer decode_view for untrusted input if the global bound matters.

§Errors

Returns DecodeError::MessageTooLarge for oversized input, or any error from decoding the message’s own fields — including DecodeError::RecursionLimitExceeded / DecodeError::UnknownFieldLimitExceeded when the configured limits are exhausted by them. Deferred sub-message bytes surface errors on access instead.

Source

pub fn decode_reader<M: Message>( &self, reader: &mut impl Read, ) -> Result<M, Error>

Available on crate feature std only.

Decode a message by reading all bytes from a std::io::Read source.

Reads until EOF, enforces the configured reader size limit unless without_reader_size_limit was selected, then decodes the buffered bytes. Returns std::io::Error to be compatible with Read-based error handling.

Source

pub fn decode_length_delimited_reader<M: Message>( &self, reader: &mut impl Read, ) -> Result<M, Error>

Available on crate feature std only.

Decode a length-delimited message from a std::io::Read source.

Reads a varint length prefix, enforces max_message_size, reads exactly that many bytes, then decodes. Useful for reading sequential length-delimited messages from a file or stream.

The declared length is treated as untrusted: the read buffer grows as bytes actually arrive rather than being allocated up front, so a source that declares a large length but never delivers the bytes cannot force a large allocation.

Trait Implementations§

Source§

impl Clone for DecodeOptions

Source§

fn clone(&self) -> DecodeOptions

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DecodeOptions

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for DecodeOptions

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.