wasm_dbms_memory/
provider.rs1use wasm_dbms_api::prelude::{MemoryError, MemoryResult};
4
5pub const WASM_PAGE_SIZE: u64 = 65536;
7
8pub trait MemoryProvider {
13 const PAGE_SIZE: u64;
15
16 fn size(&self) -> u64;
18
19 fn pages(&self) -> u64;
21
22 fn grow(&mut self, new_pages: u64) -> MemoryResult<u64>;
28
29 fn read(&mut self, offset: u64, buf: &mut [u8]) -> MemoryResult<()>;
33
34 fn write(&mut self, offset: u64, buf: &[u8]) -> MemoryResult<()>;
38
39 fn flush(&mut self) -> MemoryResult<()> {
45 Ok(())
46 }
47}
48
49#[derive(Debug, Default)]
51pub struct HeapMemoryProvider {
52 memory: Vec<u8>,
53}
54
55impl HeapMemoryProvider {
56 fn checked_range(&self, offset: u64, len: usize) -> MemoryResult<std::ops::Range<usize>> {
63 let end = offset
64 .checked_add(len as u64)
65 .filter(|end| *end <= self.size())
66 .ok_or(MemoryError::OutOfBounds)?;
67 Ok(offset as usize..end as usize)
69 }
70}
71
72impl MemoryProvider for HeapMemoryProvider {
73 const PAGE_SIZE: u64 = WASM_PAGE_SIZE; fn grow(&mut self, new_pages: u64) -> MemoryResult<u64> {
76 let previous_size = self.size();
77 let new_size = new_pages
78 .checked_mul(Self::PAGE_SIZE)
79 .and_then(|additional| previous_size.checked_add(additional))
80 .and_then(|size| usize::try_from(size).ok())
81 .ok_or(MemoryError::FailedToAllocatePage)?;
82 self.memory
83 .try_reserve_exact(new_size - self.memory.len())
84 .map_err(|_| MemoryError::FailedToAllocatePage)?;
85 self.memory.resize(new_size, 0);
86 Ok(previous_size)
87 }
88
89 fn size(&self) -> u64 {
90 self.memory.len() as u64
91 }
92
93 fn pages(&self) -> u64 {
94 self.size() / Self::PAGE_SIZE
95 }
96
97 fn read(&mut self, offset: u64, buf: &mut [u8]) -> MemoryResult<()> {
98 let range = self.checked_range(offset, buf.len())?;
99 buf.copy_from_slice(&self.memory[range]);
100 Ok(())
101 }
102
103 fn write(&mut self, offset: u64, buf: &[u8]) -> MemoryResult<()> {
104 let range = self.checked_range(offset, buf.len())?;
105 self.memory[range].copy_from_slice(buf);
106 Ok(())
107 }
108}
109
110#[cfg(test)]
111mod tests {
112
113 use super::*;
114
115 #[test]
116 fn test_should_grow_heap_memory() {
117 let mut provider = HeapMemoryProvider::default();
118 assert_eq!(provider.size(), 0);
119
120 let previous_size = provider.grow(2).unwrap();
121 assert_eq!(previous_size, 0);
122 assert_eq!(provider.size(), 2 * HeapMemoryProvider::PAGE_SIZE);
123
124 let previous_size = provider.grow(1).unwrap();
125 assert_eq!(previous_size, 2 * HeapMemoryProvider::PAGE_SIZE);
126 assert_eq!(provider.size(), 3 * HeapMemoryProvider::PAGE_SIZE);
127 }
128
129 #[test]
130 fn test_should_read_and_write_heap_memory() {
131 let mut provider = HeapMemoryProvider::default();
132 provider.grow(1).unwrap(); let data_to_write = vec![1, 2, 3, 4, 5];
134 provider.write(0, &data_to_write).unwrap();
135 let mut buffer = vec![0; 5];
136 provider.read(0, &mut buffer).unwrap();
137 assert_eq!(buffer, data_to_write);
138 }
139
140 #[test]
141 fn test_should_not_read_out_of_bounds_heap_memory() {
142 let mut provider = HeapMemoryProvider::default();
143 provider.grow(1).unwrap(); let mut buffer = vec![0; 10];
145 let result = provider.read(HeapMemoryProvider::PAGE_SIZE - 5, &mut buffer);
146 assert!(result.is_err());
147 assert!(matches!(result.err().unwrap(), MemoryError::OutOfBounds));
148 }
149
150 #[test]
151 fn test_should_not_write_out_of_bounds_heap_memory() {
152 let mut provider = HeapMemoryProvider::default();
153 provider.grow(1).unwrap(); let data_to_write = vec![1, 2, 3, 4, 5];
155 let result = provider.write(HeapMemoryProvider::PAGE_SIZE - 3, &data_to_write);
156 assert!(result.is_err());
157 assert!(matches!(result.err().unwrap(), MemoryError::OutOfBounds));
158 }
159
160 #[test]
161 fn test_should_reject_extreme_offsets_heap_memory() {
162 let mut provider = HeapMemoryProvider::default();
163 provider.grow(1).unwrap();
164
165 let mut buf = [0u8; 1];
166 assert!(matches!(
167 provider.read(u64::MAX, &mut buf),
168 Err(MemoryError::OutOfBounds)
169 ));
170 assert!(matches!(
171 provider.write(u64::MAX, &[1]),
172 Err(MemoryError::OutOfBounds)
173 ));
174 }
175
176 #[test]
177 fn test_should_reject_overflowing_growth_heap_memory() {
178 let mut provider = HeapMemoryProvider::default();
179 assert!(provider.grow(u64::MAX).is_err());
180 assert_eq!(provider.size(), 0);
181 }
182
183 #[test]
184 fn test_grow_returns_error_when_allocation_fails() {
185 let mut provider = HeapMemoryProvider::default();
186 provider.grow(1).unwrap();
187
188 assert!(provider.grow(1 << 40).is_err());
190 assert_eq!(provider.size(), HeapMemoryProvider::PAGE_SIZE);
191 }
192
193 #[test]
194 fn test_should_get_amount_of_pages_heap_memory() {
195 let mut provider = HeapMemoryProvider::default();
196 assert_eq!(provider.pages(), 0);
197
198 provider.grow(3).unwrap(); assert_eq!(provider.pages(), 3);
200
201 provider.grow(2).unwrap(); assert_eq!(provider.pages(), 5);
203 }
204}