use alloc::collections::BTreeMap; use alloc::format; use alloc::string::String; use alloc::vec::Vec; use core::cmp::min; use core::convert::TryFrom; use core::mem; use core::str; use core::u32; use core::usize;
use ::bytes::{Buf, BufMut, Bytes};
usecrate::DecodeError; usecrate::Message;
/// Encodes an integer value into LEB128 variable length format, and writes it to the buffer. /// The buffer must have enough remaining space (maximum 10 bytes). #[inline] pubfn encode_varint<B>(mut value: u64, buf: &mut B) where
B: BufMut,
{ loop { if value < 0x80 {
buf.put_u8(value as u8); break;
} else {
buf.put_u8(((value & 0x7F) | 0x80) as u8);
value >>= 7;
}
}
}
/// Decodes a LEB128-encoded variable length integer from the buffer. #[inline] pubfn decode_varint<B>(buf: &mut B) -> Result<u64, DecodeError> where
B: Buf,
{ let bytes = buf.chunk(); let len = bytes.len(); if len == 0 { return Err(DecodeError::new("invalid varint"));
}
let byte = bytes[0]; if byte < 0x80 {
buf.advance(1);
Ok(u64::from(byte))
} elseif len > 10 || bytes[len - 1] < 0x80 { let (value, advance) = decode_varint_slice(bytes)?;
buf.advance(advance);
Ok(value)
} else {
decode_varint_slow(buf)
}
}
/// Decodes a LEB128-encoded variable length integer from the slice, returning the value and the /// number of bytes read. /// /// Based loosely on [`ReadVarint64FromArray`][1] with a varint overflow check from /// [`ConsumeVarint`][2]. /// /// ## Safety /// /// The caller must ensure that `bytes` is non-empty and either `bytes.len() >= 10` or the last /// element in bytes is < `0x80`. /// /// [1]: https://github.com/google/protobuf/blob/3.3.x/src/google/protobuf/io/coded_stream.cc#L365-L406 /// [2]: https://github.com/protocolbuffers/protobuf-go/blob/v1.27.1/encoding/protowire/wire.go#L358 #[inline] fn decode_varint_slice(bytes: &[u8]) -> Result<(u64, usize), DecodeError> { // Fully unrolled varint decoding loop. Splitting into 32-bit pieces gives better performance.
// Use assertions to ensure memory safety, but it should always be optimized after inline.
assert!(!bytes.is_empty());
assert!(bytes.len() > 10 || bytes[bytes.len() - 1] < 0x80);
letmut b: u8 = unsafe { *bytes.get_unchecked(0) }; letmut part0: u32 = u32::from(b); if b < 0x80 { return Ok((u64::from(part0), 1));
};
part0 -= 0x80;
b = unsafe { *bytes.get_unchecked(1) };
part0 += u32::from(b) << 7; if b < 0x80 { return Ok((u64::from(part0), 2));
};
part0 -= 0x80 << 7;
b = unsafe { *bytes.get_unchecked(2) };
part0 += u32::from(b) << 14; if b < 0x80 { return Ok((u64::from(part0), 3));
};
part0 -= 0x80 << 14;
b = unsafe { *bytes.get_unchecked(3) };
part0 += u32::from(b) << 21; if b < 0x80 { return Ok((u64::from(part0), 4));
};
part0 -= 0x80 << 21; let value = u64::from(part0);
b = unsafe { *bytes.get_unchecked(4) }; letmut part1: u32 = u32::from(b); if b < 0x80 { return Ok((value + (u64::from(part1) << 28), 5));
};
part1 -= 0x80;
b = unsafe { *bytes.get_unchecked(5) };
part1 += u32::from(b) << 7; if b < 0x80 { return Ok((value + (u64::from(part1) << 28), 6));
};
part1 -= 0x80 << 7;
b = unsafe { *bytes.get_unchecked(6) };
part1 += u32::from(b) << 14; if b < 0x80 { return Ok((value + (u64::from(part1) << 28), 7));
};
part1 -= 0x80 << 14;
b = unsafe { *bytes.get_unchecked(7) };
part1 += u32::from(b) << 21; if b < 0x80 { return Ok((value + (u64::from(part1) << 28), 8));
};
part1 -= 0x80 << 21; let value = value + ((u64::from(part1)) << 28);
b = unsafe { *bytes.get_unchecked(8) }; letmut part2: u32 = u32::from(b); if b < 0x80 { return Ok((value + (u64::from(part2) << 56), 9));
};
part2 -= 0x80;
b = unsafe { *bytes.get_unchecked(9) };
part2 += u32::from(b) << 7; // Check for u64::MAX overflow. See [`ConsumeVarint`][1] for details. // [1]: https://github.com/protocolbuffers/protobuf-go/blob/v1.27.1/encoding/protowire/wire.go#L358 if b < 0x02 { return Ok((value + (u64::from(part2) << 56), 10));
};
// We have overrun the maximum size of a varint (10 bytes) or the final byte caused an overflow. // Assume the data is corrupt.
Err(DecodeError::new("invalid varint"))
}
/// Decodes a LEB128-encoded variable length integer from the buffer, advancing the buffer as /// necessary. /// /// Contains a varint overflow check from [`ConsumeVarint`][1]. /// /// [1]: https://github.com/protocolbuffers/protobuf-go/blob/v1.27.1/encoding/protowire/wire.go#L358 #[inline(never)] #[cold] fn decode_varint_slow<B>(buf: &mut B) -> Result<u64, DecodeError> where
B: Buf,
{ letmut value = 0; for count in0..min(10, buf.remaining()) { let byte = buf.get_u8();
value |= u64::from(byte & 0x7F) << (count * 7); if byte <= 0x7F { // Check for u64::MAX overflow. See [`ConsumeVarint`][1] for details. // [1]: https://github.com/protocolbuffers/protobuf-go/blob/v1.27.1/encoding/protowire/wire.go#L358 if count == 9 && byte >= 0x02 { return Err(DecodeError::new("invalid varint"));
} else { return Ok(value);
}
}
}
Err(DecodeError::new("invalid varint"))
}
/// Additional information passed to every decode/merge function. /// /// The context should be passed by value and can be freely cloned. When passing /// to a function which is decoding a nested object, then use `enter_recursion`. #[derive(Clone, Debug)] #[cfg_attr(feature = "no-recursion-limit", derive(Default))] pubstruct DecodeContext { /// How many times we can recurse in the current decode stack before we hit /// the recursion limit. /// /// The recursion limit is defined by `RECURSION_LIMIT` and cannot be /// customized. The recursion limit can be ignored by building the Prost /// crate with the `no-recursion-limit` feature. #[cfg(not(feature = "no-recursion-limit"))]
recurse_count: u32,
}
impl DecodeContext { /// Call this function before recursively decoding. /// /// There is no `exit` function since this function creates a new `DecodeContext` /// to be used at the next level of recursion. Continue to use the old context // at the previous level of recursion. #[cfg(not(feature = "no-recursion-limit"))] #[inline] pub(crate) fn enter_recursion(&self) -> DecodeContext {
DecodeContext {
recurse_count: self.recurse_count - 1,
}
}
/// Checks whether the recursion limit has been reached in the stack of /// decodes described by the `DecodeContext` at `self.ctx`. /// /// Returns `Ok<()>` if it is ok to continue recursing. /// Returns `Err<DecodeError>` if the recursion limit has been reached. #[cfg(not(feature = "no-recursion-limit"))] #[inline] pub(crate) fn limit_reached(&self) -> Result<(), DecodeError> { ifself.recurse_count == 0 {
Err(DecodeError::new("recursion limit reached"))
} else {
Ok(())
}
}
#[cfg(feature = "no-recursion-limit")] #[inline] #[allow(clippy::unnecessary_wraps)] // needed in other features pub(crate) fn limit_reached(&self) -> Result<(), DecodeError> {
Ok(())
}
}
/// Returns the encoded length of the value in LEB128 variable length format. /// The returned value will be between 1 and 10, inclusive. #[inline] pubfn encoded_len_varint(value: u64) -> usize { // Based on [VarintSize64][1]. // [1]: https://github.com/google/protobuf/blob/3.3.x/src/google/protobuf/io/coded_stream.h#L1301-L1309
((((value | 1).leading_zeros() ^ 63) * 9 + 73) / 64) as usize
}
/// Encodes a Protobuf field key, which consists of a wire type designator and /// the field tag. #[inline] pubfn encode_key<B>(tag: u32, wire_type: WireType, buf: &mut B) where
B: BufMut,
{
debug_assert!((MIN_TAG..=MAX_TAG).contains(&tag)); let key = (tag << 3) | wire_type as u32;
encode_varint(u64::from(key), buf);
}
/// Decodes a Protobuf field key, which consists of a wire type designator and /// the field tag. #[inline(always)] pubfn decode_key<B>(buf: &mut B) -> Result<(u32, WireType), DecodeError> where
B: Buf,
{ let key = decode_varint(buf)?; if key > u64::from(u32::MAX) { return Err(DecodeError::new(format!("invalid key value: {}", key)));
} let wire_type = WireType::try_from(key & 0x07)?; let tag = key as u32 >> 3;
if tag < MIN_TAG { return Err(DecodeError::new("invalid tag value: 0"));
}
Ok((tag, wire_type))
}
/// Returns the width of an encoded Protobuf field key with the given tag. /// The returned width will be between 1 and 5 bytes (inclusive). #[inline] pubfn key_len(tag: u32) -> usize {
encoded_len_varint(u64::from(tag << 3))
}
/// Checks that the expected wire type matches the actual wire type, /// or returns an error result. #[inline] pubfn check_wire_type(expected: WireType, actual: WireType) -> Result<(), DecodeError> { if expected != actual { return Err(DecodeError::new(format!( "invalid wire type: {:?} (expected {:?})",
actual, expected
)));
}
Ok(())
}
/// Helper function which abstracts reading a length delimiter prefix followed /// by decoding values until the length of bytes is exhausted. pubfn merge_loop<T, M, B>(
value: &mut T,
buf: &mut B,
ctx: DecodeContext, mut merge: M,
) -> Result<(), DecodeError> where
M: FnMut(&mut T, &mut B, DecodeContext) -> Result<(), DecodeError>,
B: Buf,
{ let len = decode_varint(buf)?; let remaining = buf.remaining(); if len > remaining as u64 { return Err(DecodeError::new("buffer underflow"));
}
let limit = remaining - len as usize; while buf.remaining() > limit {
merge(value, buf, ctx.clone())?;
}
pubfn skip_field<B>(
wire_type: WireType,
tag: u32,
buf: &mut B,
ctx: DecodeContext,
) -> Result<(), DecodeError> where
B: Buf,
{
ctx.limit_reached()?; let len = match wire_type {
WireType::Varint => decode_varint(buf).map(|_| 0)?,
WireType::ThirtyTwoBit => 4,
WireType::SixtyFourBit => 8,
WireType::LengthDelimited => decode_varint(buf)?,
WireType::StartGroup => loop { let (inner_tag, inner_wire_type) = decode_key(buf)?; match inner_wire_type {
WireType::EndGroup => { if inner_tag != tag { return Err(DecodeError::new("unexpected end group tag"));
} break0;
}
_ => skip_field(inner_wire_type, inner_tag, buf, ctx.enter_recursion())?,
}
},
WireType::EndGroup => return Err(DecodeError::new("unexpected end group tag")),
};
if len > buf.remaining() as u64 { return Err(DecodeError::new("buffer underflow"));
}
buf.advance(len as usize);
Ok(())
}
/// Helper macro which emits an `encode_repeated` function for the type.
macro_rules! encode_repeated {
($ty:ty) => { pubfn encode_repeated<B>(tag: u32, values: &[$ty], buf: &mut B) where
B: BufMut,
{ for value in values {
encode(tag, value, buf);
}
}
};
}
/// Helper macro which emits a `merge_repeated` function for the numeric type.
macro_rules! merge_repeated_numeric {
($ty:ty,
$wire_type:expr,
$merge:ident,
$merge_repeated:ident) => { pubfn $merge_repeated<B>(
wire_type: WireType,
values: &mut Vec<$ty>,
buf: &mut B,
ctx: DecodeContext,
) -> Result<(), DecodeError> where
B: Buf,
{ if wire_type == WireType::LengthDelimited { // Packed.
merge_loop(values, buf, ctx, |values, buf, ctx| { letmut value = Default::default();
$merge($wire_type, &mut value, buf, ctx)?;
values.push(value);
Ok(())
})
} else { // Unpacked.
check_wire_type($wire_type, wire_type)?; letmut value = Default::default();
$merge(wire_type, &mut value, buf, ctx)?;
values.push(value);
Ok(())
}
}
};
}
/// Macro which emits a module containing a set of encoding functions for a /// variable width numeric type.
macro_rules! varint {
($ty:ty,
$proto_ty:ident) => (
varint!($ty,
$proto_ty,
to_uint64(value) { *value as u64 },
from_uint64(value) { value as $ty });
);
proptest! { #[test] fn check(value: $ty, tag in MIN_TAG..=MAX_TAG) {
check_type(value, tag, WireType::Varint,
encode, merge, encoded_len)?;
} #[test] fn check_repeated(value: Vec<$ty>, tag in MIN_TAG..=MAX_TAG) {
check_collection_type(value, tag, WireType::Varint,
encode_repeated, merge_repeated,
encoded_len_repeated)?;
} #[test] fn check_packed(value: Vec<$ty>, tag in MIN_TAG..=MAX_TAG) {
check_type(value, tag, WireType::LengthDelimited,
encode_packed, merge_repeated,
encoded_len_packed)?;
}
}
}
}
);
}
varint!(bool, bool,
to_uint64(value) u64::from(*value),
from_uint64(value) value != 0);
varint!(i32, int32);
varint!(i64, int64);
varint!(u32, uint32);
varint!(u64, uint64);
varint!(i32, sint32,
to_uint64(value) {
((value << 1) ^ (value >> 31)) as u32 as u64
},
from_uint64(value) { let value = value as u32;
((value >> 1) as i32) ^ (-((value & 1) as i32))
});
varint!(i64, sint64,
to_uint64(value) {
((value << 1) ^ (value >> 63)) as u64
},
from_uint64(value) {
((value >> 1) as i64) ^ (-((value & 1) as i64))
});
/// Macro which emits a module containing a set of encoding functions for a /// fixed width numeric type.
macro_rules! fixed_width {
($ty:ty,
$width:expr,
$wire_type:expr,
$proto_ty:ident,
$put:ident,
$get:ident) => { pubmod $proto_ty { usecrate::encoding::*;
pubfn encode<B>(tag: u32, value: &$ty, buf: &mut B) where
B: BufMut,
{
encode_key(tag, $wire_type, buf);
buf.$put(*value);
}
pubfn encode<B>(tag: u32, value: &String, buf: &mut B) where
B: BufMut,
{
encode_key(tag, WireType::LengthDelimited, buf);
encode_varint(value.len() as u64, buf);
buf.put_slice(value.as_bytes());
} pubfn merge<B>(
wire_type: WireType,
value: &mut String,
buf: &mut B,
ctx: DecodeContext,
) -> Result<(), DecodeError> where
B: Buf,
{ // ## Unsafety // // `string::merge` reuses `bytes::merge`, with an additional check of utf-8 // well-formedness. If the utf-8 is not well-formed, or if any other error occurs, then the // string is cleared, so as to avoid leaking a string field with invalid data. // // This implementation uses the unsafe `String::as_mut_vec` method instead of the safe // alternative of temporarily swapping an empty `String` into the field, because it results // in up to 10% better performance on the protobuf message decoding benchmarks. // // It's required when using `String::as_mut_vec` that invalid utf-8 data not be leaked into // the backing `String`. To enforce this, even in the event of a panic in `bytes::merge` or // in the buf implementation, a drop guard is used. unsafe { struct DropGuard<'a>(&'a mut Vec<u8>); impl<'a> Drop for DropGuard<'a> { #[inline] fn drop(&mutself) { self.0.clear();
}
}
let drop_guard = DropGuard(value.as_mut_vec());
bytes::merge_one_copy(wire_type, drop_guard.0, buf, ctx)?; match str::from_utf8(drop_guard.0) {
Ok(_) => { // Success; do not clear the bytes.
mem::forget(drop_guard);
Ok(())
}
Err(_) => Err(DecodeError::new( "invalid string value: data is not UTF-8 encoded",
)),
}
}
}
fn replace_with<B>(&mutself, buf: B) where
B: Buf,
{ self.clear(); self.reserve(buf.remaining()); self.put(buf);
}
fn append_to<B>(&self, buf: &mut B) where
B: BufMut,
{
buf.put(self.as_slice())
}
}
pubmod bytes { usesuper::*;
pubfn encode<A, B>(tag: u32, value: &A, buf: &mut B) where
A: BytesAdapter,
B: BufMut,
{
encode_key(tag, WireType::LengthDelimited, buf);
encode_varint(value.len() as u64, buf);
value.append_to(buf);
}
pubfn merge<A, B>(
wire_type: WireType,
value: &mut A,
buf: &mut B,
_ctx: DecodeContext,
) -> Result<(), DecodeError> where
A: BytesAdapter,
B: Buf,
{
check_wire_type(WireType::LengthDelimited, wire_type)?; let len = decode_varint(buf)?; if len > buf.remaining() as u64 { return Err(DecodeError::new("buffer underflow"));
} let len = len as usize;
// Clear the existing value. This follows from the following rule in the encoding guide[1]: // // > Normally, an encoded message would never have more than one instance of a non-repeated // > field. However, parsers are expected to handle the case in which they do. For numeric // > types and strings, if the same field appears multiple times, the parser accepts the // > last value it sees. // // [1]: https://developers.google.com/protocol-buffers/docs/encoding#optional // // This is intended for A and B both being Bytes so it is zero-copy. // Some combinations of A and B types may cause a double-copy, // in which case merge_one_copy() should be used instead.
value.replace_with(buf.copy_to_bytes(len));
Ok(())
}
pub(super) fn merge_one_copy<A, B>(
wire_type: WireType,
value: &mut A,
buf: &mut B,
_ctx: DecodeContext,
) -> Result<(), DecodeError> where
A: BytesAdapter,
B: Buf,
{
check_wire_type(WireType::LengthDelimited, wire_type)?; let len = decode_varint(buf)?; if len > buf.remaining() as u64 { return Err(DecodeError::new("buffer underflow"));
} let len = len as usize;
// If we must copy, make sure to copy only once.
value.replace_with(buf.take(len));
Ok(())
}
proptest! { #[test] fn check_vec(value: Vec<u8>, tag in MIN_TAG..=MAX_TAG) { super::test::check_type::<Vec<u8>, Vec<u8>>(value, tag, WireType::LengthDelimited,
encode, merge, encoded_len)?;
}
#[test] fn check_bytes(value: Vec<u8>, tag in MIN_TAG..=MAX_TAG) { let value = Bytes::from(value); super::test::check_type::<Bytes, Bytes>(value, tag, WireType::LengthDelimited,
encode, merge, encoded_len)?;
}
#[test] fn check_repeated_vec(value: Vec<Vec<u8>>, tag in MIN_TAG..=MAX_TAG) { super::test::check_collection_type(value, tag, WireType::LengthDelimited,
encode_repeated, merge_repeated,
encoded_len_repeated)?;
}
#[test] fn check_repeated_bytes(value: Vec<Vec<u8>>, tag in MIN_TAG..=MAX_TAG) { let value = value.into_iter().map(Bytes::from).collect(); super::test::check_collection_type(value, tag, WireType::LengthDelimited,
encode_repeated, merge_repeated,
encoded_len_repeated)?;
}
}
}
}
pubmod message { usesuper::*;
pubfn encode<M, B>(tag: u32, msg: &M, buf: &mut B) where
M: Message,
B: BufMut,
{
encode_key(tag, WireType::LengthDelimited, buf);
encode_varint(msg.encoded_len() as u64, buf);
msg.encode_raw(buf);
}
#[inline] pubfn encoded_len<M>(tag: u32, msg: &M) -> usize where
M: Message,
{ let len = msg.encoded_len();
key_len(tag) + encoded_len_varint(len as u64) + len
}
#[inline] pubfn encoded_len_repeated<M>(tag: u32, messages: &[M]) -> usize where
M: Message,
{
key_len(tag) * messages.len()
+ messages
.iter()
.map(Message::encoded_len)
.map(|len| len + encoded_len_varint(len as u64))
.sum::<usize>()
}
}
ctx.limit_reached()?; loop { let (field_tag, field_wire_type) = decode_key(buf)?; if field_wire_type == WireType::EndGroup { if field_tag != tag { return Err(DecodeError::new("unexpected end group tag"));
} return Ok(());
}
/// Rust doesn't have a `Map` trait, so macros are currently the best way to be /// generic over `HashMap` and `BTreeMap`.
macro_rules! map {
($map_ty:ident) => { usecrate::encoding::*; use core::hash::Hash;
/// Generic protobuf map encode function with an overridden value default. /// /// This is necessary because enumeration values can have a default value other /// than 0 in proto2. pubfn encode_with_default<K, V, B, KE, KL, VE, VL>(
key_encode: KE,
key_encoded_len: KL,
val_encode: VE,
val_encoded_len: VL,
val_default: &V,
tag: u32,
values: &$map_ty<K, V>,
buf: &mut B,
) where
K: Default + Eq + Hash + Ord,
V: PartialEq,
B: BufMut,
KE: Fn(u32, &K, &mut B),
KL: Fn(u32, &K) -> usize,
VE: Fn(u32, &V, &mut B),
VL: Fn(u32, &V) -> usize,
{ for (key, val) in values.iter() { let skip_key = key == &K::default(); let skip_val = val == val_default;
#[test] fn string_merge_invalid_utf8() { letmut s = String::new(); let buf = b"\x02\x80\x80";
let r = string::merge(
WireType::LengthDelimited,
&mut s,
&mut &buf[..],
DecodeContext::default(),
);
r.expect_err("must be an error");
assert!(s.is_empty());
}
/// This big bowl o' macro soup generates an encoding property test for each combination of map /// type, scalar map key, and value type. /// TODO: these tests take a long time to compile, can this be improved? #[cfg(feature = "std")]
macro_rules! map_tests {
(keys: $keys:tt,
vals: $vals:tt) => { mod hash_map {
map_tests!(@private HashMap, hash_map, $keys, $vals);
} mod btree_map {
map_tests!(@private BTreeMap, btree_map, $keys, $vals);
}
};
(@private $map_type:ident,
$mod_name:ident,
[$(($key_ty:ty, $key_proto:ident)),*],
$vals:tt) => {
$( mod $key_proto { use std::collections::$map_type;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.42Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.