ic_stable_structures/
reader.rs

1use crate::{Memory, WASM_PAGE_SIZE};
2use std::io;
3
4#[cfg(test)]
5mod tests;
6
7/// A reader to the stable memory.
8///
9/// Keeps an offset and reads off memory consecutively.
10pub struct Reader<'a, M> {
11    /// The offset of the next read.
12    offset: u64,
13
14    /// The stable memory to read data from.
15    memory: &'a M,
16}
17
18#[derive(Debug)]
19pub struct OutOfBounds {
20    pub max_address: u64,
21    pub attempted_read_address: u64,
22}
23
24impl<'a, M: Memory> Reader<'a, M> {
25    /// Creates a new `Reader` which reads from the selected memory starting from the specified offset.
26    pub fn new(memory: &'a M, offset: u64) -> Self {
27        Self { offset, memory }
28    }
29
30    /// Reads data from the memory location specified by an offset.
31    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, OutOfBounds> {
32        let memory_end_addr = self.memory.size() * WASM_PAGE_SIZE;
33
34        let read_buf = if buf.len() as u64 + self.offset > memory_end_addr {
35            if self.offset < memory_end_addr {
36                // read only until the end of stable memory if an oversized buffer is provided
37                let available_bytes = (memory_end_addr - self.offset) as usize;
38                &mut buf[..available_bytes]
39            } else {
40                return Err(OutOfBounds {
41                    max_address: memory_end_addr,
42                    attempted_read_address: self.offset,
43                });
44            }
45        } else {
46            buf
47        };
48
49        self.memory.read(self.offset, read_buf);
50        self.offset += read_buf.len() as u64;
51        Ok(read_buf.len())
52    }
53}
54
55impl<M: Memory> io::Read for Reader<'_, M> {
56    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
57        self.read(buf).or(Ok(0)) // Read defines EOF to be success
58    }
59}
60
61/// A reader to the stable memory which reads bytes a chunk at a time as each chunk is required.
62pub struct BufferedReader<'a, M> {
63    inner: io::BufReader<Reader<'a, M>>,
64}
65
66impl<M: Memory> BufferedReader<'_, M> {
67    /// Creates a new `BufferedReader` which reads from the selected memory
68    pub fn new(buffer_size: usize, reader: Reader<M>) -> BufferedReader<M> {
69        BufferedReader {
70            inner: io::BufReader::with_capacity(buffer_size, reader),
71        }
72    }
73}
74
75impl<M: Memory> io::Read for BufferedReader<'_, M> {
76    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
77        self.inner.read(buf)
78    }
79}