use crate::error::{Error, Result};
#[derive(Debug, Clone)]
pub struct ReadBuf<'a> {
bytes: &'a [u8],
pos: usize,
}
impl<'a> ReadBuf<'a> {
#[inline]
pub const fn new(bytes: &'a [u8]) -> Self {
Self { bytes, pos: 0 }
}
#[inline]
pub const fn position(&self) -> usize {
self.pos
}
#[inline]
pub const fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.pos >= self.bytes.len()
}
#[inline]
pub fn remaining_slice(&self) -> &'a [u8] {
&self.bytes[self.pos..]
}
#[inline]
pub fn peek(&self, n: usize) -> Result<&'a [u8]> {
let end = self.pos.checked_add(n).ok_or(Error::UnexpectedEof)?;
if end > self.bytes.len() {
return Err(Error::UnexpectedEof);
}
Ok(&self.bytes[self.pos..end])
}
#[inline]
pub fn read_bytes(&mut self, n: usize) -> Result<&'a [u8]> {
let slice = self.peek(n)?;
self.pos += n;
Ok(slice)
}
#[inline]
pub fn advance(&mut self, n: usize) -> Result<()> {
let end = self.pos.checked_add(n).ok_or(Error::UnexpectedEof)?;
if end > self.bytes.len() {
return Err(Error::UnexpectedEof);
}
self.pos = end;
Ok(())
}
#[inline]
pub fn read_u8(&mut self) -> Result<u8> {
if self.pos >= self.bytes.len() {
return Err(Error::UnexpectedEof);
}
let value = self.bytes[self.pos];
self.pos += 1;
Ok(value)
}
#[inline]
pub fn read_u16_be(&mut self) -> Result<u16> {
let bytes = self.read_bytes(2)?;
Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
}
#[inline]
pub fn read_u16_le(&mut self) -> Result<u16> {
let bytes = self.read_bytes(2)?;
Ok(u16::from_le_bytes([bytes[0], bytes[1]]))
}
#[inline]
pub fn read_u32_be(&mut self) -> Result<u32> {
let bytes = self.read_bytes(4)?;
Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
}
#[inline]
pub fn read_u32_le(&mut self) -> Result<u32> {
let bytes = self.read_bytes(4)?;
Ok(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
}
#[inline]
pub fn read_u64_be(&mut self) -> Result<u64> {
let bytes = self.read_bytes(8)?;
let mut arr = [0u8; 8];
arr.copy_from_slice(bytes);
Ok(u64::from_be_bytes(arr))
}
#[inline]
pub fn read_u64_le(&mut self) -> Result<u64> {
let bytes = self.read_bytes(8)?;
let mut arr = [0u8; 8];
arr.copy_from_slice(bytes);
Ok(u64::from_le_bytes(arr))
}
}
#[derive(Debug)]
pub struct WriteBuf<'a> {
bytes: &'a mut [u8],
pos: usize,
}
impl<'a> WriteBuf<'a> {
#[inline]
pub fn new(bytes: &'a mut [u8]) -> Self {
Self { bytes, pos: 0 }
}
#[inline]
pub fn capacity(&self) -> usize {
self.bytes.len()
}
#[inline]
pub fn position(&self) -> usize {
self.pos
}
#[inline]
pub fn remaining(&self) -> usize {
self.bytes.len() - self.pos
}
#[inline]
pub fn written(&self) -> &[u8] {
&self.bytes[..self.pos]
}
#[inline]
pub fn write_bytes(&mut self, src: &[u8]) -> Result<()> {
let end = self.pos.checked_add(src.len()).ok_or(Error::BufferFull)?;
if end > self.bytes.len() {
return Err(Error::BufferFull);
}
self.bytes[self.pos..end].copy_from_slice(src);
self.pos = end;
Ok(())
}
#[inline]
pub fn write_u8(&mut self, value: u8) -> Result<()> {
if self.pos >= self.bytes.len() {
return Err(Error::BufferFull);
}
self.bytes[self.pos] = value;
self.pos += 1;
Ok(())
}
#[inline]
pub fn write_u16_be(&mut self, value: u16) -> Result<()> {
self.write_bytes(&value.to_be_bytes())
}
#[inline]
pub fn write_u16_le(&mut self, value: u16) -> Result<()> {
self.write_bytes(&value.to_le_bytes())
}
#[inline]
pub fn write_u32_be(&mut self, value: u32) -> Result<()> {
self.write_bytes(&value.to_be_bytes())
}
#[inline]
pub fn write_u32_le(&mut self, value: u32) -> Result<()> {
self.write_bytes(&value.to_le_bytes())
}
#[inline]
pub fn write_u64_be(&mut self, value: u64) -> Result<()> {
self.write_bytes(&value.to_be_bytes())
}
#[inline]
pub fn write_u64_le(&mut self, value: u64) -> Result<()> {
self.write_bytes(&value.to_le_bytes())
}
#[inline]
pub fn into_written(self) -> &'a mut [u8] {
&mut self.bytes[..self.pos]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn read_buf_round_trip() {
let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
let mut buf = ReadBuf::new(&data);
assert_eq!(buf.read_u8().unwrap(), 0x01);
assert_eq!(buf.read_u16_be().unwrap(), 0x0203);
assert_eq!(buf.read_u32_be().unwrap(), 0x04050607);
assert_eq!(buf.remaining(), 1);
assert_eq!(buf.read_u8().unwrap(), 0x08);
assert!(buf.is_empty());
}
#[test]
fn read_buf_eof() {
let mut buf = ReadBuf::new(&[0x01]);
assert_eq!(buf.read_u8().unwrap(), 0x01);
assert_eq!(buf.read_u8(), Err(Error::UnexpectedEof));
}
#[test]
fn read_buf_peek_does_not_advance() {
let buf = ReadBuf::new(&[0xAA, 0xBB]);
assert_eq!(buf.peek(2).unwrap(), &[0xAA, 0xBB]);
assert_eq!(buf.position(), 0);
}
#[test]
fn write_buf_round_trip() {
let mut storage = [0u8; 8];
let mut buf = WriteBuf::new(&mut storage);
buf.write_u8(0x01).unwrap();
buf.write_u16_be(0x0203).unwrap();
buf.write_u32_le(0x07060504).unwrap();
buf.write_u8(0x08).unwrap();
assert_eq!(&storage, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
}
#[test]
fn write_buf_full() {
let mut storage = [0u8; 2];
let mut buf = WriteBuf::new(&mut storage);
buf.write_u16_be(0x1234).unwrap();
assert_eq!(buf.write_u8(0), Err(Error::BufferFull));
}
}