pub trait Message:
DefaultInstance
+ Clone
+ PartialEq
+ Send
+ Sync {
Show 18 methods
// Required methods
fn compute_size(&self, cache: &mut SizeCache) -> u32;
fn write_to(&self, cache: &mut SizeCache, buf: &mut impl BufMut);
fn merge_field(
&mut self,
tag: Tag,
buf: &mut impl Buf,
depth: u32,
) -> Result<(), DecodeError>;
fn clear(&mut self);
// Provided methods
fn encode(&self, buf: &mut impl BufMut) { ... }
fn encode_with_cache(&self, cache: &mut SizeCache, buf: &mut impl BufMut) { ... }
fn encoded_len(&self) -> u32 { ... }
fn encode_length_delimited(&self, buf: &mut impl BufMut) { ... }
fn encode_to_vec(&self) -> Vec<u8> ⓘ { ... }
fn encode_to_bytes(&self) -> Bytes { ... }
fn decode(buf: &mut impl Buf) -> Result<Self, DecodeError>
where Self: Sized { ... }
fn decode_from_slice(data: &[u8]) -> Result<Self, DecodeError>
where Self: Sized { ... }
fn decode_length_delimited(buf: &mut impl Buf) -> Result<Self, DecodeError>
where Self: Sized { ... }
fn merge_to_limit(
&mut self,
buf: &mut impl Buf,
depth: u32,
limit: usize,
) -> Result<(), DecodeError> { ... }
fn merge_group(
&mut self,
buf: &mut impl Buf,
depth: u32,
field_number: u32,
) -> Result<(), DecodeError> { ... }
fn merge(
&mut self,
buf: &mut impl Buf,
depth: u32,
) -> Result<(), DecodeError> { ... }
fn merge_from_slice(&mut self, data: &[u8]) -> Result<(), DecodeError> { ... }
fn merge_length_delimited(
&mut self,
buf: &mut impl Buf,
depth: u32,
) -> Result<(), DecodeError> { ... }
}Expand description
The core trait implemented by all protobuf message types.
This trait is implemented by generated code — you write a .proto file,
codegen emits the Rust struct and its Message impl. You should almost
never implement this trait by hand.
§Manual implementation is discouraged
The only reason to implement Message yourself is when you need a
custom in-memory representation that codegen cannot produce — for
example, wrapping a std::ops::Range<i64> as a leaf message so the
rest of your code uses the natural Rust type. If you just want a message
type, write a .proto file instead.
Manual implementation is intentionally high-friction:
- You must correctly implement the two-pass serialization contract
(
compute_sizepopulates theSizeCachein the same traversal order thatwrite_toconsumes it). - You must implement wire-format decoding in
merge_field. - You must implement the
DefaultInstancesupertrait, which provides the lazily-initialized static default thatMessageFielddereferences to when unset.
If you still need to do this, see the custom types section of the user guide for a complete worked example.
§Serialization model
Serialization is a two-pass process to avoid the exponential-time problem that affects prost with deeply nested messages:
compute_size()— walks the message tree and records the encoded size of every length-delimited sub-message in aSizeCache.write_to()— walks the tree again, writing bytes and consuming cached sizes for length-prefixed sub-messages.
The provided encode method performs both passes with a
fresh SizeCache — most callers use that and never touch the cache
directly. compute_size / write_to take the cache explicitly so that
manual Message implementations can thread it through nested-message
recursion.
§Thread safety
Message requires Send + Sync. Generated structs contain no interior
mutability — serialization state lives in the external SizeCache, not
in the message — so messages can be placed in an Arc and shared across
threads freely. merge requires &mut self, so mutation is exclusive.
Required Methods§
Sourcefn compute_size(&self, cache: &mut SizeCache) -> u32
fn compute_size(&self, cache: &mut SizeCache) -> u32
Compute the encoded byte size of this message, recording nested
sub-message sizes in cache for write_to to consume.
Most callers should use encode instead, which runs
both passes with a fresh cache. Manual Message implementations call
this recursively on nested message fields, wrapping each call in
SizeCache::reserve / SizeCache::set for length-delimited
fields — see the user guide’s custom-types section for the pattern.
§Size limit
The protobuf specification limits messages to 2 GiB. The return type
is u32, so messages whose encoded size exceeds u32::MAX (4 GiB)
will produce a wrapped (undefined) size and a truncated encoding.
Stay well within the 2 GiB spec limit.
Sourcefn write_to(&self, cache: &mut SizeCache, buf: &mut impl BufMut)
fn write_to(&self, cache: &mut SizeCache, buf: &mut impl BufMut)
Write this message’s encoded bytes to a buffer, consuming
nested-message sizes from cache (populated by a prior
compute_size call on the same cache).
Most callers should use encode instead.
Sourcefn merge_field(
&mut self,
tag: Tag,
buf: &mut impl Buf,
depth: u32,
) -> Result<(), DecodeError>
fn merge_field( &mut self, tag: Tag, buf: &mut impl Buf, depth: u32, ) -> Result<(), DecodeError>
Processes a single already-decoded tag and its associated field data
from buf.
This is the per-field dispatch method generated for each message type.
Both merge_to_limit and
merge_group call this in their respective loops.
depth is the remaining nesting budget.
§Errors
Returns a DecodeError if:
- the buffer is truncated or malformed,
- a wire-type mismatch is detected for a known field, or
- the recursion limit is exceeded.
Provided Methods§
Sourcefn encode(&self, buf: &mut impl BufMut)
fn encode(&self, buf: &mut impl BufMut)
Compute size, then write. This is the primary encoding API.
Sourcefn encode_with_cache(&self, cache: &mut SizeCache, buf: &mut impl BufMut)
fn encode_with_cache(&self, cache: &mut SizeCache, buf: &mut impl BufMut)
Encode using a caller-supplied SizeCache, for
reuse across many encodes in a hot loop. Clears the cache first.
Sourcefn encoded_len(&self) -> u32
fn encoded_len(&self) -> u32
Compute the encoded byte size of this message.
Walks the message tree, discarding the intermediate SizeCache.
If you also intend to encode, prefer encode or
encode_to_vec — they do a single size pass
and reuse the cache for the write.
Sourcefn encode_length_delimited(&self, buf: &mut impl BufMut)
fn encode_length_delimited(&self, buf: &mut impl BufMut)
Encode this message as a length-delimited byte sequence.
Sourcefn encode_to_vec(&self) -> Vec<u8> ⓘ
fn encode_to_vec(&self) -> Vec<u8> ⓘ
Encode this message to a new Vec<u8>.
Sourcefn encode_to_bytes(&self) -> Bytes
fn encode_to_bytes(&self) -> Bytes
Encode this message to a new bytes::Bytes.
Useful when handing off to networking code (hyper, tonic, axum)
that expects Bytes frame or body payloads. Works in no_std.
This is equivalent to Bytes::from(self.encode_to_vec()) — both
are zero-copy with respect to the encoded bytes — but saves readers
from having to know that From<Vec<u8>> for Bytes is zero-copy.
Sourcefn decode(buf: &mut impl Buf) -> Result<Self, DecodeError>where
Self: Sized,
fn decode(buf: &mut impl Buf) -> Result<Self, DecodeError>where
Self: Sized,
Decode a message from a buffer.
Sourcefn decode_from_slice(data: &[u8]) -> Result<Self, DecodeError>where
Self: Sized,
fn decode_from_slice(data: &[u8]) -> Result<Self, DecodeError>where
Self: Sized,
Decode a message from a byte slice.
Convenience wrapper around decode that avoids the
&mut bytes.as_slice() incantation.
Sourcefn decode_length_delimited(buf: &mut impl Buf) -> Result<Self, DecodeError>where
Self: Sized,
fn decode_length_delimited(buf: &mut impl Buf) -> Result<Self, DecodeError>where
Self: Sized,
Decode a length-delimited message from a buffer.
This is a top-level entry point. It reads a varint length prefix,
then decodes using arithmetic bounds checking, calling
merge_to_limit with a fresh
RECURSION_LIMIT budget. Any sub-messages inside are decoded via
merge_length_delimited, which tracks
and decrements the budget.
Do not call this method from within a
merge_to_limit implementation to decode a
nested sub-message field; use
merge_length_delimited instead so
that the caller’s depth budget is propagated correctly.
Sourcefn merge_to_limit(
&mut self,
buf: &mut impl Buf,
depth: u32,
limit: usize,
) -> Result<(), DecodeError>
fn merge_to_limit( &mut self, buf: &mut impl Buf, depth: u32, limit: usize, ) -> Result<(), DecodeError>
Merge fields from a buffer until buf.remaining() reaches limit.
This is the core decode loop. merge delegates to this
with limit = 0 (read until exhausted).
merge_length_delimited computes
limit from the declared sub-message length and calls this directly.
The caller must ensure limit <= buf.remaining(). The default
implementations of merge and
merge_length_delimited uphold this
invariant.
depth is the remaining nesting budget. Each call to
merge_length_delimited decrements it
by one before recursing; when it reaches zero the call returns
DecodeError::RecursionLimitExceeded.
Sourcefn merge_group(
&mut self,
buf: &mut impl Buf,
depth: u32,
field_number: u32,
) -> Result<(), DecodeError>
fn merge_group( &mut self, buf: &mut impl Buf, depth: u32, field_number: u32, ) -> Result<(), DecodeError>
Merges a group-encoded message from buf, reading fields until an
EndGroup tag with the given field_number is encountered.
Proto2 groups use StartGroup/EndGroup wire types instead of length-delimited encoding. The opening StartGroup tag has already been consumed by the caller; this method reads the group body and the closing EndGroup tag.
§Errors
Returns a DecodeError if:
- the buffer is truncated before the EndGroup tag,
- an EndGroup tag is encountered with a mismatched field number,
- a wire-type mismatch is detected for a known field, or
- the recursion limit is exceeded.
Sourcefn merge(&mut self, buf: &mut impl Buf, depth: u32) -> Result<(), DecodeError>
fn merge(&mut self, buf: &mut impl Buf, depth: u32) -> Result<(), DecodeError>
Merge fields from a buffer into this message.
Fields that are already set will be overwritten for singular fields, or appended for repeated fields, following standard protobuf merge semantics.
depth is the remaining nesting budget. Each call to
merge_length_delimited decrements it
by one before recursing; when it reaches zero the call returns
DecodeError::RecursionLimitExceeded. Pass RECURSION_LIMIT at
the outermost call site, or use the convenience methods
(decode, merge_from_slice)
which do this automatically.
Sourcefn merge_from_slice(&mut self, data: &[u8]) -> Result<(), DecodeError>
fn merge_from_slice(&mut self, data: &[u8]) -> Result<(), DecodeError>
Merge fields from a byte slice into this message.
Convenience wrapper around merge that avoids the
&mut bytes.as_slice() incantation.
Sourcefn merge_length_delimited(
&mut self,
buf: &mut impl Buf,
depth: u32,
) -> Result<(), DecodeError>
fn merge_length_delimited( &mut self, buf: &mut impl Buf, depth: u32, ) -> Result<(), DecodeError>
Merge fields from a length-delimited sub-message payload into this message.
Reads a varint length prefix, then calls merge_to_limit
with an arithmetic bound derived from the declared sub-message length.
The buffer type B passes through unchanged at every recursion level,
avoiding the E0275 trait-solver recursion limit that occurs with
Take<&mut Take<&mut T>> type growth.
Used by generated code when decoding singular MessageField<T> fields
— the sub-message is merged into the existing value rather than
replaced, per protobuf merge semantics.
depth is the remaining nesting budget passed down from the enclosing
merge_to_limit call. This method decrements
it by one before calling the inner merge_to_limit; when it reaches
zero it returns DecodeError::RecursionLimitExceeded.
Enforces the same 2 GiB safety limit as decode_length_delimited.
§Errors
Returns an error if the buffer is too short, if the declared length
exceeds 2 GiB, if the recursion limit is reached, or if the inner
merge_to_limit call fails.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".