use bytes::{Buf, BufMut};
use crate::error::DecodeError;
pub const MAX_FIELD_NUMBER: u32 = (1 << 29) - 1;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
#[non_exhaustive]
pub enum WireType {
Varint = 0,
Fixed64 = 1,
LengthDelimited = 2,
StartGroup = 3,
EndGroup = 4,
Fixed32 = 5,
}
impl WireType {
pub fn from_u32(value: u32) -> Result<Self, DecodeError> {
match value {
0 => Ok(Self::Varint),
1 => Ok(Self::Fixed64),
2 => Ok(Self::LengthDelimited),
3 => Ok(Self::StartGroup),
4 => Ok(Self::EndGroup),
5 => Ok(Self::Fixed32),
_ => Err(DecodeError::InvalidWireType(value)),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Tag {
field_number: u32,
wire_type: WireType,
}
impl Tag {
pub fn new(field_number: u32, wire_type: WireType) -> Self {
assert!(
(1..=MAX_FIELD_NUMBER).contains(&field_number),
"field_number must be in [1, {MAX_FIELD_NUMBER}], got {field_number}"
);
Self {
field_number,
wire_type,
}
}
#[inline]
pub fn field_number(&self) -> u32 {
self.field_number
}
#[inline]
pub fn wire_type(&self) -> WireType {
self.wire_type
}
#[inline]
pub fn encode(&self, buf: &mut impl BufMut) {
let value = ((self.field_number as u64) << 3) | (self.wire_type as u64);
encode_varint(value, buf);
}
#[inline]
pub fn decode(buf: &mut impl Buf) -> Result<Self, DecodeError> {
let chunk = buf.chunk();
if !chunk.is_empty() && chunk[0] < 0x80 {
let b = chunk[0];
buf.advance(1);
return Self::from_raw_u32(b as u32);
}
let value = decode_varint(buf)?;
if value > u32::MAX as u64 {
return Err(DecodeError::InvalidFieldNumber);
}
Self::from_raw_u32(value as u32)
}
#[inline]
fn from_raw_u32(value: u32) -> Result<Self, DecodeError> {
let wire_type = WireType::from_u32(value & 0x07)?;
let field_number = value >> 3;
if field_number == 0 {
return Err(DecodeError::InvalidFieldNumber);
}
Ok(Self {
field_number,
wire_type,
})
}
}
#[inline]
pub fn encode_varint(mut value: u64, buf: &mut impl BufMut) {
loop {
if value < 0x80 {
buf.put_u8(value as u8);
return;
}
buf.put_u8(((value & 0x7F) | 0x80) as u8);
value >>= 7;
}
}
#[inline]
pub fn decode_varint(buf: &mut impl Buf) -> Result<u64, DecodeError> {
let chunk = buf.chunk();
let len = chunk.len();
if len == 0 {
return Err(DecodeError::UnexpectedEof);
}
let first = chunk[0];
if first < 0x80 {
buf.advance(1);
return Ok(first as u64);
}
if len > 10 || chunk[len - 1] < 0x80 {
let (value, advance) = decode_varint_slice(chunk)?;
buf.advance(advance);
Ok(value)
} else {
decode_varint_slow(buf)
}
}
#[inline]
fn decode_varint_slice(bytes: &[u8]) -> Result<(u64, usize), DecodeError> {
assert!(!bytes.is_empty());
assert!(bytes.len() > 10 || bytes[bytes.len() - 1] < 0x80);
let mut b: u8 = bytes[0];
let mut part0: u32 = u32::from(b);
if b < 0x80 {
return Ok((u64::from(part0), 1));
}
part0 -= 0x80;
b = bytes[1];
part0 += u32::from(b) << 7;
if b < 0x80 {
return Ok((u64::from(part0), 2));
}
part0 -= 0x80 << 7;
b = bytes[2];
part0 += u32::from(b) << 14;
if b < 0x80 {
return Ok((u64::from(part0), 3));
}
part0 -= 0x80 << 14;
b = bytes[3];
part0 += u32::from(b) << 21;
if b < 0x80 {
return Ok((u64::from(part0), 4));
}
part0 -= 0x80 << 21;
let value = u64::from(part0);
b = bytes[4];
let mut part1: u32 = u32::from(b);
if b < 0x80 {
return Ok((value + (u64::from(part1) << 28), 5));
}
part1 -= 0x80;
b = bytes[5];
part1 += u32::from(b) << 7;
if b < 0x80 {
return Ok((value + (u64::from(part1) << 28), 6));
}
part1 -= 0x80 << 7;
b = bytes[6];
part1 += u32::from(b) << 14;
if b < 0x80 {
return Ok((value + (u64::from(part1) << 28), 7));
}
part1 -= 0x80 << 14;
b = bytes[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 = bytes[8];
let mut part2: u32 = u32::from(b);
if b < 0x80 {
return Ok((value + (u64::from(part2) << 56), 9));
}
part2 -= 0x80;
b = bytes[9];
part2 += u32::from(b) << 7;
if b >= 0x02 {
return Err(DecodeError::VarintTooLong);
}
Ok((value + (u64::from(part2) << 56), 10))
}
#[inline(never)]
#[cold]
fn decode_varint_slow(buf: &mut impl Buf) -> Result<u64, DecodeError> {
let mut value: u64 = 0;
let mut shift: u32 = 0;
let limit = core::cmp::min(10, buf.remaining());
for _ in 0..limit {
let byte = buf.get_u8();
if shift < 63 {
value |= ((byte & 0x7F) as u64) << shift;
if byte < 0x80 {
return Ok(value);
}
shift += 7;
} else {
if byte > 0x01 {
return Err(DecodeError::VarintTooLong);
}
value |= (byte as u64) << 63;
return Ok(value);
}
}
Err(DecodeError::UnexpectedEof)
}
#[inline]
pub const fn varint_len(value: u64) -> usize {
if value == 0 {
return 1;
}
let bits = 64 - value.leading_zeros() as usize;
bits.div_ceil(7)
}
#[inline]
pub fn skip_field(tag: Tag, buf: &mut impl Buf) -> Result<(), DecodeError> {
skip_field_depth(tag, buf, crate::RECURSION_LIMIT)
}
pub fn skip_field_depth(tag: Tag, buf: &mut impl Buf, depth: u32) -> Result<(), DecodeError> {
match tag.wire_type() {
WireType::Varint => {
decode_varint(buf)?;
}
WireType::Fixed64 => {
if buf.remaining() < 8 {
return Err(DecodeError::UnexpectedEof);
}
buf.advance(8);
}
WireType::LengthDelimited => {
let len = decode_varint(buf)?;
let len = usize::try_from(len).map_err(|_| DecodeError::MessageTooLarge)?;
if buf.remaining() < len {
return Err(DecodeError::UnexpectedEof);
}
buf.advance(len);
}
WireType::Fixed32 => {
if buf.remaining() < 4 {
return Err(DecodeError::UnexpectedEof);
}
buf.advance(4);
}
WireType::StartGroup => {
let depth = depth
.checked_sub(1)
.ok_or(DecodeError::RecursionLimitExceeded)?;
loop {
let nested_tag = Tag::decode(buf)?;
if nested_tag.wire_type() == WireType::EndGroup {
if nested_tag.field_number() != tag.field_number() {
return Err(DecodeError::InvalidEndGroup(nested_tag.field_number()));
}
break;
}
skip_field_depth(nested_tag, buf, depth)?;
}
}
wt => {
return Err(DecodeError::InvalidWireType(wt as u8 as u32));
}
}
Ok(())
}
pub fn decode_unknown_field(
tag: Tag,
buf: &mut impl Buf,
depth: u32,
) -> Result<crate::unknown_fields::UnknownField, DecodeError> {
use crate::unknown_fields::{UnknownField, UnknownFieldData, UnknownFields};
let data = match tag.wire_type() {
WireType::Varint => UnknownFieldData::Varint(decode_varint(buf)?),
WireType::Fixed64 => {
if buf.remaining() < 8 {
return Err(DecodeError::UnexpectedEof);
}
UnknownFieldData::Fixed64(buf.get_u64_le())
}
WireType::Fixed32 => {
if buf.remaining() < 4 {
return Err(DecodeError::UnexpectedEof);
}
UnknownFieldData::Fixed32(buf.get_u32_le())
}
WireType::LengthDelimited => {
let len = decode_varint(buf)?;
let len = usize::try_from(len).map_err(|_| DecodeError::MessageTooLarge)?;
if buf.remaining() < len {
return Err(DecodeError::UnexpectedEof);
}
let mut data = alloc::vec![0u8; len];
buf.copy_to_slice(&mut data);
UnknownFieldData::LengthDelimited(data)
}
WireType::StartGroup => {
let depth = depth
.checked_sub(1)
.ok_or(DecodeError::RecursionLimitExceeded)?;
let group_field_number = tag.field_number();
let mut nested = UnknownFields::new();
loop {
let nested_tag = Tag::decode(buf)?;
if nested_tag.wire_type() == WireType::EndGroup {
if nested_tag.field_number() != group_field_number {
return Err(DecodeError::InvalidEndGroup(nested_tag.field_number()));
}
break;
}
nested.push(decode_unknown_field(nested_tag, buf, depth)?);
}
UnknownFieldData::Group(nested)
}
wt => return Err(DecodeError::InvalidWireType(wt as u8 as u32)),
};
Ok(UnknownField {
number: tag.field_number(),
data,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_varint_roundtrip() {
let test_values: &[u64] = &[0, 1, 127, 128, 255, 300, 16384, u64::MAX];
for &v in test_values {
let mut buf = Vec::new();
encode_varint(v, &mut buf);
assert_eq!(buf.len(), varint_len(v), "varint_len mismatch for {v}");
let decoded = decode_varint(&mut buf.as_slice()).unwrap();
assert_eq!(v, decoded, "roundtrip failed for {v}");
}
}
#[test]
fn test_tag_roundtrip() {
let tag = Tag::new(1, WireType::Varint);
let mut buf = Vec::new();
tag.encode(&mut buf);
let decoded = Tag::decode(&mut buf.as_slice()).unwrap();
assert_eq!(tag, decoded);
}
#[test]
fn test_tag_high_field_number() {
let tag = Tag::new(MAX_FIELD_NUMBER, WireType::LengthDelimited);
let mut buf = Vec::new();
tag.encode(&mut buf);
let decoded = Tag::decode(&mut buf.as_slice()).unwrap();
assert_eq!(tag, decoded);
}
#[test]
fn test_zero_field_number_rejected() {
let mut buf = Vec::new();
encode_varint(0b0000_0000, &mut buf); let result = Tag::decode(&mut buf.as_slice());
assert!(result.is_err());
}
#[test]
fn test_oversize_field_number_rejected() {
let mut buf = Vec::new();
encode_varint(536_870_912u64 << 3, &mut buf);
assert_eq!(
Tag::decode(&mut buf.as_slice()),
Err(DecodeError::InvalidFieldNumber)
);
}
#[test]
fn test_tag_single_byte_fast_path() {
#[rustfmt::skip]
let cases: &[(u8, Option<(u32, WireType)>)] = &[
(0x08, Some((1, WireType::Varint))), (0x0A, Some((1, WireType::LengthDelimited))), (0x7D, Some((15, WireType::Fixed32))), (0x78, Some((15, WireType::Varint))), (0x00, None), (0x07, None), (0x0E, None), ];
for &(byte, expected) in cases {
let buf = [byte];
let result = Tag::decode(&mut &buf[..]);
match expected {
Some((fn_, wt)) => {
let t = result.unwrap_or_else(|e| panic!("byte {byte:#04x}: {e:?}"));
assert_eq!(t.field_number(), fn_, "byte {byte:#04x}");
assert_eq!(t.wire_type(), wt, "byte {byte:#04x}");
}
None => assert!(result.is_err(), "byte {byte:#04x} should be rejected"),
}
}
}
#[test]
fn test_tag_field_16_takes_slow_path() {
let tag = Tag::new(16, WireType::Varint);
let mut buf = Vec::new();
tag.encode(&mut buf);
assert_eq!(buf, [0x80, 0x01]); let decoded = Tag::decode(&mut buf.as_slice()).unwrap();
assert_eq!(decoded.field_number(), 16);
assert_eq!(decoded.wire_type(), WireType::Varint);
}
#[test]
fn test_varint_u64_max_roundtrip() {
let mut buf = Vec::new();
encode_varint(u64::MAX, &mut buf);
assert_eq!(buf.len(), 10);
assert_eq!(buf[9], 0x01); let decoded = decode_varint(&mut buf.as_slice()).unwrap();
assert_eq!(decoded, u64::MAX);
}
#[test]
fn test_varint_10th_byte_overflow_rejected() {
let mut buf: Vec<u8> = vec![0xFF; 9]; buf.push(0x02); assert_eq!(
decode_varint(&mut buf.as_slice()),
Err(DecodeError::VarintTooLong)
);
}
#[test]
fn test_varint_11th_byte_rejected() {
let buf: Vec<u8> = vec![0xFF; 10]; assert_eq!(
decode_varint(&mut buf.as_slice()),
Err(DecodeError::VarintTooLong)
);
}
#[test]
fn test_skip_field_varint() {
let mut buf = Vec::new();
let tag = Tag::new(1, WireType::Varint);
tag.encode(&mut buf);
encode_varint(300, &mut buf);
let mut combined = buf.clone();
let tag2 = Tag::new(2, WireType::Varint);
tag2.encode(&mut combined);
encode_varint(1, &mut combined);
let slice = &mut combined.as_slice();
let t = Tag::decode(slice).unwrap();
skip_field(t, slice).unwrap();
let t2 = Tag::decode(slice).unwrap();
assert_eq!(t2.field_number(), 2);
}
#[test]
fn test_skip_field_fixed32() {
let mut buf = Vec::new();
Tag::new(1, WireType::Fixed32).encode(&mut buf);
buf.extend_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD]);
let slice = &mut buf.as_slice();
let t = Tag::decode(slice).unwrap();
skip_field(t, slice).unwrap();
assert!(slice.is_empty());
}
#[test]
fn test_skip_field_fixed64() {
let mut buf = Vec::new();
Tag::new(1, WireType::Fixed64).encode(&mut buf);
buf.extend_from_slice(&[0u8; 8]);
let slice = &mut buf.as_slice();
let t = Tag::decode(slice).unwrap();
skip_field(t, slice).unwrap();
assert!(slice.is_empty());
}
#[test]
fn test_skip_field_length_delimited() {
let mut buf = Vec::new();
Tag::new(1, WireType::LengthDelimited).encode(&mut buf);
encode_varint(3, &mut buf); buf.extend_from_slice(&[0xAA, 0xBB, 0xCC]);
let slice = &mut buf.as_slice();
let t = Tag::decode(slice).unwrap();
skip_field(t, slice).unwrap();
assert!(slice.is_empty());
}
#[test]
fn test_skip_field_truncated_returns_error() {
let mut buf = Vec::new();
Tag::new(1, WireType::Fixed32).encode(&mut buf);
buf.extend_from_slice(&[0x01, 0x02]);
let slice = &mut buf.as_slice();
let t = Tag::decode(slice).unwrap();
assert_eq!(skip_field(t, slice), Err(DecodeError::UnexpectedEof));
}
#[test]
fn test_skip_field_start_group_empty_buf() {
let tag = Tag::new(1, WireType::StartGroup);
let mut buf: &[u8] = &[];
assert_eq!(skip_field(tag, &mut buf), Err(DecodeError::UnexpectedEof));
}
#[test]
fn test_skip_field_start_group_with_end() {
let mut data = Vec::new();
Tag::new(2, WireType::Varint).encode(&mut data);
encode_varint(42, &mut data);
Tag::new(1, WireType::EndGroup).encode(&mut data);
let tag = Tag::new(1, WireType::StartGroup);
let mut buf: &[u8] = &data;
assert_eq!(skip_field(tag, &mut buf), Ok(()));
assert!(buf.is_empty());
}
#[test]
fn test_skip_field_start_group_wrong_end() {
let mut data = Vec::new();
Tag::new(99, WireType::EndGroup).encode(&mut data);
let tag = Tag::new(1, WireType::StartGroup);
let mut buf: &[u8] = &data;
assert_eq!(
skip_field(tag, &mut buf),
Err(DecodeError::InvalidEndGroup(99))
);
}
#[test]
fn test_skip_field_end_group_returns_invalid_wire_type() {
let tag = Tag::new(1, WireType::EndGroup);
let mut buf: &[u8] = &[];
assert_eq!(
skip_field(tag, &mut buf),
Err(DecodeError::InvalidWireType(4))
);
}
fn encode_group_payload(field_number: u32, inner: &[u8]) -> Vec<u8> {
let mut buf = inner.to_vec();
Tag::new(field_number, WireType::EndGroup).encode(&mut buf);
buf
}
#[test]
fn test_decode_unknown_field_group_at_depth_1_succeeds() {
let payload = encode_group_payload(1, &[]);
let tag = Tag::new(1, WireType::StartGroup);
let result = decode_unknown_field(tag, &mut payload.as_slice(), 1);
assert!(result.is_ok());
}
#[test]
fn test_decode_unknown_field_group_at_depth_0_exceeds_limit() {
let payload = encode_group_payload(1, &[]);
let tag = Tag::new(1, WireType::StartGroup);
assert_eq!(
decode_unknown_field(tag, &mut payload.as_slice(), 0),
Err(DecodeError::RecursionLimitExceeded)
);
}
#[test]
fn test_decode_unknown_field_end_group_mismatched_field_number() {
let mut payload = Vec::new();
Tag::new(2, WireType::EndGroup).encode(&mut payload); let tag = Tag::new(1, WireType::StartGroup);
assert_eq!(
decode_unknown_field(tag, &mut payload.as_slice(), 1),
Err(DecodeError::InvalidEndGroup(2))
);
}
#[test]
fn test_decode_unknown_field_all_wire_types() {
use crate::unknown_fields::{UnknownField, UnknownFieldData};
struct Case {
tag: Tag,
payload: Vec<u8>,
expected: UnknownFieldData,
}
let cases = vec![
Case {
tag: Tag::new(1, WireType::Varint),
payload: {
let mut b = Vec::new();
encode_varint(300, &mut b);
b
},
expected: UnknownFieldData::Varint(300),
},
Case {
tag: Tag::new(2, WireType::Fixed32),
payload: 0xDEAD_BEEF_u32.to_le_bytes().to_vec(),
expected: UnknownFieldData::Fixed32(0xDEAD_BEEF),
},
Case {
tag: Tag::new(3, WireType::Fixed64),
payload: 0x1234_5678_9ABC_DEF0_u64.to_le_bytes().to_vec(),
expected: UnknownFieldData::Fixed64(0x1234_5678_9ABC_DEF0),
},
Case {
tag: Tag::new(4, WireType::LengthDelimited),
payload: {
let mut b = Vec::new();
encode_varint(3, &mut b);
b.extend_from_slice(b"abc");
b
},
expected: UnknownFieldData::LengthDelimited(b"abc".to_vec()),
},
Case {
tag: Tag::new(5, WireType::StartGroup),
payload: {
let mut inner = Vec::new();
Tag::new(1, WireType::Varint).encode(&mut inner);
encode_varint(42, &mut inner);
encode_group_payload(5, &inner)
},
expected: UnknownFieldData::Group({
let mut fields = crate::unknown_fields::UnknownFields::new();
fields.push(UnknownField {
number: 1,
data: UnknownFieldData::Varint(42),
});
fields
}),
},
];
for case in cases {
let got = decode_unknown_field(
case.tag,
&mut case.payload.as_slice(),
crate::RECURSION_LIMIT,
)
.unwrap_or_else(|e| panic!("decode failed for tag {:?}: {e}", case.tag));
assert_eq!(got.number, case.tag.field_number());
assert_eq!(got.data, case.expected, "tag {:?}", case.tag);
}
}
#[test]
fn test_decode_unknown_field_eof_rejection() {
#[rustfmt::skip]
let cases: &[(Tag, &[u8])] = &[
(Tag::new(1, WireType::Fixed32), &[0x01, 0x02, 0x03]),
(Tag::new(2, WireType::Fixed64), &[0; 7]),
(Tag::new(3, WireType::LengthDelimited), &[0x0A, 0xAA, 0xBB]),
];
for &(tag, payload) in cases {
assert_eq!(
decode_unknown_field(tag, &mut &payload[..], crate::RECURSION_LIMIT),
Err(DecodeError::UnexpectedEof),
"tag {tag:?}"
);
}
}
#[test]
fn test_decode_unknown_field_invalid_wire_type() {
let tag = Tag::new(1, WireType::EndGroup);
assert_eq!(
decode_unknown_field(tag, &mut &[][..], crate::RECURSION_LIMIT),
Err(DecodeError::InvalidWireType(4))
);
}
#[test]
fn test_decode_unknown_field_round_trip_via_unknown_fields() {
use crate::unknown_fields::{UnknownField, UnknownFieldData, UnknownFields};
let mut original = UnknownFields::new();
original.push(UnknownField {
number: 1,
data: UnknownFieldData::Varint(u64::MAX),
});
original.push(UnknownField {
number: 2,
data: UnknownFieldData::Fixed32(0xFFFF_FFFF),
});
original.push(UnknownField {
number: 3,
data: UnknownFieldData::Fixed64(0),
});
original.push(UnknownField {
number: 4,
data: UnknownFieldData::LengthDelimited(vec![]),
});
original.push(UnknownField {
number: 5,
data: UnknownFieldData::LengthDelimited(vec![0xFF; 200]),
});
let mut buf = Vec::new();
original.write_to(&mut buf);
assert_eq!(original.encoded_len(), buf.len());
let mut decoded = UnknownFields::new();
let mut cur = buf.as_slice();
while !cur.is_empty() {
let tag = Tag::decode(&mut cur).unwrap();
decoded.push(decode_unknown_field(tag, &mut cur, crate::RECURSION_LIMIT).unwrap());
}
assert_eq!(decoded, original);
}
#[test]
fn test_decode_varint_slice_all_sizes() {
let test_values: &[u64] = &[
0, 128, 1 << 14, 1 << 21, 1 << 28, 1 << 35, 1 << 42, 1 << 49, 1 << 56, u64::MAX, ];
for &v in test_values {
let mut buf = Vec::new();
encode_varint(v, &mut buf);
let (decoded, advance) = decode_varint_slice(&buf).unwrap();
assert_eq!(v, decoded, "decode_varint_slice failed for {v}");
assert_eq!(buf.len(), advance, "advance mismatch for {v}");
}
}
#[test]
fn test_decode_varint_slice_overflow_rejected() {
let mut buf: Vec<u8> = vec![0xFF; 9];
buf.push(0x02);
assert_eq!(decode_varint_slice(&buf), Err(DecodeError::VarintTooLong));
}
#[test]
fn test_decode_varint_slow_roundtrip() {
let test_values: &[u64] = &[
0,
1,
127,
128,
300,
16384,
1 << 7,
(1 << 7) - 1,
1 << 14,
(1 << 14) - 1,
1 << 21,
1 << 28,
1 << 35,
1 << 42,
1 << 49,
1 << 56,
1 << 63,
u64::MAX,
];
for &v in test_values {
let mut buf = Vec::new();
encode_varint(v, &mut buf);
let decoded = decode_varint_slow(&mut buf.as_slice()).unwrap();
assert_eq!(v, decoded, "slow path roundtrip failed for {v}");
}
}
#[test]
fn test_decode_varint_slow_overflow_rejected() {
let mut buf: Vec<u8> = vec![0xFF; 9];
buf.push(0x02);
assert_eq!(
decode_varint_slow(&mut buf.as_slice()),
Err(DecodeError::VarintTooLong)
);
}
#[test]
fn test_decode_varint_empty_buffer() {
let mut buf: &[u8] = &[];
assert_eq!(decode_varint(&mut buf), Err(DecodeError::UnexpectedEof));
}
#[test]
fn test_decode_varint_slow_path_via_fragmented_buffer() {
use bytes::Buf;
let test_values: &[u64] = &[128, 300, 16384, 1 << 28, u64::MAX];
for &v in test_values {
let mut encoded = Vec::new();
encode_varint(v, &mut encoded);
let mid = encoded.len() / 2;
let first_half = bytes::Bytes::copy_from_slice(&encoded[..mid]);
let second_half = bytes::Bytes::copy_from_slice(&encoded[mid..]);
let mut chain = first_half.chain(second_half);
let decoded = decode_varint(&mut chain).unwrap();
assert_eq!(v, decoded, "fragmented buffer roundtrip failed for {v}");
assert_eq!(chain.remaining(), 0);
}
}
#[test]
fn test_decode_varint_single_byte_fast_path() {
for v in 0..=127u64 {
let mut buf = Vec::new();
encode_varint(v, &mut buf);
assert_eq!(buf.len(), 1);
let decoded = decode_varint(&mut buf.as_slice()).unwrap();
assert_eq!(v, decoded);
}
}
#[cfg(target_pointer_width = "32")]
const OVERSIZED_VARINT: &[u8] = &[0x80, 0x80, 0x80, 0x80, 0x10];
#[test]
#[cfg(target_pointer_width = "32")]
fn skip_field_rejects_oversized_length_on_32bit() {
let tag = Tag::new(1, WireType::LengthDelimited);
let mut buf: &[u8] = OVERSIZED_VARINT;
assert_eq!(skip_field(tag, &mut buf), Err(DecodeError::MessageTooLarge));
}
#[test]
#[cfg(target_pointer_width = "32")]
fn decode_unknown_field_rejects_oversized_length_on_32bit() {
let tag = Tag::new(1, WireType::LengthDelimited);
let mut buf: &[u8] = OVERSIZED_VARINT;
assert_eq!(
decode_unknown_field(tag, &mut buf, crate::RECURSION_LIMIT),
Err(DecodeError::MessageTooLarge)
);
}
}