ic_kit/
stable.rs

1// This file is copied from ic_cdk, but changed so that it works with IC-Kit.
2use crate::ic::{stable_grow, stable_read, stable_size, stable_write};
3use crate::StableMemoryError;
4use std::io;
5
6/// A writer to the stable memory.
7///
8/// Will attempt to grow the memory as it writes,
9/// and keep offsets and total capacity.
10pub struct StableWriter {
11    /// The offset of the next write.
12    offset: usize,
13    /// The capacity, in pages.
14    capacity: u32,
15}
16
17impl Default for StableWriter {
18    fn default() -> Self {
19        let capacity = stable_size();
20
21        Self {
22            offset: 0,
23            capacity,
24        }
25    }
26}
27
28impl StableWriter {
29    /// Create a new stable writer that writes from the given offset forward.
30    pub fn new(offset: usize) -> Self {
31        StableWriter {
32            offset,
33            capacity: stable_size(),
34        }
35    }
36
37    /// Returns the current offset of the writer.
38    pub fn offset(&self) -> usize {
39        self.offset
40    }
41
42    /// Attempts to grow the memory by adding new pages.
43    pub fn grow(&mut self, added_pages: u32) -> Result<(), StableMemoryError> {
44        let old_page_count = stable_grow(added_pages)?;
45        self.capacity = old_page_count + added_pages;
46        Ok(())
47    }
48
49    /// Writes a byte slice to the buffer.
50    ///
51    /// The only condition where this will
52    /// error out is if it cannot grow the memory.
53    pub fn write(&mut self, buf: &[u8]) -> Result<usize, StableMemoryError> {
54        if self.offset + buf.len() > ((self.capacity as usize) << 16) {
55            self.grow((buf.len() >> 16) as u32 + 1)?;
56        }
57
58        stable_write(self.offset as u32, buf);
59        self.offset += buf.len();
60        Ok(buf.len())
61    }
62}
63
64impl io::Write for StableWriter {
65    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
66        self.write(buf)
67            .map_err(|_| io::Error::new(io::ErrorKind::Other, "Out Of Memory"))
68    }
69
70    fn flush(&mut self) -> Result<(), io::Error> {
71        // Noop.
72        Ok(())
73    }
74}
75
76/// A reader to the stable memory.
77///
78/// Keeps an offset and reads off stable memory consecutively.
79pub struct StableReader {
80    /// The offset of the next write.
81    offset: usize,
82}
83
84impl Default for StableReader {
85    fn default() -> Self {
86        Self { offset: 0 }
87    }
88}
89
90impl StableReader {
91    /// Create a new stable reader that reads from the given offset forward.
92    pub fn new(offset: usize) -> Self {
93        StableReader { offset }
94    }
95
96    /// Reads data from the stable memory location specified by an offset.
97    pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, StableMemoryError> {
98        stable_read(self.offset as u32, buf);
99        self.offset += buf.len();
100        Ok(buf.len())
101    }
102}
103
104impl io::Read for StableReader {
105    fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
106        self.read(buf)
107            .map_err(|_| io::Error::new(io::ErrorKind::Other, "Unexpected error."))
108    }
109}