protobuf/varint/
decode.rsuse crate::error::WireError;
use crate::varint::MAX_VARINT32_ENCODED_LEN;
use crate::varint::MAX_VARINT_ENCODED_LEN;
trait DecodeVarint {
const MAX_ENCODED_LEN: usize;
const LAST_BYTE_MAX_VALUE: u8;
fn from_u64(value: u64) -> Self;
}
impl DecodeVarint for u64 {
const MAX_ENCODED_LEN: usize = MAX_VARINT_ENCODED_LEN;
const LAST_BYTE_MAX_VALUE: u8 = 0x01;
fn from_u64(value: u64) -> Self {
value
}
}
impl DecodeVarint for u32 {
const MAX_ENCODED_LEN: usize = MAX_VARINT32_ENCODED_LEN;
const LAST_BYTE_MAX_VALUE: u8 = 0x0f;
fn from_u64(value: u64) -> Self {
value as u32
}
}
#[inline]
fn decode_varint_full<D: DecodeVarint>(rem: &[u8]) -> crate::Result<Option<(D, usize)>> {
let mut r: u64 = 0;
for (i, &b) in rem.iter().enumerate() {
if i == D::MAX_ENCODED_LEN - 1 {
if b > D::LAST_BYTE_MAX_VALUE {
return Err(WireError::IncorrectVarint.into());
}
let r = r | ((b as u64) << (i as u64 * 7));
return Ok(Some((D::from_u64(r), i + 1)));
}
r = r | (((b & 0x7f) as u64) << (i as u64 * 7));
if b < 0x80 {
return Ok(Some((D::from_u64(r), i + 1)));
}
}
Ok(None)
}
#[inline]
fn decode_varint_impl<D: DecodeVarint>(buf: &[u8]) -> crate::Result<Option<(D, usize)>> {
if buf.len() >= 1 && buf[0] < 0x80 {
let ret = buf[0] as u64;
let consume = 1;
Ok(Some((D::from_u64(ret), consume)))
} else if buf.len() >= 2 && buf[1] < 0x80 {
let ret = (buf[0] & 0x7f) as u64 | (buf[1] as u64) << 7;
let consume = 2;
Ok(Some((D::from_u64(ret), consume)))
} else {
decode_varint_full(buf)
}
}
#[inline]
pub(crate) fn decode_varint64(buf: &[u8]) -> crate::Result<Option<(u64, usize)>> {
decode_varint_impl(buf)
}
#[inline]
pub(crate) fn decode_varint32(buf: &[u8]) -> crate::Result<Option<(u32, usize)>> {
decode_varint_impl(buf)
}
#[cfg(test)]
mod tests {
use crate::hex::decode_hex;
use crate::varint::decode::decode_varint32;
use crate::varint::decode::decode_varint64;
#[test]
fn test_decode_varint64() {
assert_eq!((0, 1), decode_varint64(&decode_hex("00")).unwrap().unwrap());
assert_eq!(
(u64::MAX, 10),
decode_varint64(&decode_hex("ff ff ff ff ff ff ff ff ff 01"))
.unwrap()
.unwrap()
);
assert!(decode_varint64(&decode_hex("ff ff ff ff ff ff ff ff ff 02")).is_err());
}
#[test]
fn test_decode_varint32() {
assert_eq!((0, 1), decode_varint32(&decode_hex("00")).unwrap().unwrap());
assert_eq!(
(u32::MAX, 5),
decode_varint32(&decode_hex("ff ff ff ff 0f"))
.unwrap()
.unwrap()
);
assert!(decode_varint32(&decode_hex("ff ff ff ff 10")).is_err());
}
}