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}