//! Varint decode utilities. use 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 } } /// Decode a varint, and return decoded value and decoded byte count. #[inline] fn decode_varint_full(rem: &[u8]) -> crate::Result> { 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(buf: &[u8]) -> crate::Result> { if buf.len() >= 1 && buf[0] < 0x80 { // The the most common case. let ret = buf[0] as u64; let consume = 1; Ok(Some((D::from_u64(ret), consume))) } else if buf.len() >= 2 && buf[1] < 0x80 { // Handle the case of two bytes too. let ret = (buf[0] & 0x7f) as u64 | (buf[1] as u64) << 7; let consume = 2; Ok(Some((D::from_u64(ret), consume))) } else { // Read from array when buf at at least 10 bytes, // max len for varint. decode_varint_full(buf) } } /// Try decode a varint. Return `None` if the buffer does not contain complete varint. #[inline] pub(crate) fn decode_varint64(buf: &[u8]) -> crate::Result> { decode_varint_impl(buf) } /// Try decode a varint. Return `None` if the buffer does not contain complete varint. #[inline] pub(crate) fn decode_varint32(buf: &[u8]) -> crate::Result> { 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()); } }