linera_wasmer/externals/
memory_view.rs

1use super::memory::{Memory, MemoryBuffer};
2use crate::store::AsStoreRef;
3use crate::MemoryAccessError;
4use std::mem::MaybeUninit;
5use std::ops::Range;
6use wasmer_types::Pages;
7
8#[cfg(feature = "js")]
9use crate::js::externals::memory_view as memory_view_impl;
10#[cfg(feature = "jsc")]
11use crate::jsc::externals::memory_view as memory_view_impl;
12#[cfg(feature = "sys")]
13use crate::sys::externals::memory_view as memory_view_impl;
14
15/// A WebAssembly `memory` view.
16///
17/// A memory view is used to read and write to the linear memory.
18///
19/// After a memory is grown a view must not be used anymore. Views are
20/// created using the Memory.view() method.
21#[derive(Debug)]
22pub struct MemoryView<'a>(pub(crate) memory_view_impl::MemoryView<'a>);
23
24impl<'a> MemoryView<'a> {
25    pub(crate) fn new(memory: &Memory, store: &'a (impl AsStoreRef + ?Sized)) -> Self {
26        MemoryView(memory_view_impl::MemoryView::new(&memory.0, store))
27    }
28
29    /// Returns the pointer to the raw bytes of the `Memory`.
30    //
31    // This used by wasmer-emscripten and wasmer-c-api, but should be treated
32    // as deprecated and not used in future code.
33    #[doc(hidden)]
34    pub fn data_ptr(&self) -> *mut u8 {
35        self.0.data_ptr()
36    }
37
38    /// Returns the size (in bytes) of the `Memory`.
39    pub fn data_size(&self) -> u64 {
40        self.0.data_size()
41    }
42
43    /// Retrieve a slice of the memory contents.
44    ///
45    /// # Safety
46    ///
47    /// Until the returned slice is dropped, it is undefined behaviour to
48    /// modify the memory contents in any way including by calling a wasm
49    /// function that writes to the memory or by resizing the memory.
50    #[doc(hidden)]
51    pub unsafe fn data_unchecked(&self) -> &[u8] {
52        self.0.data_unchecked()
53    }
54
55    /// Retrieve a mutable slice of the memory contents.
56    ///
57    /// # Safety
58    ///
59    /// This method provides interior mutability without an UnsafeCell. Until
60    /// the returned value is dropped, it is undefined behaviour to read or
61    /// write to the pointed-to memory in any way except through this slice,
62    /// including by calling a wasm function that reads the memory contents or
63    /// by resizing this Memory.
64    #[allow(clippy::mut_from_ref)]
65    #[doc(hidden)]
66    pub unsafe fn data_unchecked_mut(&self) -> &mut [u8] {
67        self.0.data_unchecked_mut()
68    }
69
70    /// Returns the size (in [`Pages`]) of the `Memory`.
71    ///
72    /// # Example
73    ///
74    /// ```
75    /// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
76    /// # let mut store = Store::default();
77    /// #
78    /// let m = Memory::new(&mut store, MemoryType::new(1, None, false)).unwrap();
79    ///
80    /// assert_eq!(m.view(&mut store).size(), Pages(1));
81    /// ```
82    pub fn size(&self) -> Pages {
83        self.0.size()
84    }
85
86    #[inline]
87    pub(crate) fn buffer(&'a self) -> MemoryBuffer<'a> {
88        MemoryBuffer(self.0.buffer())
89    }
90
91    /// Safely reads bytes from the memory at the given offset.
92    ///
93    /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
94    /// to indicate an out-of-bounds access.
95    ///
96    /// This method is guaranteed to be safe (from the host side) in the face of
97    /// concurrent writes.
98    pub fn read(&self, offset: u64, buf: &mut [u8]) -> Result<(), MemoryAccessError> {
99        self.0.read(offset, buf)
100    }
101
102    /// Safely reads a single byte from memory at the given offset
103    ///
104    /// This method is guaranteed to be safe (from the host side) in the face of
105    /// concurrent writes.
106    pub fn read_u8(&self, offset: u64) -> Result<u8, MemoryAccessError> {
107        self.0.read_u8(offset)
108    }
109
110    /// Safely reads bytes from the memory at the given offset.
111    ///
112    /// This method is similar to `read` but allows reading into an
113    /// uninitialized buffer. An initialized view of the buffer is returned.
114    ///
115    /// The full buffer will be filled, otherwise a `MemoryAccessError` is returned
116    /// to indicate an out-of-bounds access.
117    ///
118    /// This method is guaranteed to be safe (from the host side) in the face of
119    /// concurrent writes.
120    pub fn read_uninit<'b>(
121        &self,
122        offset: u64,
123        buf: &'b mut [MaybeUninit<u8>],
124    ) -> Result<&'b mut [u8], MemoryAccessError> {
125        self.0.read_uninit(offset, buf)
126    }
127
128    /// Safely writes bytes to the memory at the given offset.
129    ///
130    /// If the write exceeds the bounds of the memory then a `MemoryAccessError` is
131    /// returned.
132    ///
133    /// This method is guaranteed to be safe (from the host side) in the face of
134    /// concurrent reads/writes.
135    pub fn write(&self, offset: u64, data: &[u8]) -> Result<(), MemoryAccessError> {
136        self.0.write(offset, data)
137    }
138
139    /// Safely writes a single byte from memory at the given offset
140    ///
141    /// This method is guaranteed to be safe (from the host side) in the face of
142    /// concurrent writes.
143    pub fn write_u8(&self, offset: u64, val: u8) -> Result<(), MemoryAccessError> {
144        self.0.write_u8(offset, val)
145    }
146
147    /// Copies the memory and returns it as a vector of bytes
148    pub fn copy_to_vec(&self) -> Result<Vec<u8>, MemoryAccessError> {
149        self.copy_range_to_vec(0..self.data_size())
150    }
151
152    /// Copies a range of the memory and returns it as a vector of bytes
153    pub fn copy_range_to_vec(&self, range: Range<u64>) -> Result<Vec<u8>, MemoryAccessError> {
154        let mut new_memory = Vec::new();
155        let mut offset = range.start;
156        let end = range.end.min(self.data_size());
157        let mut chunk = [0u8; 40960];
158        while offset < end {
159            let remaining = end - offset;
160            let sublen = remaining.min(chunk.len() as u64) as usize;
161            self.read(offset, &mut chunk[..sublen])?;
162            new_memory.extend_from_slice(&chunk[..sublen]);
163            offset += sublen as u64;
164        }
165        Ok(new_memory)
166    }
167
168    /// Copies the memory to another new memory object
169    pub fn copy_to_memory(&self, amount: u64, new_memory: &Self) -> Result<(), MemoryAccessError> {
170        let mut offset = 0;
171        let mut chunk = [0u8; 40960];
172        while offset < amount {
173            let remaining = amount - offset;
174            let sublen = remaining.min(chunk.len() as u64) as usize;
175            self.read(offset, &mut chunk[..sublen])?;
176
177            new_memory.write(offset, &chunk[..sublen])?;
178
179            offset += sublen as u64;
180        }
181        Ok(())
182    }
183}