wasmer/backend/sys/entities/function/
env.rs

1use std::{any::Any, fmt::Debug, marker::PhantomData};
2
3#[cfg(feature = "experimental-async")]
4use crate::{AsStoreAsync, StoreAsync, StoreAsyncReadLock, StoreAsyncWriteLock};
5use crate::{
6    Store, StoreContext, StoreInner, StoreMut, StorePtrWrapper,
7    store::{AsStoreMut, AsStoreRef, StoreRef},
8};
9
10use wasmer_vm::{StoreHandle, StoreId, StoreObject, StoreObjects, VMFunctionEnvironment};
11
12#[derive(Debug)]
13#[repr(transparent)]
14/// An opaque reference to a function environment.
15/// The function environment data is owned by the `Store`.
16pub struct FunctionEnv<T> {
17    pub(crate) handle: StoreHandle<VMFunctionEnvironment>,
18    marker: PhantomData<T>,
19}
20
21impl<T: Any + Send + 'static + Sized> FunctionEnv<T> {
22    /// Make a new FunctionEnv
23    pub fn new(store: &mut impl AsStoreMut, value: T) -> Self {
24        Self {
25            handle: StoreHandle::new(
26                store.as_store_mut().objects_mut().as_sys_mut(),
27                VMFunctionEnvironment::new(value),
28            ),
29            marker: PhantomData,
30        }
31    }
32
33    #[allow(dead_code)] // This function is only used in js
34    pub(crate) fn from_handle(handle: StoreHandle<VMFunctionEnvironment>) -> Self {
35        Self {
36            handle,
37            marker: PhantomData,
38        }
39    }
40
41    /// Convert it into a `FunctionEnvMut`
42    pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<'_, T> {
43        FunctionEnvMut {
44            store_mut: store.as_store_mut(),
45            func_env: self,
46        }
47    }
48}
49
50impl<T: Any + 'static + Sized> FunctionEnv<T> {
51    /// Get the data as reference
52    pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T {
53        self.handle
54            .get(store.as_store_ref().objects().as_sys())
55            .as_ref()
56            .downcast_ref::<T>()
57            .unwrap()
58    }
59
60    /// Get the data as mutable
61    pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T {
62        self.handle
63            .get_mut(store.objects_mut().as_sys_mut())
64            .as_mut()
65            .downcast_mut::<T>()
66            .unwrap()
67    }
68}
69
70impl<T> crate::FunctionEnv<T> {
71    /// Consume self into [`crate::backend::sys::function::FunctionEnv`].
72    pub fn into_sys(self) -> FunctionEnv<T> {
73        match self.0 {
74            crate::BackendFunctionEnv::Sys(s) => s,
75            _ => panic!("Not a `sys` function env!"),
76        }
77    }
78
79    /// Convert a reference to self into a reference to [`crate::backend::sys::function::FunctionEnv`].
80    pub fn as_sys(&self) -> &FunctionEnv<T> {
81        match self.0 {
82            crate::BackendFunctionEnv::Sys(ref s) => s,
83            _ => panic!("Not a `sys` function env!"),
84        }
85    }
86
87    /// Convert a mutable reference to self into a mutable reference [`crate::backend::sys::function::FunctionEnv`].
88    pub fn as_sys_mut(&mut self) -> &mut FunctionEnv<T> {
89        match self.0 {
90            crate::BackendFunctionEnv::Sys(ref mut s) => s,
91            _ => panic!("Not a `sys` function env!"),
92        }
93    }
94}
95
96impl<T> PartialEq for FunctionEnv<T> {
97    fn eq(&self, other: &Self) -> bool {
98        self.handle == other.handle
99    }
100}
101
102impl<T> Eq for FunctionEnv<T> {}
103
104impl<T> std::hash::Hash for FunctionEnv<T> {
105    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
106        self.handle.hash(state);
107        self.marker.hash(state);
108    }
109}
110
111impl<T> Clone for FunctionEnv<T> {
112    fn clone(&self) -> Self {
113        Self {
114            handle: self.handle.clone(),
115            marker: self.marker,
116        }
117    }
118}
119
120/// A temporary handle to a [`FunctionEnv`].
121pub struct FunctionEnvMut<'a, T: 'a> {
122    pub(crate) store_mut: StoreMut<'a>,
123    pub(crate) func_env: FunctionEnv<T>,
124}
125
126impl<T> Debug for FunctionEnvMut<'_, T>
127where
128    T: Send + Debug + 'static,
129{
130    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131        self.func_env.as_ref(&self.store_mut).fmt(f)
132    }
133}
134
135impl<T: Send + 'static> FunctionEnvMut<'_, T> {
136    /// Returns a reference to the host state in this function environement.
137    pub fn data(&self) -> &T {
138        self.func_env.as_ref(&self.store_mut)
139    }
140
141    /// Returns a mutable- reference to the host state in this function environement.
142    pub fn data_mut(&mut self) -> &mut T {
143        self.func_env.as_mut(&mut self.store_mut)
144    }
145
146    /// Borrows a new immmutable reference
147    pub fn as_ref(&self) -> FunctionEnv<T> {
148        self.func_env.clone()
149    }
150
151    /// Borrows a new mutable reference
152    pub fn as_mut(&mut self) -> FunctionEnvMut<'_, T> {
153        FunctionEnvMut {
154            store_mut: self.store_mut.as_store_mut(),
155            func_env: self.func_env.clone(),
156        }
157    }
158
159    /// Borrows a new mutable reference of both the attached Store and host state
160    pub fn data_and_store_mut(&mut self) -> (&mut T, StoreMut<'_>) {
161        let data = self.func_env.as_mut(&mut self.store_mut) as *mut T;
162        // telling the borrow check to close his eyes here
163        // this is still relatively safe to do as func_env are
164        // stored in a specific vec of Store, separate from the other objects
165        // and not really directly accessible with the StoreMut
166        let data = unsafe { &mut *data };
167        (data, self.store_mut.as_store_mut())
168    }
169
170    /// Returns a [`StoreAsync`] if the current
171    /// context is asynchronous. The store will be locked since
172    /// it's already active in the current context, but can be used
173    /// to spawn new coroutines via
174    /// [`Function::call_async`](crate::Function::call_async).
175    #[cfg(feature = "experimental-async")]
176    pub fn as_store_async(&self) -> Option<impl AsStoreAsync + 'static> {
177        self.store_mut.as_store_async()
178    }
179}
180
181impl<T> AsStoreRef for FunctionEnvMut<'_, T> {
182    fn as_store_ref(&self) -> StoreRef<'_> {
183        StoreRef {
184            inner: self.store_mut.inner,
185        }
186    }
187}
188
189impl<T> AsStoreMut for FunctionEnvMut<'_, T> {
190    fn as_store_mut(&mut self) -> StoreMut<'_> {
191        StoreMut {
192            inner: self.store_mut.inner,
193        }
194    }
195
196    fn objects_mut(&mut self) -> &mut crate::StoreObjects {
197        self.store_mut.objects_mut()
198    }
199}
200
201impl<'a, T> From<FunctionEnvMut<'a, T>> for crate::FunctionEnvMut<'a, T> {
202    fn from(value: FunctionEnvMut<'a, T>) -> Self {
203        crate::FunctionEnvMut(crate::BackendFunctionEnvMut::Sys(value))
204    }
205}
206
207impl<T> From<FunctionEnv<T>> for crate::FunctionEnv<T> {
208    fn from(value: FunctionEnv<T>) -> Self {
209        Self(crate::BackendFunctionEnv::Sys(value))
210    }
211}
212
213/// A shared handle to a [`FunctionEnv`], suitable for use
214/// in async imports.
215#[cfg(feature = "experimental-async")]
216pub struct AsyncFunctionEnvMut<T> {
217    pub(crate) store: AsyncFunctionEnvMutStore,
218    pub(crate) func_env: FunctionEnv<T>,
219}
220
221// We need to let async functions that *don't suspend* run
222// in a sync context. To that end, `AsyncFunctionEnvMut`
223// must be able to be constructed without an actual
224// StoreAsync instance, hence this enum.
225#[cfg(feature = "experimental-async")]
226pub(crate) enum AsyncFunctionEnvMutStore {
227    Async(StoreAsync),
228    Sync(StorePtrWrapper),
229}
230
231/// A read-only handle to the [`FunctionEnv`] in an [`AsyncFunctionEnvMut`].
232#[cfg(feature = "experimental-async")]
233pub struct AsyncFunctionEnvHandle<T> {
234    read_lock: StoreAsyncReadLock,
235    pub(crate) func_env: FunctionEnv<T>,
236}
237
238/// A mutable handle to the [`FunctionEnv`] in an [`AsyncFunctionEnvMut`].
239#[cfg(feature = "experimental-async")]
240pub struct AsyncFunctionEnvHandleMut<T> {
241    write_lock: StoreAsyncWriteLock,
242    pub(crate) func_env: FunctionEnv<T>,
243}
244
245#[cfg(feature = "experimental-async")]
246impl<T> Debug for AsyncFunctionEnvMut<T>
247where
248    T: Send + Debug + 'static,
249{
250    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
251        match &self.store {
252            AsyncFunctionEnvMutStore::Sync(ptr) => self.func_env.as_ref(&ptr.as_ref()).fmt(f),
253            AsyncFunctionEnvMutStore::Async(store) => match store.inner.try_read() {
254                Some(read_lock) => self.func_env.as_ref(&read_lock).fmt(f),
255                None => write!(f, "AsyncFunctionEnvMut {{ <STORE LOCKED> }}"),
256            },
257        }
258    }
259}
260
261#[cfg(feature = "experimental-async")]
262impl<T: 'static> AsyncFunctionEnvMut<T> {
263    pub(crate) fn store_id(&self) -> StoreId {
264        match &self.store {
265            AsyncFunctionEnvMutStore::Sync(ptr) => ptr.as_ref().objects().id(),
266            AsyncFunctionEnvMutStore::Async(store) => store.id,
267        }
268    }
269
270    /// Waits for a store lock and returns a read-only handle to the
271    /// function environment.
272    pub async fn read(&self) -> AsyncFunctionEnvHandle<T> {
273        let read_lock = match &self.store {
274            AsyncFunctionEnvMutStore::Async(store) => store.read_lock().await,
275
276            // We can never acquire a store lock in a sync context
277            AsyncFunctionEnvMutStore::Sync(_) => futures::future::pending().await,
278        };
279
280        AsyncFunctionEnvHandle {
281            read_lock,
282            func_env: self.func_env.clone(),
283        }
284    }
285
286    /// Waits for a store lock and returns a mutable handle to the
287    /// function environment.
288    pub async fn write(&self) -> AsyncFunctionEnvHandleMut<T> {
289        let write_lock = match &self.store {
290            AsyncFunctionEnvMutStore::Async(store) => store.write_lock().await,
291
292            // We can never acquire a store lock in a sync context
293            AsyncFunctionEnvMutStore::Sync(_) => futures::future::pending().await,
294        };
295
296        AsyncFunctionEnvHandleMut {
297            write_lock,
298            func_env: self.func_env.clone(),
299        }
300    }
301
302    /// Borrows a new immmutable reference
303    pub fn as_ref(&self) -> FunctionEnv<T> {
304        self.func_env.clone()
305    }
306
307    /// Borrows a new mutable reference
308    pub fn as_mut(&mut self) -> Self {
309        self.clone()
310    }
311
312    /// Creates an [`AsStoreAsync`] from this [`AsyncFunctionEnvMut`].
313    pub fn as_store_async(&self) -> impl AsStoreAsync + 'static {
314        match &self.store {
315            AsyncFunctionEnvMutStore::Sync(_) => {
316                panic!("Cannot build a StoreAsync within a sync context")
317            }
318            AsyncFunctionEnvMutStore::Async(store) => StoreAsync {
319                id: store.id,
320                inner: store.inner.clone(),
321            },
322        }
323    }
324}
325
326#[cfg(feature = "experimental-async")]
327impl<T> Clone for AsyncFunctionEnvMut<T> {
328    fn clone(&self) -> Self {
329        Self {
330            store: self.store.clone(),
331            func_env: self.func_env.clone(),
332        }
333    }
334}
335
336#[cfg(feature = "experimental-async")]
337impl Clone for AsyncFunctionEnvMutStore {
338    fn clone(&self) -> Self {
339        match self {
340            Self::Async(store) => Self::Async(StoreAsync {
341                id: store.id,
342                inner: store.inner.clone(),
343            }),
344            Self::Sync(ptr) => Self::Sync(ptr.clone()),
345        }
346    }
347}
348
349#[cfg(feature = "experimental-async")]
350impl<T: 'static> AsyncFunctionEnvHandle<T> {
351    /// Returns a reference to the host state in this function environment.
352    pub fn data(&self) -> &T {
353        self.func_env.as_ref(&self.read_lock)
354    }
355
356    /// Returns both the host state and the attached StoreRef
357    pub fn data_and_store(&self) -> (&T, &impl AsStoreRef) {
358        (self.data(), &self.read_lock)
359    }
360}
361
362#[cfg(feature = "experimental-async")]
363impl<T: 'static> AsStoreRef for AsyncFunctionEnvHandle<T> {
364    fn as_store_ref(&self) -> StoreRef<'_> {
365        AsStoreRef::as_store_ref(&self.read_lock)
366    }
367}
368
369#[cfg(feature = "experimental-async")]
370impl<T: 'static> AsyncFunctionEnvHandleMut<T> {
371    /// Returns a mutable reference to the host state in this function environment.
372    pub fn data_mut(&mut self) -> &mut T {
373        self.func_env.as_mut(&mut self.write_lock)
374    }
375
376    /// Returns both the host state and the attached StoreMut
377    pub fn data_and_store_mut(&mut self) -> (&mut T, &mut impl AsStoreMut) {
378        let data = self.data_mut() as *mut T;
379        // Wisdom of the ancients:
380        // telling the borrow check to close his eyes here
381        // this is still relatively safe to do as func_env are
382        // stored in a specific vec of Store, separate from the other objects
383        // and not really directly accessible with the StoreMut
384        let data = unsafe { &mut *data };
385        (data, &mut self.write_lock)
386    }
387
388    /// Borrows a new [`FunctionEnvMut`] from this [`AsyncFunctionEnvHandleMut`].
389    pub fn as_function_env_mut(&mut self) -> FunctionEnvMut<'_, T> {
390        FunctionEnvMut {
391            store_mut: self.write_lock.as_store_mut(),
392            func_env: self.func_env.clone(),
393        }
394    }
395}
396
397#[cfg(feature = "experimental-async")]
398impl<T: 'static> AsStoreRef for AsyncFunctionEnvHandleMut<T> {
399    fn as_store_ref(&self) -> StoreRef<'_> {
400        AsStoreRef::as_store_ref(&self.write_lock)
401    }
402}
403
404#[cfg(feature = "experimental-async")]
405impl<T: 'static> AsStoreMut for AsyncFunctionEnvHandleMut<T> {
406    fn as_store_mut(&mut self) -> StoreMut<'_> {
407        AsStoreMut::as_store_mut(&mut self.write_lock)
408    }
409
410    fn objects_mut(&mut self) -> &mut crate::StoreObjects {
411        AsStoreMut::objects_mut(&mut self.write_lock)
412    }
413}