pyodide_webassembly_runtime_layer/
store.rs1use std::{
2 fmt,
3 marker::PhantomData,
4 sync::{Arc, Weak},
5};
6
7use wasm_runtime_layer::backend::{
8 AsContext, AsContextMut, WasmStore, WasmStoreContext, WasmStoreContextMut,
9};
10use wobbly::sync::Wobbly;
11
12use crate::{func::PyHostFuncFn, Engine};
13
14pub struct Store<T> {
17 inner: Arc<StoreProof>,
56 _marker: PhantomData<T>,
58}
59
60struct StoreInner<T> {
62 engine: Engine,
64 data: T,
66 host_funcs: Vec<Wobbly<PyHostFuncFn>>,
69}
70
71impl<T> WasmStore<T, Engine> for Store<T> {
72 fn new(engine: &Engine, data: T) -> Self {
73 #[cfg(feature = "tracing")]
74 tracing::debug!("Store::new");
75
76 Self {
77 inner: Arc::new(StoreProof::from_ptr(Box::into_raw(Box::new(StoreInner {
78 engine: engine.clone(),
79 data,
80 host_funcs: Vec::new(),
81 })))),
82 _marker: PhantomData::<T>,
83 }
84 }
85
86 fn engine(&self) -> &Engine {
87 &self.as_inner().engine
88 }
89
90 fn data(&self) -> &T {
91 &self.as_inner().data
92 }
93
94 fn data_mut(&mut self) -> &mut T {
95 &mut self.as_inner_mut().data
96 }
97
98 fn into_data(self) -> T {
99 let this = std::mem::ManuallyDrop::new(self);
100
101 let inner = Arc::into_inner(unsafe { std::ptr::read(&this.inner) })
106 .expect("Store owns the only strong reference to StoreInner");
107
108 let inner = unsafe { Box::from_raw(inner.as_ptr()) };
112 inner.data
113 }
114}
115
116impl<T> AsContext<Engine> for Store<T> {
117 type UserState = T;
118
119 fn as_context(&self) -> StoreContext<'_, T> {
120 StoreContext {
121 store: self.as_inner(),
122 proof: &self.inner,
123 }
124 }
125}
126
127impl<T> AsContextMut<Engine> for Store<T> {
128 fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
129 let store = unsafe { &mut *self.inner.as_ptr() };
134
135 StoreContextMut {
136 store,
137 proof: &mut self.inner,
138 }
139 }
140}
141
142impl<T: fmt::Debug> fmt::Debug for Store<T> {
143 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
144 let store = self.as_inner();
145
146 fmt.debug_struct("Store")
147 .field("engine", &store.engine)
148 .field("data", &store.data)
149 .finish_non_exhaustive()
150 }
151}
152
153impl<T: Default> Default for Store<T> {
154 fn default() -> Self {
155 Self::new(&Engine::default(), T::default())
156 }
157}
158
159impl<T: Clone> Clone for Store<T> {
160 fn clone(&self) -> Self {
161 Self::new(self.engine(), self.data().clone())
162 }
163}
164
165impl<T> Drop for Store<T> {
166 fn drop(&mut self) {
167 std::mem::drop(unsafe { Box::from_raw(self.inner.as_ptr::<T>()) });
168
169 #[cfg(feature = "tracing")]
170 tracing::debug!("Store::drop");
171 }
172}
173
174impl<T> Store<T> {
175 fn as_inner(&self) -> &StoreInner<T> {
176 unsafe { &*self.inner.as_ptr() }
181 }
182
183 fn as_inner_mut(&mut self) -> &mut StoreInner<T> {
184 unsafe { &mut *self.inner.as_ptr() }
189 }
190}
191
192#[allow(clippy::module_name_repetitions)]
193pub struct StoreContext<'a, T: 'a> {
195 store: &'a StoreInner<T>,
197 proof: &'a Arc<StoreProof>,
199}
200
201#[allow(clippy::module_name_repetitions)]
202pub struct StoreContextMut<'a, T: 'a> {
204 store: &'a mut StoreInner<T>,
206 proof: &'a mut Arc<StoreProof>,
208}
209
210impl<'a, T: 'a> StoreContextMut<'a, T> {
211 #[allow(clippy::needless_pass_by_ref_mut)]
212 pub(crate) fn as_weak_proof(&mut self) -> Weak<StoreProof> {
217 Arc::downgrade(self.proof)
218 }
219
220 pub(crate) unsafe fn from_proof_unchecked(proof: &'a mut Arc<StoreProof>) -> Self {
231 Self {
232 store: unsafe { &mut *(proof.as_ptr()) },
233 proof,
234 }
235 }
236
237 pub(crate) fn register_host_func(&mut self, func: Arc<PyHostFuncFn>) -> Wobbly<PyHostFuncFn> {
238 let func = Wobbly::new(func);
239 self.store.host_funcs.push(func.clone());
240 func
241 }
242}
243
244impl<'a, T: 'a> WasmStoreContext<'a, T, Engine> for StoreContext<'a, T> {
245 fn engine(&self) -> &Engine {
246 &self.store.engine
247 }
248
249 fn data(&self) -> &T {
250 &self.store.data
251 }
252}
253
254impl<'a, T: 'a> AsContext<Engine> for StoreContext<'a, T> {
255 type UserState = T;
256
257 fn as_context(&self) -> StoreContext<'_, T> {
258 StoreContext {
259 store: self.store,
260 proof: self.proof,
261 }
262 }
263}
264
265impl<'a, T: 'a> WasmStoreContext<'a, T, Engine> for StoreContextMut<'a, T> {
266 fn engine(&self) -> &Engine {
267 &self.store.engine
268 }
269
270 fn data(&self) -> &T {
271 &self.store.data
272 }
273}
274
275impl<'a, T: 'a> WasmStoreContextMut<'a, T, Engine> for StoreContextMut<'a, T> {
276 fn data_mut(&mut self) -> &mut T {
277 &mut self.store.data
278 }
279}
280
281impl<'a, T: 'a> AsContext<Engine> for StoreContextMut<'a, T> {
282 type UserState = T;
283
284 fn as_context(&self) -> StoreContext<'_, T> {
285 StoreContext {
286 store: self.store,
287 proof: self.proof,
288 }
289 }
290}
291
292impl<'a, T: 'a> AsContextMut<Engine> for StoreContextMut<'a, T> {
293 fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
294 StoreContextMut {
295 store: self.store,
296 proof: self.proof,
297 }
298 }
299}
300
301#[allow(clippy::module_name_repetitions)]
302pub struct StoreProof(*mut ());
304
305unsafe impl Send for StoreProof {}
306unsafe impl Sync for StoreProof {}
307
308impl StoreProof {
309 const fn from_ptr<T>(ptr: *mut StoreInner<T>) -> Self {
310 Self(ptr.cast())
311 }
312
313 const fn as_ptr<T>(&self) -> *mut StoreInner<T> {
314 self.0.cast()
315 }
316}