use crate::egress::wire::varint;
use crate::error::{Result, fmt};
pub(crate) struct ByteReader<'a> {
bytes: &'a [u8],
pos: usize,
}
impl<'a> ByteReader<'a> {
#[inline]
pub(crate) fn new(bytes: &'a [u8]) -> Self {
Self { bytes, pos: 0 }
}
#[inline]
pub(crate) fn pos(&self) -> usize {
self.pos
}
#[inline]
pub(crate) fn remaining(&self) -> &'a [u8] {
&self.bytes[self.pos..]
}
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.pos == self.bytes.len()
}
#[inline]
pub(crate) fn advance(&mut self, n: usize) -> Result<()> {
let new_pos = self
.pos
.checked_add(n)
.ok_or_else(|| fmt!(ProtocolError, "byte reader pos overflow"))?;
if new_pos > self.bytes.len() {
return Err(fmt!(
ProtocolError,
"frame truncated: need {} bytes, have {}",
n,
self.bytes.len() - self.pos
));
}
self.pos = new_pos;
Ok(())
}
#[inline]
pub(crate) fn read_u8(&mut self) -> Result<u8> {
if self.pos >= self.bytes.len() {
return Err(fmt!(ProtocolError, "frame truncated reading u8"));
}
let v = self.bytes[self.pos];
self.pos += 1;
Ok(v)
}
#[inline]
pub(crate) fn read_u16_le(&mut self) -> Result<u16> {
Ok(u16::from_le_bytes(self.read_bytes(2)?.try_into().unwrap()))
}
#[inline]
pub(crate) fn read_u32_le(&mut self) -> Result<u32> {
Ok(u32::from_le_bytes(self.read_bytes(4)?.try_into().unwrap()))
}
#[inline]
pub(crate) fn read_u64_le(&mut self) -> Result<u64> {
Ok(u64::from_le_bytes(self.read_bytes(8)?.try_into().unwrap()))
}
#[inline]
pub(crate) fn read_i64_le(&mut self) -> Result<i64> {
Ok(i64::from_le_bytes(self.read_bytes(8)?.try_into().unwrap()))
}
#[inline]
pub(crate) fn read_bytes(&mut self, n: usize) -> Result<&'a [u8]> {
let end = self
.pos
.checked_add(n)
.ok_or_else(|| fmt!(ProtocolError, "byte reader pos overflow"))?;
if end > self.bytes.len() {
return Err(fmt!(
ProtocolError,
"frame truncated: need {} bytes, have {}",
n,
self.bytes.len() - self.pos
));
}
let s = &self.bytes[self.pos..end];
self.pos = end;
Ok(s)
}
#[inline]
pub(crate) fn read_varint_u64(&mut self) -> Result<u64> {
let (v, n) = varint::decode_u64(self.remaining())?;
self.advance(n)?;
Ok(v)
}
#[inline]
pub(crate) fn read_varint_usize(&mut self) -> Result<usize> {
let (v, n) = varint::decode_usize(self.remaining())?;
self.advance(n)?;
Ok(v)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::ErrorCode;
#[test]
fn reads_in_order() {
let bytes = [0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02, 0x03, 0x04, 0x05];
let mut r = ByteReader::new(&bytes);
assert_eq!(r.read_u8().unwrap(), 0xDE);
assert_eq!(r.read_u8().unwrap(), 0xAD);
assert_eq!(r.read_u16_le().unwrap(), 0xEFBE);
assert_eq!(r.read_u32_le().unwrap(), 0x04030201);
assert_eq!(r.read_u8().unwrap(), 0x05);
assert!(r.is_empty());
}
#[test]
fn truncation_is_protocol_error() {
let bytes = [0x01u8, 0x02];
let mut r = ByteReader::new(&bytes);
let err = r.read_u32_le().unwrap_err();
assert_eq!(err.code(), ErrorCode::ProtocolError);
}
#[test]
fn varint_via_reader() {
let bytes = [0xAC, 0x02, 0xFF];
let mut r = ByteReader::new(&bytes);
assert_eq!(r.read_varint_u64().unwrap(), 300);
assert_eq!(r.remaining(), &[0xFF]);
}
}