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