wasmer/entities/store/
async_.rs

1use std::{fmt::Debug, marker::PhantomData};
2
3use crate::{
4    AsStoreMut, AsStoreRef, LocalRwLock, LocalRwLockReadGuard, LocalRwLockWriteGuard, Store,
5    StoreContext, StoreInner, StoreMut, StorePtrWrapper, StoreRef,
6};
7
8use wasmer_types::StoreId;
9
10/// A store that can be used to invoke
11/// [`Function::call_async`](crate::Function::call_async).
12pub struct StoreAsync {
13    pub(crate) id: StoreId,
14    // We use a box inside the RW lock because the StoreInner shouldn't be moved
15    pub(crate) inner: LocalRwLock<Box<StoreInner>>,
16}
17
18impl StoreAsync {
19    pub(crate) fn from_context(id: StoreId) -> Option<Self> {
20        // Safety: we don't keep the guard around, it's just used to
21        // build a safe lock handle.
22        match unsafe { StoreContext::try_get_current_async(id) } {
23            crate::GetStoreAsyncGuardResult::Ok(guard) => Some(Self {
24                id,
25                inner: crate::LocalRwLockWriteGuard::lock_handle(unsafe {
26                    guard.guard.as_ref().unwrap()
27                }),
28            }),
29            _ => None,
30        }
31    }
32
33    /// Transform this [`StoreAsync`] back into a [`Store`]
34    /// if this is the only clone of it and is unlocked.
35    pub fn into_store(self) -> Result<Store, Self> {
36        match self.inner.consume() {
37            Ok(unwrapped) => Ok(Store { inner: unwrapped }),
38            Err(lock) => Err(Self {
39                id: self.id,
40                inner: lock,
41            }),
42        }
43    }
44
45    /// Acquire a read lock on the store. Panics if the store is
46    /// locked for writing.
47    pub fn read(&self) -> StoreAsyncReadLock {
48        if !StoreContext::is_empty() {
49            panic!("This method cannot be called from inside imported functions");
50        }
51
52        let store_ref = self
53            .inner
54            .try_read()
55            .expect("StoreAsync is locked for write");
56        StoreAsyncReadLock { inner: store_ref }
57    }
58
59    /// Acquire a write lock on the store. Panics if the store is
60    /// locked.
61    pub fn write(self) -> StoreAsyncWriteLock {
62        if !StoreContext::is_empty() {
63            panic!("This method cannot be called from inside imported functions");
64        }
65
66        let store_guard = self.inner.try_write().expect("StoreAsync is locked");
67        StoreAsyncWriteLock { inner: store_guard }
68    }
69}
70
71impl Debug for StoreAsync {
72    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73        f.debug_struct("StoreAsync").field("id", &self.id).finish()
74    }
75}
76
77/// A trait for types that can be used with
78/// [`Function::call_async`](crate::Function::call_async).
79pub trait AsStoreAsync {
80    /// Returns a reference to the inner store.
81    fn store_ref(&self) -> &StoreAsync;
82
83    /// Returns a copy of the store.
84    fn store(&self) -> StoreAsync {
85        let store = self.store_ref();
86        StoreAsync {
87            id: store.id,
88            inner: store.inner.clone(),
89        }
90    }
91
92    /// Returns the store id.
93    fn store_id(&self) -> StoreId {
94        self.store().id
95    }
96
97    /// Acquires a read lock on the store.
98    fn read_lock(&self) -> impl Future<Output = StoreAsyncReadLock> {
99        StoreAsyncReadLock::acquire(self.store_ref())
100    }
101
102    /// Acquires a write lock on the store.
103    fn write_lock(&self) -> impl Future<Output = StoreAsyncWriteLock> {
104        StoreAsyncWriteLock::acquire(self.store_ref())
105    }
106}
107
108impl AsStoreAsync for StoreAsync {
109    fn store_ref(&self) -> &StoreAsync {
110        self
111    }
112}
113
114/// A read lock on an async store.
115pub struct StoreAsyncReadLock {
116    pub(crate) inner: LocalRwLockReadGuard<Box<StoreInner>>,
117}
118
119impl StoreAsyncReadLock {
120    pub(crate) async fn acquire(store: &StoreAsync) -> Self {
121        let store_ref = store.inner.read().await;
122        Self { inner: store_ref }
123    }
124}
125
126impl AsStoreRef for StoreAsyncReadLock {
127    fn as_store_ref(&self) -> StoreRef<'_> {
128        StoreRef { inner: &self.inner }
129    }
130}
131
132/// A write lock on an async store.
133pub struct StoreAsyncWriteLock {
134    pub(crate) inner: LocalRwLockWriteGuard<Box<StoreInner>>,
135}
136
137impl StoreAsyncWriteLock {
138    pub(crate) async fn acquire(store: &StoreAsync) -> Self {
139        let store_guard = store.inner.write().await;
140        Self { inner: store_guard }
141    }
142}
143
144impl AsStoreRef for StoreAsyncWriteLock {
145    fn as_store_ref(&self) -> StoreRef<'_> {
146        StoreRef { inner: &self.inner }
147    }
148}
149
150impl AsStoreMut for StoreAsyncWriteLock {
151    fn as_store_mut(&mut self) -> StoreMut<'_> {
152        StoreMut {
153            inner: &mut self.inner,
154        }
155    }
156
157    fn objects_mut(&mut self) -> &mut super::StoreObjects {
158        &mut self.inner.objects
159    }
160}