|
1 | | -use core::cell::RefCell; |
| 1 | +use core::{ |
| 2 | + cell::{Ref, RefCell}, |
| 3 | + ffi::CStr, |
| 4 | +}; |
| 5 | + |
| 6 | +use crate::{GlobalInstance, MemoryInstance, Result}; |
| 7 | +use alloc::{ |
| 8 | + ffi::CString, |
| 9 | + rc::Rc, |
| 10 | + string::{String, ToString}, |
| 11 | + vec::Vec, |
| 12 | +}; |
| 13 | +use tinywasm_types::WasmValue; |
2 | 14 |
|
3 | | -use crate::{GlobalInstance, MemoryInstance}; |
4 | | -use alloc::rc::Rc; |
5 | 15 | // This module essentially contains the public APIs to interact with the data stored in the store |
6 | 16 |
|
7 | 17 | /// A reference to a memory instance |
8 | 18 | #[derive(Debug, Clone)] |
9 | 19 | pub struct MemoryRef { |
10 | | - pub(crate) _instance: Rc<RefCell<MemoryInstance>>, |
| 20 | + pub(crate) instance: Rc<RefCell<MemoryInstance>>, |
| 21 | +} |
| 22 | + |
| 23 | +/// A borrowed reference to a memory instance |
| 24 | +#[derive(Debug)] |
| 25 | +pub struct BorrowedMemory<'a> { |
| 26 | + pub(crate) instance: Ref<'a, MemoryInstance>, |
| 27 | +} |
| 28 | + |
| 29 | +impl<'a> BorrowedMemory<'a> { |
| 30 | + /// Load a slice of memory |
| 31 | + pub fn load(&self, offset: usize, len: usize) -> Result<&[u8]> { |
| 32 | + self.instance.load(offset, 0, len) |
| 33 | + } |
| 34 | + |
| 35 | + /// Load a C-style string from memory |
| 36 | + pub fn load_cstr(&self, offset: usize, len: usize) -> Result<&CStr> { |
| 37 | + let bytes = self.load(offset, len)?; |
| 38 | + CStr::from_bytes_with_nul(bytes).map_err(|_| crate::Error::Other("Invalid C-style string".to_string())) |
| 39 | + } |
| 40 | + |
| 41 | + /// Load a C-style string from memory, stopping at the first nul byte |
| 42 | + pub fn load_cstr_until_nul(&self, offset: usize, max_len: usize) -> Result<&CStr> { |
| 43 | + let bytes = self.load(offset, max_len)?; |
| 44 | + CStr::from_bytes_until_nul(bytes).map_err(|_| crate::Error::Other("Invalid C-style string".to_string())) |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +impl MemoryRef { |
| 49 | + /// Borrow the memory instance |
| 50 | + /// |
| 51 | + /// This is useful for when you want to load only a reference to a slice of memory |
| 52 | + /// without copying the data. The borrow should be dropped before any other memory |
| 53 | + /// operations are performed. |
| 54 | + pub fn borrow(&self) -> BorrowedMemory<'_> { |
| 55 | + BorrowedMemory { instance: self.instance.borrow() } |
| 56 | + } |
| 57 | + |
| 58 | + /// Load a slice of memory |
| 59 | + pub fn load_vec(&self, offset: usize, len: usize) -> Result<Vec<u8>> { |
| 60 | + self.instance.borrow().load(offset, 0, len).map(|x| x.to_vec()) |
| 61 | + } |
| 62 | + |
| 63 | + /// Grow the memory by the given number of pages |
| 64 | + pub fn grow(&self, delta_pages: i32) -> Option<i32> { |
| 65 | + self.instance.borrow_mut().grow(delta_pages) |
| 66 | + } |
| 67 | + |
| 68 | + /// Get the current size of the memory in pages |
| 69 | + pub fn page_count(&self) -> usize { |
| 70 | + self.instance.borrow().page_count() |
| 71 | + } |
| 72 | + |
| 73 | + /// Copy a slice of memory to another place in memory |
| 74 | + pub fn copy_within(&self, src: usize, dst: usize, len: usize) -> Result<()> { |
| 75 | + self.instance.borrow_mut().copy_within(src, dst, len) |
| 76 | + } |
| 77 | + |
| 78 | + /// Fill a slice of memory with a value |
| 79 | + pub fn fill(&self, offset: usize, len: usize, val: u8) -> Result<()> { |
| 80 | + self.instance.borrow_mut().fill(offset, len, val) |
| 81 | + } |
| 82 | + |
| 83 | + /// Load a UTF-8 string from memory |
| 84 | + pub fn load_string(&self, offset: usize, len: usize) -> Result<String> { |
| 85 | + let bytes = self.load_vec(offset, len)?; |
| 86 | + Ok(String::from_utf8(bytes).map_err(|_| crate::Error::Other("Invalid UTF-8 string".to_string()))?) |
| 87 | + } |
| 88 | + |
| 89 | + /// Load a C-style string from memory |
| 90 | + pub fn load_cstring(&self, offset: usize, len: usize) -> Result<CString> { |
| 91 | + Ok(CString::from(self.borrow().load_cstr(offset, len)?)) |
| 92 | + } |
| 93 | + |
| 94 | + /// Load a C-style string from memory, stopping at the first nul byte |
| 95 | + pub fn load_cstring_until_nul(&self, offset: usize, max_len: usize) -> Result<CString> { |
| 96 | + Ok(CString::from(self.borrow().load_cstr_until_nul(offset, max_len)?)) |
| 97 | + } |
| 98 | + |
| 99 | + /// Load a JavaScript-style utf-16 string from memory |
| 100 | + pub fn load_js_string(&self, offset: usize, len: usize) -> Result<String> { |
| 101 | + let memref = self.borrow(); |
| 102 | + let bytes = memref.load(offset, len)?; |
| 103 | + let mut string = String::new(); |
| 104 | + for i in 0..(len / 2) { |
| 105 | + let c = u16::from_le_bytes([bytes[i * 2], bytes[i * 2 + 1]]); |
| 106 | + string.push( |
| 107 | + char::from_u32(c as u32).ok_or_else(|| crate::Error::Other("Invalid UTF-16 string".to_string()))?, |
| 108 | + ); |
| 109 | + } |
| 110 | + Ok(string) |
| 111 | + } |
| 112 | + |
| 113 | + /// Store a slice of memory |
| 114 | + pub fn store(&self, offset: usize, len: usize, data: &[u8]) -> Result<()> { |
| 115 | + self.instance.borrow_mut().store(offset, 0, data, len) |
| 116 | + } |
11 | 117 | } |
12 | 118 |
|
13 | 119 | /// A reference to a global instance |
14 | 120 | #[derive(Debug, Clone)] |
15 | 121 | pub struct GlobalRef { |
16 | | - pub(crate) _instance: Rc<RefCell<GlobalInstance>>, |
| 122 | + pub(crate) instance: Rc<RefCell<GlobalInstance>>, |
| 123 | +} |
| 124 | + |
| 125 | +impl GlobalRef { |
| 126 | + /// Get the value of the global |
| 127 | + pub fn get(&self) -> WasmValue { |
| 128 | + self.instance.borrow().get() |
| 129 | + } |
| 130 | + |
| 131 | + /// Set the value of the global |
| 132 | + pub fn set(&self, val: WasmValue) -> Result<()> { |
| 133 | + self.instance.borrow_mut().set(val) |
| 134 | + } |
17 | 135 | } |
0 commit comments