#![warn(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
use core::cell::Cell;
use super::errors::TBytesError;
#[derive(Clone, Debug)]
pub struct TBytesReader<B: TBytesReaderBackend> {
backend: B,
}
impl<B: TBytesReaderBackend> TBytesReader<B> {
pub fn new(backend: B) -> Self {
Self { backend }
}
}
pub trait TBytesReaderFor<T> {
fn read(&self) -> Result<T, TBytesError>;
fn read_array<const N: usize>(&self) -> Result<[T; N], TBytesError>;
}
macro_rules! t_bytes_reader_for {
($type_: ident) => {
impl<B: TBytesReaderBackend> TBytesReaderFor<$type_> for TBytesReader<B> {
fn read(&self) -> Result<$type_, TBytesError> {
const SIZE: usize = core::mem::size_of::<$type_>();
let mut bytes = [0u8; SIZE];
bytes.copy_from_slice(self.backend.read(SIZE)?);
Ok($type_::from_le_bytes(bytes))
}
fn read_array<const N: usize>(&self) -> Result<[$type_; N], TBytesError> {
const SIZE: usize = core::mem::size_of::<$type_>();
let mut result: [$type_; N] = [0 as $type_; N];
for i in 0..N {
let mut bytes = [0u8; SIZE];
bytes.copy_from_slice(self.backend.read(SIZE)?);
result[i] = $type_::from_le_bytes(bytes);
}
Ok(result)
}
}
};
}
t_bytes_reader_for!(u8);
t_bytes_reader_for!(u16);
t_bytes_reader_for!(u32);
t_bytes_reader_for!(u64);
t_bytes_reader_for!(u128);
t_bytes_reader_for!(i8);
t_bytes_reader_for!(i16);
t_bytes_reader_for!(i32);
t_bytes_reader_for!(i64);
t_bytes_reader_for!(i128);
t_bytes_reader_for!(f32);
t_bytes_reader_for!(f64);
pub trait TBytesReaderBackend: Sized {
fn read(&self, num_bytes: usize) -> Result<&[u8], TBytesError>;
}
#[derive(Clone, Debug)]
pub struct TBytesReaderSliceBackend<'a> {
buffer: &'a [u8],
pos: Cell<usize>,
}
impl<'a> TBytesReaderSliceBackend<'a> {
pub fn new(buffer: &'a [u8]) -> Self {
Self {
buffer,
pos: Default::default(),
}
}
pub fn pos(&self) -> usize {
self.pos.get()
}
}
impl<'a> TBytesReaderBackend for TBytesReaderSliceBackend<'a> {
fn read(&self, num_bytes: usize) -> Result<&[u8], TBytesError> {
let pos = self.pos.get();
if self.buffer.len() < pos + num_bytes {
return Err(TBytesError::OutOfBounds);
}
let bytes = &self.buffer[pos..pos + num_bytes];
self.pos.replace(pos + num_bytes);
Ok(bytes)
}
}
impl<'a> From<&'a [u8]> for TBytesReader<TBytesReaderSliceBackend<'a>> {
fn from(value: &'a [u8]) -> Self {
TBytesReader::new(TBytesReaderSliceBackend::new(value))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn slice_backend() {
let buffer = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9u8];
let backend = TBytesReaderSliceBackend::new(&buffer);
assert_eq!(backend.read(2).unwrap(), &[0, 1u8]);
assert_eq!(backend.read(4).unwrap(), &[2, 3, 4, 5u8]);
assert_eq!(backend.read(4).unwrap(), &[6, 7, 8, 9u8]);
let eof = backend.read(1);
assert!(eof.is_err());
assert!(matches!(eof, Err(TBytesError::OutOfBounds)));
}
#[test]
fn slice_backend_out_of_bouts_is_idempotent() {
let buffer = [42; 10];
let backend = TBytesReaderSliceBackend::new(&buffer);
assert_eq!(backend.read(10).unwrap(), &[42; 10]);
let eof = backend.read(1);
assert!(matches!(eof, Err(TBytesError::OutOfBounds)));
let eof = backend.read(1);
assert!(matches!(eof, Err(TBytesError::OutOfBounds)));
assert_eq!(backend.pos(), 10);
}
#[test]
fn from_slice() {
let buffer = [128, 255, 1, 1u8, 1, 255];
let reader = TBytesReader::from(buffer.as_slice());
let val: u8 = reader.read().unwrap();
assert_eq!(val, 128);
let val: i8 = reader.read().unwrap();
assert_eq!(val, -1);
let val: u16 = reader.read().unwrap();
assert_eq!(val, 257);
let val: [u8; 2] = reader.read_array().unwrap();
assert_eq!(val, [1, 255]);
}
#[test]
fn bytes_reader_for() {
let buffer = [128, 255, 1, 1u8, 1, 255];
let backend = TBytesReaderSliceBackend::new(&buffer);
let reader = TBytesReader::new(backend);
let val: u8 = reader.read().unwrap();
assert_eq!(val, 128);
let val: i8 = reader.read().unwrap();
assert_eq!(val, -1);
let val: u16 = reader.read().unwrap();
assert_eq!(val, 257);
let val: [u8; 2] = reader.read_array().unwrap();
assert_eq!(val, [1, 255]);
}
#[test]
fn arrays() {
let buffer = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9u8];
let backend = TBytesReaderSliceBackend::new(&buffer);
let reader = &TBytesReader::new(backend);
let result: Result<[u8; 8], TBytesError> = reader.read_array();
assert!(result.is_ok());
assert_eq!(result.unwrap(), [0, 1, 2, 3, 4, 5, 6, 7u8]);
let result: Result<[u8; 4], TBytesError> = reader.read_array();
assert!(result.is_err());
}
}