linera_wasmer/
access.rs

1use std::mem::MaybeUninit;
2
3use crate::mem_access::{WasmRef, WasmSlice};
4
5pub(super) enum SliceCow<'a, T> {
6    #[allow(dead_code)]
7    Borrowed(&'a mut [T]),
8    #[allow(dead_code)]
9    Owned(Vec<T>, bool),
10}
11
12impl<'a, T> AsRef<[T]> for SliceCow<'a, T> {
13    fn as_ref(&self) -> &[T] {
14        match self {
15            Self::Borrowed(buf) => buf,
16            Self::Owned(buf, _) => buf,
17        }
18    }
19}
20
21impl<'a, T> AsMut<[T]> for SliceCow<'a, T> {
22    fn as_mut(&mut self) -> &mut [T] {
23        // Note: Zero padding is not required here as its a typed copy which does
24        //       not leak the bytes into the memory
25        // https://stackoverflow.com/questions/61114026/does-stdptrwrite-transfer-the-uninitialized-ness-of-the-bytes-it-writes
26        match self {
27            Self::Borrowed(buf) => buf,
28            Self::Owned(buf, modified) => {
29                *modified = true;
30                buf.as_mut()
31            }
32        }
33    }
34}
35
36/// Provides direct memory access to a piece of memory that
37/// is owned by WASM
38pub struct WasmSliceAccess<'a, T>
39where
40    T: wasmer_types::ValueType,
41{
42    pub(super) slice: WasmSlice<'a, T>,
43    pub(super) buf: SliceCow<'a, T>,
44}
45
46impl<'a, T> AsRef<[T]> for WasmSliceAccess<'a, T>
47where
48    T: wasmer_types::ValueType,
49{
50    fn as_ref(&self) -> &[T] {
51        self.buf.as_ref()
52    }
53}
54
55impl<'a, T> AsMut<[T]> for WasmSliceAccess<'a, T>
56where
57    T: wasmer_types::ValueType,
58{
59    fn as_mut(&mut self) -> &mut [T] {
60        self.buf.as_mut()
61    }
62}
63
64impl<'a, T> WasmSliceAccess<'a, T>
65where
66    T: wasmer_types::ValueType,
67{
68    /// Returns an iterator of all the elements in the slice
69    pub fn iter(&'a self) -> std::slice::Iter<'a, T> {
70        self.as_ref().iter()
71    }
72
73    /// Returns an iterator of all the elements in the slice
74    pub fn iter_mut(&'a mut self) -> std::slice::IterMut<'a, T> {
75        self.buf.as_mut().iter_mut()
76    }
77
78    /// Number of elements in this slice
79    pub fn len(&self) -> usize {
80        self.buf.as_ref().len()
81    }
82
83    /// If the slice is empty
84    pub fn is_empty(&self) -> bool {
85        self.buf.as_ref().is_empty()
86    }
87}
88
89impl<'a> WasmSliceAccess<'a, u8> {
90    /// Writes to the address pointed to by this `WasmPtr` in a memory.
91    #[inline]
92    pub fn copy_from_slice(&mut self, src: &[u8]) {
93        let dst = self.buf.as_mut();
94        dst.copy_from_slice(src);
95    }
96
97    /// Writes to the address pointed to by this `WasmPtr` in a memory.
98    ///
99    /// If the source buffer is smaller than the destination buffer
100    /// only the correct amount of bytes will be copied
101    ///
102    /// Returns the number of bytes copied
103    #[inline]
104    pub fn copy_from_slice_min(&mut self, src: &[u8]) -> usize {
105        let dst = self.buf.as_mut();
106        let amt = dst.len().min(src.len());
107        dst[..amt].copy_from_slice(&src[..amt]);
108        amt
109    }
110}
111
112impl<'a, T> Drop for WasmSliceAccess<'a, T>
113where
114    T: wasmer_types::ValueType,
115{
116    fn drop(&mut self) {
117        if let SliceCow::Owned(buf, modified) = &self.buf {
118            if *modified {
119                self.slice.write_slice(buf.as_ref()).ok();
120            }
121        }
122    }
123}
124
125pub(super) enum RefCow<'a, T> {
126    #[allow(dead_code)]
127    Borrowed(&'a mut T),
128    #[allow(dead_code)]
129    Owned(T, bool),
130}
131
132impl<'a, T> AsRef<T> for RefCow<'a, T> {
133    fn as_ref(&self) -> &T {
134        match self {
135            Self::Borrowed(val) => val,
136            Self::Owned(val, _) => val,
137        }
138    }
139}
140
141impl<'a, T> AsMut<T> for RefCow<'a, T> {
142    fn as_mut(&mut self) -> &mut T {
143        // Note: Zero padding is not required here as its a typed copy which does
144        //       not leak the bytes into the memory
145        // https://stackoverflow.com/questions/61114026/does-stdptrwrite-transfer-the-uninitialized-ness-of-the-bytes-it-writes
146        match self {
147            Self::Borrowed(val) => val,
148            Self::Owned(val, modified) => {
149                *modified = true;
150                val
151            }
152        }
153    }
154}
155
156/// Provides direct memory access to a piece of memory that
157/// is owned by WASM
158pub struct WasmRefAccess<'a, T>
159where
160    T: wasmer_types::ValueType,
161{
162    pub(super) ptr: WasmRef<'a, T>,
163    pub(super) buf: RefCow<'a, T>,
164}
165
166impl<'a, T> AsRef<T> for WasmRefAccess<'a, T>
167where
168    T: wasmer_types::ValueType,
169{
170    fn as_ref(&self) -> &T {
171        self.buf.as_ref()
172    }
173}
174
175impl<'a, T> AsMut<T> for WasmRefAccess<'a, T>
176where
177    T: wasmer_types::ValueType,
178{
179    fn as_mut(&mut self) -> &mut T {
180        self.buf.as_mut()
181    }
182}
183
184impl<'a, T> Drop for WasmRefAccess<'a, T>
185where
186    T: wasmer_types::ValueType,
187{
188    fn drop(&mut self) {
189        if let RefCow::Owned(val, modified) = &self.buf {
190            if *modified {
191                self.ptr.write(*val).ok();
192            }
193        }
194    }
195}
196
197impl<'a, T> WasmSliceAccess<'a, T>
198where
199    T: wasmer_types::ValueType,
200{
201    /// Returns a mutable slice that is not yet initialized
202    pub fn as_mut_uninit(&mut self) -> &mut [MaybeUninit<T>] {
203        let ret: &mut [T] = self.buf.as_mut();
204        let ret: &mut [MaybeUninit<T>] = unsafe { std::mem::transmute(ret) };
205        ret
206    }
207}
208
209impl<'a, T> WasmRefAccess<'a, T>
210where
211    T: wasmer_types::ValueType,
212{
213    /// Returns a reference to an unitialized reference to this value
214    pub fn as_mut_uninit(&mut self) -> &mut MaybeUninit<T> {
215        let ret: &mut T = self.buf.as_mut();
216        let ret: &mut MaybeUninit<T> = unsafe { std::mem::transmute(ret) };
217        ret
218    }
219}