#[cfg(any(feature = "embedded", feature = "embedded-hal-02"))]
use crate::embedded::Read;
#[cfg(feature = "std")]
use std::io::Read;
#[cfg(all(doc, feature = "std"))]
use std::io::ErrorKind;
use crate::error::MessageReadError;
pub struct PeekReader<R, const BUFFER_SIZE: usize = 280> {
buffer: [u8; BUFFER_SIZE],
cursor: usize,
top: usize,
reader: R,
}
impl<R: Read, const BUFFER_SIZE: usize> PeekReader<R, BUFFER_SIZE> {
pub fn new(reader: R) -> Self {
Self {
buffer: [0; BUFFER_SIZE],
cursor: 0,
top: 0,
reader,
}
}
pub fn peek_exact(&mut self, amount: usize) -> Result<&[u8], MessageReadError> {
let result = self.fetch(amount, false);
result
}
pub fn read_exact(&mut self, amount: usize) -> Result<&[u8], MessageReadError> {
self.fetch(amount, true)
}
pub fn read_u8(&mut self) -> Result<u8, MessageReadError> {
let buf = self.read_exact(1)?;
Ok(buf[0])
}
pub fn consume(&mut self, amount: usize) -> usize {
let amount = amount.min(self.top - self.cursor);
self.cursor += amount;
amount
}
pub fn reader_ref(&self) -> &R {
&self.reader
}
pub fn reader_mut(&mut self) -> &mut R {
&mut self.reader
}
fn fetch(&mut self, amount: usize, consume: bool) -> Result<&[u8], MessageReadError> {
loop {
let buffered = self.top - self.cursor;
if buffered >= amount {
break;
}
let bytes_to_read = amount - buffered;
assert!(bytes_to_read < BUFFER_SIZE);
if self.top + bytes_to_read > BUFFER_SIZE {
self.buffer.copy_within(self.cursor..self.top, 0);
self.top = buffered;
self.cursor = 0;
}
let end_pos = self.top + bytes_to_read;
let bytes_read = self.reader.read(&mut self.buffer[self.top..end_pos])?;
if bytes_read == 0 {
return Err(MessageReadError::eof());
}
self.top += bytes_read;
}
let result = &self.buffer[self.cursor..self.cursor + amount];
if consume {
self.cursor += amount;
}
Ok(result)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "std")]
use std::io::Write;
#[cfg(not(feature = "std"))]
use embedded_io::Write;
#[test]
fn test_read_and_peek() {
let data = b"Hello, World!";
let mut buffer = [0u8; 280];
let mut writer: &mut [u8] = &mut buffer[..];
writer.write_all(data).unwrap();
let mut reader = PeekReader::<_, 280>::new(&buffer[..data.len()]);
let peeked = reader.peek_exact(5).unwrap();
assert_eq!(peeked, b"Hello");
let read = reader.read_exact(5).unwrap();
assert_eq!(read, b"Hello");
let read = reader.read_exact(8).unwrap();
assert_eq!(read, b", World!");
match reader.read_u8().unwrap_err() {
#[cfg(feature = "std")]
MessageReadError::Io(io_err) => {
assert_eq!(io_err.kind(), std::io::ErrorKind::UnexpectedEof);
}
#[cfg(not(feature = "std"))]
MessageReadError::Io => (),
_ => panic!("Expected Io error with UnexpectedEof"),
}
}
}