use crate::integer::Integer;
#[derive(Clone, Debug)]
pub struct SimpleCursor<'a> {
index: usize,
collection: &'a [u8],
}
impl core::fmt::Display for SimpleCursor<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "byte {} of {}", self.index, self.collection.len())
}
}
impl<'a> SimpleCursor<'a> {
pub fn new(collection: &'a [u8]) -> Self {
Self {
index: 0,
collection,
}
}
pub fn read(&mut self, buffer: &mut [u8]) -> usize {
let byte_count = buffer.len().min(self.collection.len() - self.index);
if byte_count == 0 {
return 0;
}
let data = self.read_count(byte_count).unwrap();
buffer[..byte_count].copy_from_slice(data);
byte_count
}
pub fn read_to_array<const N: usize>(&mut self) -> Result<[u8; N], OutOfBounds> {
let mut output = [0u8; N];
let data = self.read_count(N)?;
output.copy_from_slice(data);
Ok(output)
}
pub fn read_count<N: Into<usize>>(&mut self, count: N) -> Result<&[u8], OutOfBounds> {
let count = count.into();
let data = self
.collection
.get(self.index..self.index + count)
.ok_or_else(|| OutOfBounds::new(count))?;
self.index += count;
Ok(data)
}
pub fn read_be_integer<const N: usize, I: Integer<N>>(&mut self) -> Result<I, OutOfBounds> {
let data = self.read_to_array::<N>()?;
Ok(I::from_be_bytes(data))
}
pub fn read_le_integer<const N: usize, I: Integer<N>>(&mut self) -> Result<I, OutOfBounds> {
let data = self.read_to_array::<N>()?;
Ok(I::from_le_bytes(data))
}
pub fn read_ne_integer<const N: usize, I: Integer<N>>(&mut self) -> Result<I, OutOfBounds> {
let data = self.read_to_array::<N>()?;
Ok(I::from_ne_bytes(data))
}
}
impl std::io::Read for SimpleCursor<'_> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
Ok(self.read(buf))
}
}
#[derive(Clone, Copy, Debug)]
#[non_exhaustive]
pub struct OutOfBounds {
requested: usize,
}
impl OutOfBounds {
fn new(requested: usize) -> Self {
Self { requested }
}
}
impl core::fmt::Display for OutOfBounds {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"reading {} bytes would take the cursor out of bounds",
self.requested,
)
}
}
impl core::error::Error for OutOfBounds {}
#[cfg(test)]
mod test {
use crate::simple_cursor::SimpleCursor;
#[test]
fn simple_cursor() {
let collection: Vec<u8> = (0..32).collect();
let mut cursor = SimpleCursor::new(&collection);
let result = cursor.read_count(2usize).unwrap();
assert_eq!(&[0, 1], result);
let mut buffer = vec![0u8; 0];
let result = cursor.read(&mut buffer);
assert_eq!(0, result);
let mut buffer = vec![0u8; 4];
let result = cursor.read(&mut buffer);
assert_eq!(4, result);
assert_eq!(vec![2, 3, 4, 5], buffer);
let result = cursor.read_to_array::<3>().unwrap();
assert_eq!([6, 7, 8], result);
let result: u8 = cursor.read_ne_integer().unwrap();
assert_eq!(9, result);
let result: i8 = cursor.read_ne_integer().unwrap();
assert_eq!(10, result);
let result: i64 = cursor.read_be_integer().unwrap();
assert_eq!(i64::from_be_bytes([11, 12, 13, 14, 15, 16, 17, 18]), result);
let result: u32 = cursor.read_le_integer().unwrap();
assert_eq!(u32::from_le_bytes([19, 20, 21, 22]), result);
let mut buffer = vec![0u8; 32];
let result = cursor.read(&mut buffer);
assert_eq!(result, 9);
assert_eq!(&[23, 24, 25, 26, 27, 28, 29, 30, 31], &buffer[0..9]);
let result = cursor.read(&mut buffer);
assert_eq!(0, result);
}
}