ic_stable_structures/
file_mem.rs1use crate::{Memory, WASM_PAGE_SIZE};
2use std::cell::RefCell;
3use std::fs::File;
4use std::io::{Read, Seek, SeekFrom, Write};
5use std::rc::Rc;
6
7#[derive(Clone)]
9pub struct FileMemory(Rc<RefCell<File>>);
10
11impl FileMemory {
12 pub fn new(file: File) -> Self {
13 Self(Rc::new(RefCell::new(file)))
14 }
15}
16
17impl Memory for FileMemory {
18 fn size(&self) -> u64 {
19 let len = self.0.borrow().metadata().unwrap().len();
20 assert_eq!(
21 len % WASM_PAGE_SIZE,
22 0,
23 "File size must correspond to exact page sizes"
24 );
25 len / WASM_PAGE_SIZE
26 }
27
28 fn grow(&self, pages: u64) -> i64 {
29 let previous_size = self.size();
30 self.0
31 .borrow()
32 .set_len((previous_size + pages) * WASM_PAGE_SIZE)
33 .expect("grow must succeed");
34 assert_eq!(self.size(), previous_size + pages);
35 previous_size as i64
36 }
37
38 fn read(&self, offset: u64, dst: &mut [u8]) {
39 self.0
40 .borrow_mut()
41 .seek(SeekFrom::Start(offset))
42 .expect("out of bounds");
43 let bytes_read = self.0.borrow_mut().read(dst).expect("out of bounds");
44 assert_eq!(bytes_read, dst.len(), "out of bounds");
45 }
46
47 fn write(&self, offset: u64, src: &[u8]) {
48 self.0
49 .borrow_mut()
50 .seek(SeekFrom::Start(offset))
51 .expect("out of bounds");
52 let bytes_written = self.0.borrow_mut().write(src).expect("out of bounds");
53 assert_eq!(bytes_written, src.len(), "out of bounds");
54 }
55}
56
57#[cfg(test)]
58mod test {
59 use super::*;
60 use crate::write;
61 use proptest::prelude::*;
62
63 fn make_vec_memory() -> Rc<RefCell<Vec<u8>>> {
64 Rc::new(RefCell::new(Vec::new()))
65 }
66
67 fn make_file_memory() -> FileMemory {
68 FileMemory::new(tempfile::tempfile().unwrap())
69 }
70
71 #[test]
72 fn write_and_read_random_bytes() {
73 let vec_mem = make_vec_memory();
74 let file_mem = make_file_memory();
75
76 proptest!(|(
77 data in proptest::collection::vec(0..u8::MAX, 0..2*WASM_PAGE_SIZE as usize),
78 offset in 0..10*WASM_PAGE_SIZE
79 )| {
80 write(&file_mem, offset, &data);
82
83 let mut bytes = vec![0; data.len()];
85 file_mem.read(offset, &mut bytes);
86 assert_eq!(bytes, data);
87
88 write(&vec_mem, offset, &data);
90 assert_eq!(vec_mem.size(), file_mem.size());
91 let mut buf = vec![0; (file_mem.size() * WASM_PAGE_SIZE) as usize];
92 file_mem.read(0, &mut buf);
93 assert_eq!(buf.as_slice(), vec_mem.borrow().as_slice());
94 });
95 }
96}