use crate::DecodeError; use crate::varint::{self, VarintError}; /// A cursor over a packet body. #[derive(Debug, Clone)] pub(crate) struct Reader<'a> { bytes: &'a [u8], position: usize, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum ReadError { Truncated, Overflow, } impl From for DecodeError { fn from(error: ReadError) -> Self { match error { ReadError::Truncated => Self::Truncated, ReadError::Overflow => Self::Overflow, } } } impl<'a> Reader<'a> { pub fn new(bytes: &'a [u8]) -> Self { Self { bytes, position: 0 } } pub fn position(&self) -> usize { self.position } /// The bytes not yet read. pub fn rest(&self) -> &'a [u8] { &self.bytes[self.position..] } pub fn skip(&mut self, len: usize) -> Result<(), ReadError> { if self.rest().len() < len { return Err(ReadError::Truncated); } self.position += len; Ok(()) } /// Reads past `expected` if the bytes not yet read start with it. pub fn eat(&mut self, expected: &[u8]) -> bool { let matches = self.rest().starts_with(expected); if matches { self.position += expected.len(); } matches } pub fn u8(&mut self) -> Result { let byte = *self.rest().first().ok_or(ReadError::Truncated)?; self.position += 1; Ok(byte) } pub fn bytes(&mut self, len: usize) -> Result<&'a [u8], ReadError> { let bytes = self.rest().get(..len).ok_or(ReadError::Truncated)?; self.position += len; Ok(bytes) } pub fn u16_le(&mut self) -> Result { let bytes = self.rest().first_chunk::<2>().ok_or(ReadError::Truncated)?; self.position += 2; Ok(u16::from_le_bytes(*bytes)) } pub fn u32_le(&mut self) -> Result { let bytes = self.rest().first_chunk::<4>().ok_or(ReadError::Truncated)?; self.position += 4; Ok(u32::from_le_bytes(*bytes)) } pub fn u64_le(&mut self) -> Result { let bytes = self.rest().first_chunk::<8>().ok_or(ReadError::Truncated)?; self.position += 8; Ok(u64::from_le_bytes(*bytes)) } pub fn varint(&mut self) -> Result { let (value, len) = varint::read(self.rest()).map_err(|error| match error { VarintError::Incomplete => ReadError::Truncated, VarintError::Overflow => ReadError::Overflow, })?; self.position += len; Ok(value) } }