use crate::{Memory, WASM_PAGE_SIZE};
use std::io;
#[cfg(test)]
mod tests;
pub struct Reader<'a, M> {
offset: u64,
memory: &'a M,
}
#[derive(Debug)]
pub struct OutOfBounds {
pub max_address: u64,
pub attempted_read_address: u64,
}
impl<'a, M: Memory> Reader<'a, M> {
pub fn new(memory: &'a M, offset: u64) -> Self {
Self { offset, memory }
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, OutOfBounds> {
let memory_end_addr = self.memory.size() * WASM_PAGE_SIZE;
let read_buf = if buf.len() as u64 + self.offset > memory_end_addr {
if self.offset < memory_end_addr {
let available_bytes = (memory_end_addr - self.offset) as usize;
&mut buf[..available_bytes]
} else {
return Err(OutOfBounds {
max_address: memory_end_addr,
attempted_read_address: self.offset,
});
}
} else {
buf
};
self.memory.read(self.offset, read_buf);
self.offset += read_buf.len() as u64;
Ok(read_buf.len())
}
}
impl<'a, M: Memory> io::Read for Reader<'a, M> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
self.read(buf).or(Ok(0)) }
}
pub struct BufferedReader<'a, M> {
inner: io::BufReader<Reader<'a, M>>,
}
impl<'a, M: Memory> BufferedReader<'a, M> {
pub fn new(buffer_size: usize, reader: Reader<M>) -> BufferedReader<M> {
BufferedReader {
inner: io::BufReader::with_capacity(buffer_size, reader),
}
}
}
impl<'a, M: Memory> io::Read for BufferedReader<'a, M> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
}