wasm/execution/checked/
mod.rs

1//! Definitions for checked, safe variants of methods defined on [`Store`] and
2//! [`Linker`].
3//!
4//! This module defines extensions in the form of new types and new methods. It
5//! only relies on the fact that the [`Store`] and the [`Linker`] both store a
6//! [`StoreId`]. No other changes are required to be made to the main
7//! interpreter for this checked API.
8//!
9//!
10//! All extension methods defined in this module use special _stored_ objects.
11//! These objects are essentially normal objects like [`FuncAddr`], [`RunState`]
12//! or [`Value`](crate::execution::Value). However, they also contain an
13//! additional field of type [`StoreId`] as a tag to know to which [`Store`]
14//! they belong to.
15//!
16//! While this is easy for address types like [`FuncAddr`] or [`MemAddr`], some
17//! types are enums and their variants are visible to the user. For example,
18//! consider the [`Value`](crate::execution::Value) enum, where users have full
19//! access to all of its variants. To be able to attach a tag only to the
20//! [`Value::Ref`](crate::execution::Value::Ref) variant of this enum, the
21//! entire enum has to be re-defined. The result is a completely new type
22//! [`StoredValue`].
23
24use core::num::NonZeroU32;
25
26use crate::{
27    addrs::{FuncAddr, GlobalAddr, MemAddr, ModuleAddr, TableAddr},
28    config::Config,
29    core::reader::types::{FuncType, MemType, TableType},
30    linker::Linker,
31    resumable::{ResumableRef, RunState},
32    ExternVal, GlobalType, InstantiationOutcome, RuntimeError, Store, StoreId, ValidationInfo,
33};
34use alloc::{string::String, vec::Vec};
35
36mod interop;
37mod value;
38
39pub use interop::*;
40pub use value::*;
41
42// All functions in this impl block must occur in the same order as they are
43// defined in for the unchecked `Store` methods. Also all functions must follow
44// the same implementation scheme to make sure they are only light wrappers:
45//
46// 1. try unwrap [stored parameter objects]
47// 2. call [unchecked method]
48// 3. rewrap [results into stored objects]
49// 4. return [stored result objects]
50impl<'b, T: Config> Store<'b, T> {
51    // `fn new_checked` is missing, because it does not interact with any stored
52    // objects.
53
54    /// This is a safe variant of [`Store::module_instantiate_unchecked`].
55    pub fn module_instantiate(
56        &mut self,
57        validation_info: &ValidationInfo<'b>,
58        extern_vals: Vec<StoredExternVal>,
59        maybe_fuel: Option<u32>,
60    ) -> Result<StoredInstantiationOutcome, RuntimeError> {
61        // 1. try unwrap
62        let extern_vals = extern_vals
63            .into_iter()
64            .map(|extern_val| extern_val.try_unwrap_into_bare(self.id))
65            .collect::<Result<Vec<ExternVal>, RuntimeError>>()?;
66        // 2. call
67        let instantiation_outcome =
68            self.module_instantiate_unchecked(validation_info, extern_vals, maybe_fuel)?;
69        // 3. rewrap
70        // Safety: The `InstantiationOutcome` just came from the current store.
71        let stored_instantiation_outcome =
72            unsafe { StoredInstantiationOutcome::from_bare(instantiation_outcome, self.id) };
73        // 4. return
74        Ok(stored_instantiation_outcome)
75    }
76
77    /// This is a safe variant of [`Store::instance_export_unchecked`].
78    pub fn instance_export(
79        &self,
80        module_addr: Stored<ModuleAddr>,
81        name: &str,
82    ) -> Result<StoredExternVal, RuntimeError> {
83        // 1. try unwrap
84        let module_addr = module_addr.try_unwrap_into_bare(self.id)?;
85        // 2. call
86        let extern_val = self.instance_export_unchecked(module_addr, name)?;
87        // 3. rewrap
88        // Safety: The `ExternVal` just came from the current store.
89        let stored_extern_val = unsafe { StoredExternVal::from_bare(extern_val, self.id) };
90        // 4. return
91        Ok(stored_extern_val)
92    }
93
94    // `fn func_alloc` is missing, because it would require changes in the core
95    // interpreter.
96
97    /// This is a safe variant of [`Store::func_type_unchecked`].
98    pub fn func_type(&self, func_addr: Stored<FuncAddr>) -> Result<FuncType, RuntimeError> {
99        // 1. try unwrap
100        let func_addr = func_addr.try_unwrap_into_bare(self.id)?;
101        // 2. call
102        let func_type = self.func_type_unchecked(func_addr);
103        // 3. rewrap
104        // `FuncType` does not have a stored variant.
105        // 4. return
106        Ok(func_type)
107    }
108
109    /// This is a safe variant of [`Store::invoke_unchecked`].
110    pub fn invoke(
111        &mut self,
112        func_addr: Stored<FuncAddr>,
113        params: Vec<StoredValue>,
114        maybe_fuel: Option<u32>,
115    ) -> Result<StoredRunState, RuntimeError> {
116        // 1. try unwrap
117        let func_addr = func_addr.try_unwrap_into_bare(self.id)?;
118        let params = try_unwrap_values(params, self.id)?;
119        // 2. call
120        let run_state = self.invoke_unchecked(func_addr, params, maybe_fuel)?;
121        // 3. rewrap
122        // Safety: The `RunState` just came from the current store.
123        let stored_run_state = unsafe { StoredRunState::from_bare(run_state, self.id) };
124        // 4. return
125        Ok(stored_run_state)
126    }
127
128    /// This is a safe variant of [`Store::table_alloc_unchecked`].
129    pub fn table_alloc(
130        &mut self,
131        table_type: TableType,
132        r#ref: StoredRef,
133    ) -> Result<Stored<TableAddr>, RuntimeError> {
134        // 1. try unwrap
135        let r#ref = r#ref.try_unwrap_into_bare(self.id)?;
136        // 2. call
137        let table_addr = self.table_alloc_unchecked(table_type, r#ref)?;
138        // 3. rewrap
139        // Safety: The `TableAddr` just came from the current store.
140        let stored_table_addr = unsafe { Stored::from_bare(table_addr, self.id) };
141        // 4. return
142        Ok(stored_table_addr)
143    }
144
145    /// This is a safe variant of [`Store::table_type_unchecked`].
146    pub fn table_type(&self, table_addr: Stored<TableAddr>) -> Result<TableType, RuntimeError> {
147        // 1. try unwrap
148        let table_addr = table_addr.try_unwrap_into_bare(self.id)?;
149        // 2. call
150        let table_type = self.table_type_unchecked(table_addr);
151        // 3. rewrap
152        // `TableType` has no stored variant.
153        // 4. return
154        Ok(table_type)
155    }
156
157    /// This is a safe variant of [`Store::table_read_unchecked`].
158    pub fn table_read(
159        &self,
160        table_addr: Stored<TableAddr>,
161        i: u32,
162    ) -> Result<StoredRef, RuntimeError> {
163        // 1. try unwrap
164        let table_addr = table_addr.try_unwrap_into_bare(self.id)?;
165        // 2. call
166        let r#ref = self.table_read_unchecked(table_addr, i)?;
167        // 3. rewrap
168        // Safety: The `Ref` ust came from the current store.
169        let stored_ref = unsafe { StoredRef::from_bare(r#ref, self.id) };
170        // 4. return
171        Ok(stored_ref)
172    }
173
174    /// This is a safe variant of [`Store::table_write_unchecked`].
175    pub fn table_write(
176        &mut self,
177        table_addr: Stored<TableAddr>,
178        i: u32,
179        r#ref: StoredRef,
180    ) -> Result<(), RuntimeError> {
181        // 1. try unwrap
182        let table_addr = table_addr.try_unwrap_into_bare(self.id)?;
183        let r#ref = r#ref.try_unwrap_into_bare(self.id)?;
184        // 2. call
185        self.table_write_unchecked(table_addr, i, r#ref)?;
186        // 3. rewrap
187        // result is the unit type.
188        // 4. return
189        Ok(())
190    }
191
192    /// This is a safe variant of [`Store::table_size_unchecked`].
193    pub fn table_size(&self, table_addr: Stored<TableAddr>) -> Result<u32, RuntimeError> {
194        // 1. try unwrap
195        let table_addr = table_addr.try_unwrap_into_bare(self.id)?;
196        // 2. call
197        let table_size = self.table_size_unchecked(table_addr);
198        // 3. rewrap
199        // table size has no stored variant.
200        // 4. return
201        Ok(table_size)
202    }
203
204    /// This is a safe variant of [`Store::mem_alloc_unchecked`].
205    #[allow(clippy::let_and_return)] // reason = "to follow the 1234 structure"
206    pub fn mem_alloc(&mut self, mem_type: MemType) -> Stored<MemAddr> {
207        // 1. try unwrap
208        // no stored parameters
209        // 2. call
210        let mem_addr = self.mem_alloc_unchecked(mem_type);
211        // 3. rewrap
212        // Safety: The `MemAddr` just came from the current store.
213        let stored_mem_addr = unsafe { Stored::from_bare(mem_addr, self.id) };
214        // 4. return
215        stored_mem_addr
216    }
217
218    /// This is a safe variant of [`Store::mem_type_unchecked`].
219    pub fn mem_type(&self, mem_addr: Stored<MemAddr>) -> Result<MemType, RuntimeError> {
220        // 1. try unwrap
221        let mem_addr = mem_addr.try_unwrap_into_bare(self.id)?;
222        // 2. call
223        let mem_type = self.mem_type_unchecked(mem_addr);
224        // 3. rewrap
225        // `MemType` does not have a stored variant.
226        // 4. return
227        Ok(mem_type)
228    }
229
230    /// This is a safe variant of [`Store::mem_read_unchecked`].
231    pub fn mem_read(&self, mem_addr: Stored<MemAddr>, i: u32) -> Result<u8, RuntimeError> {
232        // 1. try unwrap
233        let mem_addr = mem_addr.try_unwrap_into_bare(self.id)?;
234        // 2. call
235        let byte = self.mem_read_unchecked(mem_addr, i)?;
236        // 3. rewrap
237        // a single byte does not have a stored variant.
238        // 4. return
239        Ok(byte)
240    }
241
242    /// This is a safe variant of [`Store::mem_write_unchecked`].
243    pub fn mem_write(
244        &mut self,
245        mem_addr: Stored<MemAddr>,
246        i: u32,
247        byte: u8,
248    ) -> Result<(), RuntimeError> {
249        // 1. try unwrap
250        let mem_addr = mem_addr.try_unwrap_into_bare(self.id)?;
251        // 2. call
252        self.mem_write_unchecked(mem_addr, i, byte)?;
253        // 3. rewrap
254        // result is the unit type.
255        // 4. return
256        Ok(())
257    }
258
259    /// This is a safe variant of [`Store::mem_size_unchecked`].
260    pub fn mem_size(&self, mem_addr: Stored<MemAddr>) -> Result<u32, RuntimeError> {
261        // 1. try unwrap
262        let mem_addr = mem_addr.try_unwrap_into_bare(self.id)?;
263        // 2. call
264        let mem_size = self.mem_size_unchecked(mem_addr);
265        // 3. rewrap
266        // mem size does not have a stored variant.
267        // 4. return
268        Ok(mem_size)
269    }
270
271    /// This is a safe variant of [`Store::mem_grow_unchecked`].
272    pub fn mem_grow(&mut self, mem_addr: Stored<MemAddr>, n: u32) -> Result<(), RuntimeError> {
273        // 1. try unwrap
274        let mem_addr = mem_addr.try_unwrap_into_bare(self.id)?;
275        // 2. call
276        self.mem_grow_unchecked(mem_addr, n)?;
277        // 3. rewrap
278        // result is the unit type.
279        // 4. return
280        Ok(())
281    }
282
283    /// This is a safe variant of [`Store::global_alloc_unchecked`].
284    pub fn global_alloc(
285        &mut self,
286        global_type: GlobalType,
287        val: StoredValue,
288    ) -> Result<Stored<GlobalAddr>, RuntimeError> {
289        // 1. try unwrap
290        let val = val.try_unwrap_into_bare(self.id)?;
291        // 2. call
292        let global_addr = self.global_alloc_unchecked(global_type, val)?;
293        // 3. rewrap
294        // Safety: The `GlobalAddr` just came from the current store.
295        let stored_global_addr = unsafe { Stored::from_bare(global_addr, self.id) };
296        // 4. return
297        Ok(stored_global_addr)
298    }
299
300    /// This is a safe variant of [`Store::global_type_unchecked`].
301    pub fn global_type(&self, global_addr: Stored<GlobalAddr>) -> Result<GlobalType, RuntimeError> {
302        // 1. try unwrap
303        let global_addr = global_addr.try_unwrap_into_bare(self.id)?;
304        // 2. call
305        let global_type = self.global_type_unchecked(global_addr);
306        // 3. rewrap
307        // `GlobalType` does not have a stored variant.
308        // 4. return
309        Ok(global_type)
310    }
311
312    /// This is a safe variant of [`Store::global_read_unchecked`].
313    pub fn global_read(
314        &self,
315        global_addr: Stored<GlobalAddr>,
316    ) -> Result<StoredValue, RuntimeError> {
317        // 1. try unwrap
318        let global_addr = global_addr.try_unwrap_into_bare(self.id)?;
319        // 2. call
320        let value = self.global_read_unchecked(global_addr);
321        // 3. rewrap
322        // Safety: The `Value` just came from the current store.
323        let stored_value = unsafe { StoredValue::from_bare(value, self.id) };
324        // 4. return
325        Ok(stored_value)
326    }
327
328    /// This is a safe variant of [`Store::global_write_unchecked`].
329    pub fn global_write(
330        &mut self,
331        global_addr: Stored<GlobalAddr>,
332        val: StoredValue,
333    ) -> Result<(), RuntimeError> {
334        // 1. try unwrap
335        let global_addr = global_addr.try_unwrap_into_bare(self.id)?;
336        let val = val.try_unwrap_into_bare(self.id)?;
337        // 2. call
338        self.global_write_unchecked(global_addr, val)?;
339        // 3. rewrap
340        // result is the unit type.
341        // 4. return
342        Ok(())
343    }
344
345    /// This is a safe variant of [`Store::create_resumable_unchecked`].
346    pub fn create_resumable(
347        &self,
348        func_addr: Stored<FuncAddr>,
349        params: Vec<StoredValue>,
350        maybe_fuel: Option<u32>,
351    ) -> Result<Stored<ResumableRef>, RuntimeError> {
352        // 1. try unwrap
353        let func_addr = func_addr.try_unwrap_into_bare(self.id)?;
354        let params = try_unwrap_values(params, self.id)?;
355        // 2. call
356        let resumable_ref = self.create_resumable_unchecked(func_addr, params, maybe_fuel)?;
357        // 3. rewrap
358        // Safety: The `ResumableRef` just came from the current store.
359        let stored_resumable_ref = unsafe { Stored::from_bare(resumable_ref, self.id) };
360        // 4. return
361        Ok(stored_resumable_ref)
362    }
363
364    /// This is a safe variant of [`Store::resume_unchecked`].
365    pub fn resume(
366        &mut self,
367        resumable_ref: Stored<ResumableRef>,
368    ) -> Result<StoredRunState, RuntimeError> {
369        // 1. try unwrap
370        let resumable_ref = resumable_ref.try_unwrap_into_bare(self.id)?;
371        // 2. call
372        let run_state = self.resume_unchecked(resumable_ref)?;
373        // 3. rewrap
374        // Safety: The `RunState` just came from the current store.
375        let stored_run_state = unsafe { StoredRunState::from_bare(run_state, self.id) };
376        // 4. return
377        Ok(stored_run_state)
378    }
379
380    /// This is a safe variant of [`Store::access_fuel_mut_unchecked`].
381    // TODO `&mut Stored<...>` seems off as a parameter type. Instead it should
382    // be `Stored<ResumableRef>`
383    pub fn access_fuel_mut<R>(
384        &mut self,
385        resumable_ref: &mut Stored<ResumableRef>,
386        f: impl FnOnce(&mut Option<u32>) -> R,
387    ) -> Result<R, RuntimeError> {
388        // 1. try unwrap
389        let resumable_ref = resumable_ref.as_mut().try_unwrap_into_bare(self.id)?;
390        // 2. call
391        let r = self.access_fuel_mut_unchecked(resumable_ref, f)?;
392        // 3. rewrap
393        // result type `R` is generic.
394        // 4. return
395        Ok(r)
396    }
397
398    // `fn func_alloc_typed` is missing because of the same reason why `fn
399    // func_alloc` is missing.
400
401    /// This is a safe variant of [`Store::invoke_without_fuel_unchecked`].
402    pub fn invoke_without_fuel(
403        &mut self,
404        func_addr: Stored<FuncAddr>,
405        params: Vec<StoredValue>,
406    ) -> Result<Vec<StoredValue>, RuntimeError> {
407        // 1 try unwrap
408        let func_addr = func_addr.try_unwrap_into_bare(self.id)?;
409        let params = try_unwrap_values(params, self.id)?;
410        // 2. call
411        let returns = self.invoke_without_fuel_unchecked(func_addr, params)?;
412        // 3. rewrap
413        // Safety: All `Value`s just came from the current store.
414        let returns = unsafe { wrap_vec_elements(returns, self.id) };
415        // 4. return
416        Ok(returns)
417    }
418
419    /// This is a safe variant of [`Store::invoke_typed_without_fuel_unchecked`].
420    pub fn invoke_typed_without_fuel<
421        Params: StoredInteropValueList,
422        Returns: StoredInteropValueList,
423    >(
424        &mut self,
425        function: Stored<FuncAddr>,
426        params: Params,
427    ) -> Result<Returns, RuntimeError> {
428        // 1. try unwrap
429        let function = function.try_unwrap_into_bare(self.id)?;
430        let params = try_unwrap_values(params.into_values(), self.id)?;
431        // 2. call
432        let returns = self.invoke_without_fuel_unchecked(function, params)?;
433        // 3. rewrap
434        // Safety: All `Value`s just came from the current store.
435        let stored_returns = unsafe { wrap_vec_elements(returns, self.id) };
436        // 4. return
437        let stored_returns = Returns::try_from_values(stored_returns.into_iter())
438            .map_err(|_| RuntimeError::FunctionInvocationSignatureMismatch)?;
439        Ok(stored_returns)
440    }
441}
442
443// All functions in this impl block must occur in the same order as they are
444// defined in for the unchecked [`Linker`] methods. Also all functions must
445// follow the same implementation scheme to make sure they are only light
446// wrappers:
447//
448// 1. get or insert the `StoreId` [of the store associated with the current `Linker`]
449// 2. try unwrap [stored parameter objects]
450// 3. call [unchecked method]
451// 4. rewrap [results into stored objects]
452// 5. return [stored result objects]
453impl Linker {
454    /// This is a safe variant of [`Linker::define_unchecked`].
455    pub fn define(
456        &mut self,
457        module_name: String,
458        name: String,
459        extern_val: StoredExternVal,
460    ) -> Result<(), RuntimeError> {
461        // 1. get or insert the `StoreId`
462        let extern_val_store_id = extern_val
463            .id()
464            .expect("this type to always contain a StoreId");
465        let linker_store_id = *self.store_id.get_or_insert(extern_val_store_id);
466        if linker_store_id != extern_val_store_id {
467            return Err(RuntimeError::StoreIdMismatch);
468        }
469        // 2. try unwrap
470        let extern_val = extern_val.try_unwrap_into_bare(linker_store_id)?;
471        // 3. call
472        self.define_unchecked(module_name, name, extern_val)?;
473        // 4. rewrap
474        // result is the unit type.
475        // 5. return
476        Ok(())
477    }
478
479    /// This is a safe variant of [`Linker::define_module_instance_unchecked`].
480    pub fn define_module_instance<T: Config>(
481        &mut self,
482        store: &Store<T>,
483        module_name: String,
484        module: Stored<ModuleAddr>,
485    ) -> Result<(), RuntimeError> {
486        // 1. get or insert the `StoreId`
487        let module_store_id = module.id().expect("this type to always contain a StoreId");
488        let linker_store_id = *self.store_id.get_or_insert(module_store_id);
489        if linker_store_id != module_store_id {
490            return Err(RuntimeError::StoreIdMismatch);
491        }
492        // 2. try unwrap
493        let module = module.try_unwrap_into_bare(linker_store_id)?;
494        // 3. call
495        self.define_module_instance_unchecked(store, module_name, module)?;
496        // 4. rewrap
497        // result is the unit type.
498        // 5. return
499        Ok(())
500    }
501
502    /// This is a safe variant of [`Linker::get_unchecked`].
503    ///
504    /// # Interaction with unchecked API
505    ///
506    /// This method is able to find externs defined through the unchecked
507    /// `define` methods.  However, for this to work, at least one of the
508    /// following methods must have been called successfully:
509    /// [`Linker::define`], [`Linker::define_module_instance`],
510    /// [`Linker::module_instantiate`]. Otherwise, this method may spuriously
511    /// return an error.
512    ///
513    /// Therefore, it is advised against to mix the unchecked and checked API
514    /// for a single [`Linker`] instance.
515    ///
516    /// # Errors
517    ///
518    /// - [`RuntimeError::LinkerNotYetAssociatedWithStoreId`]
519    /// - [`RuntimeError::UnableToResolveExternLookup`]
520    pub fn get(&self, module_name: String, name: String) -> Result<StoredExternVal, RuntimeError> {
521        // 1. get or insert the `StoreId`
522        // TODO docs are not consistent
523        let Some(linker_store_id) = self.store_id else {
524            // At this point we have no way to set the current store id, because
525            // the parameters are all non-stored types.
526
527            // We also know that nothing was defined in this linker context through
528            // the checked methods yet, because `self.store_id` has not been set
529            // yet. Therefore, a get would always return `None`.
530
531            // However, when an unchecked `define` method was used before, we
532            // also have to return `None` here, because even if the lookup for
533            // `module_name` and `name` returns something, we cannot attach a
534            // store id to it.
535
536            return Err(RuntimeError::LinkerNotYetAssociatedWithStoreId);
537        };
538        // 2. try unwrap
539        // no stored parameters
540        // 3. call
541        let extern_val = self
542            .get_unchecked(module_name, name)
543            .ok_or(RuntimeError::UnableToResolveExternLookup)?;
544        // 4. rewrap
545        // Safety: The `ExternVal` just came from the current `Linker`. Because
546        // a `Linker` can always be used with only one unique `Store`, this
547        // `ExternVal` must be from the current Linker's store.
548        let stored_extern_val = unsafe { StoredExternVal::from_bare(extern_val, linker_store_id) };
549        // 5. return
550        Ok(stored_extern_val)
551    }
552
553    /// This is a safe variant of [`Linker::instantiate_pre_unchecked`].
554    ///
555    /// # Interaction with unchecked API
556    ///
557    /// See [`Linker::get`]
558    ///
559    /// # Errors
560    ///
561    /// - [`RuntimeError::LinkerNotYetAssociatedWithStoreId`]
562    /// - [`RuntimeError::UnableToResolveExternLookup`]
563    pub fn instantiate_pre(
564        &self,
565        validation_info: &ValidationInfo,
566    ) -> Result<Vec<StoredExternVal>, RuntimeError> {
567        // Special case: If the module has no imports, we don't perform any
568        // linking. We need this special case, so that a `Linker`, that has not
569        // yet been associated with some `Store`, can still be used to
570        // pre-instantiate modules.
571        if validation_info.imports.is_empty() {
572            return Ok(Vec::new());
573        }
574        // 1. get or insert `StoreId`
575        let Some(linker_store_id) = self.store_id else {
576            // We are not able to perform safe linking (see this method's and
577            // `Linker::get`'s documentations).
578            return Err(RuntimeError::LinkerNotYetAssociatedWithStoreId);
579        };
580        // 2. try unwrap
581        // no stored parameters
582        // 3. call
583        let extern_vals = self.instantiate_pre_unchecked(validation_info)?;
584        // 4. rewrap
585        // Safety: All `ExternVal`s just came from the current `Linker`. Because
586        // a Linker can always be used with only one unique `Store`, all
587        // `ExternVal`s must be from the current Linker's store.
588        let stored_extern_vals = unsafe { wrap_vec_elements(extern_vals, linker_store_id) };
589        // 5. retur
590        Ok(stored_extern_vals)
591    }
592
593    /// This is a safe variant of [`Linker::module_instantiate_unchecked`].
594    pub fn module_instantiate<'b, T: Config>(
595        &mut self,
596        store: &mut Store<'b, T>,
597        validation_info: &ValidationInfo<'b>,
598        maybe_fuel: Option<u32>,
599    ) -> Result<StoredInstantiationOutcome, RuntimeError> {
600        // 1. get or insert `StoreId`
601        let linker_store_id = *self.store_id.get_or_insert(store.id);
602        if linker_store_id != store.id {
603            return Err(RuntimeError::StoreIdMismatch);
604        }
605        // 2. try unwrap
606        // no stored parameters
607        // 3. call
608        let instantiation_outcome =
609            self.module_instantiate_unchecked(store, validation_info, maybe_fuel)?;
610        // 4. rewrap
611        // Safety: The `InstantiationOutcome` just came from the current
612        // `Linker`. Because a linker can always be used with only one unique
613        // `Store`, the `InstantiationOutcome` must be from the current Linker's
614        // store.
615        let stored_instantiation_outcome = unsafe {
616            StoredInstantiationOutcome::from_bare(instantiation_outcome, linker_store_id)
617        };
618        // 5. return
619        Ok(stored_instantiation_outcome)
620    }
621}
622
623/// A trait for types that might have a [`StoreId`] attached to them, so-called
624/// _stored_ types.
625trait AbstractStored: Sized {
626    type BareTy: Sized;
627
628    /// Creates a new stored object
629    ///
630    /// # Safety
631    /// The caller has to guarantee that the bare value comes from a [`Store`]
632    /// with the given [`StoreId`].
633    unsafe fn from_bare(bare_value: Self::BareTy, id: StoreId) -> Self;
634
635    /// Gets the id of this stored object
636    ///
637    /// Not all stored objects require to have an id attached to them.
638    fn id(&self) -> Option<StoreId>;
639
640    /// Converts this stored object into its bare form that does not have any [`StoreId`] attached to it.
641    fn into_bare(self) -> Self::BareTy;
642
643    /// Checks if this stored object comes from a specific store by its
644    /// [`StoreId`]. If true, it converts self into its bare form, otherwise an
645    /// error is returned.
646    ///
647    /// # Errors
648    /// - [`RuntimeError::StoreIdMismatch`]
649    fn try_unwrap_into_bare(
650        self,
651        expected_store_id: StoreId,
652    ) -> Result<Self::BareTy, RuntimeError> {
653        if let Some(id) = self.id() {
654            if id != expected_store_id {
655                return Err(RuntimeError::StoreIdMismatch);
656            }
657        }
658
659        Ok(self.into_bare())
660    }
661}
662
663/// A generic stored wrapper. This is used to wrap `struct` types such as
664/// [`FuncAddr`], [`MemAddr`], etc.
665pub struct Stored<T> {
666    id: StoreId,
667    inner: T,
668}
669
670impl<T> AbstractStored for Stored<T> {
671    type BareTy = T;
672
673    unsafe fn from_bare(bare_value: Self::BareTy, id: StoreId) -> Self {
674        Self {
675            inner: bare_value,
676            id,
677        }
678    }
679
680    fn id(&self) -> Option<StoreId> {
681        Some(self.id)
682    }
683
684    fn into_bare(self) -> Self::BareTy {
685        self.inner
686    }
687}
688
689impl<T: Clone> Clone for Stored<T> {
690    fn clone(&self) -> Self {
691        Self {
692            id: self.id,
693            inner: self.inner.clone(),
694        }
695    }
696}
697
698impl<T: Copy> Copy for Stored<T> {}
699
700impl<T: core::fmt::Debug> core::fmt::Debug for Stored<T> {
701    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
702        f.debug_struct("Stored")
703            .field("inner", &self)
704            .field("id", &self.id)
705            .finish()
706    }
707}
708
709impl<T: PartialEq> PartialEq for Stored<T> {
710    fn eq(&self, other: &Self) -> bool {
711        self.id.eq(&other.id) && self.inner.eq(&other.inner)
712    }
713}
714
715impl<T: Eq> Eq for Stored<T> {}
716
717impl<T> Stored<T> {
718    // TODO remove this after the `ResumableRef` rework. Currently
719    // `ResumableRef` can store data, however it should merely be an addr type
720    // into the store in the future.
721    fn as_mut(&mut self) -> Stored<&mut T> {
722        Stored {
723            id: self.id,
724            inner: &mut self.inner,
725        }
726    }
727}
728
729/// A stored variant of [`ExternVal`]
730#[derive(Debug, Copy, Clone, PartialEq, Eq)]
731pub enum StoredExternVal {
732    Func(Stored<FuncAddr>),
733    Table(Stored<TableAddr>),
734    Mem(Stored<MemAddr>),
735    Global(Stored<GlobalAddr>),
736}
737
738impl AbstractStored for StoredExternVal {
739    type BareTy = ExternVal;
740
741    unsafe fn from_bare(bare_value: Self::BareTy, id: StoreId) -> Self {
742        match bare_value {
743            ExternVal::Func(func_addr) => Self::Func(Stored::from_bare(func_addr, id)),
744            ExternVal::Table(table_addr) => Self::Table(Stored::from_bare(table_addr, id)),
745            ExternVal::Mem(mem_addr) => Self::Mem(Stored::from_bare(mem_addr, id)),
746            ExternVal::Global(global_addr) => Self::Global(Stored::from_bare(global_addr, id)),
747        }
748    }
749
750    fn id(&self) -> Option<StoreId> {
751        match self {
752            StoredExternVal::Func(stored_func_addr) => stored_func_addr.id(),
753            StoredExternVal::Table(stored_table_addr) => stored_table_addr.id(),
754            StoredExternVal::Mem(stored_mem_addr) => stored_mem_addr.id(),
755            StoredExternVal::Global(stored_global_addr) => stored_global_addr.id(),
756        }
757    }
758
759    fn into_bare(self) -> Self::BareTy {
760        match self {
761            StoredExternVal::Func(stored_func_addr) => {
762                ExternVal::Func(stored_func_addr.into_bare())
763            }
764            StoredExternVal::Table(stored_table_addr) => {
765                ExternVal::Table(stored_table_addr.into_bare())
766            }
767            StoredExternVal::Mem(stored_mem_addr) => ExternVal::Mem(stored_mem_addr.into_bare()),
768            StoredExternVal::Global(stored_global_addr) => {
769                ExternVal::Global(stored_global_addr.into_bare())
770            }
771        }
772    }
773}
774
775impl StoredExternVal {
776    pub fn as_func(self) -> Option<Stored<FuncAddr>> {
777        match self {
778            StoredExternVal::Func(func_addr) => Some(func_addr),
779            _ => None,
780        }
781    }
782
783    pub fn as_table(self) -> Option<Stored<TableAddr>> {
784        match self {
785            StoredExternVal::Table(table_addr) => Some(table_addr),
786            _ => None,
787        }
788    }
789
790    pub fn as_mem(self) -> Option<Stored<MemAddr>> {
791        match self {
792            StoredExternVal::Mem(mem_addr) => Some(mem_addr),
793            _ => None,
794        }
795    }
796
797    pub fn as_global(self) -> Option<Stored<GlobalAddr>> {
798        match self {
799            StoredExternVal::Global(global_addr) => Some(global_addr),
800            _ => None,
801        }
802    }
803}
804
805/// A stored variant of [`RunState`]
806pub enum StoredRunState {
807    Finished {
808        values: Vec<StoredValue>,
809        maybe_remaining_fuel: Option<u32>,
810    },
811    Resumable {
812        resumable_ref: Stored<ResumableRef>,
813        required_fuel: NonZeroU32,
814    },
815}
816
817impl AbstractStored for StoredRunState {
818    type BareTy = RunState;
819
820    unsafe fn from_bare(bare_value: Self::BareTy, id: StoreId) -> Self {
821        match bare_value {
822            RunState::Finished {
823                values,
824                maybe_remaining_fuel,
825            } => Self::Finished {
826                values: wrap_vec_elements(values, id),
827                maybe_remaining_fuel,
828            },
829            RunState::Resumable {
830                resumable_ref,
831                required_fuel,
832            } => Self::Resumable {
833                resumable_ref: Stored::from_bare(resumable_ref, id),
834                required_fuel,
835            },
836        }
837    }
838
839    fn id(&self) -> Option<StoreId> {
840        todo!()
841    }
842
843    fn into_bare(self) -> Self::BareTy {
844        todo!()
845    }
846}
847
848/// A stored variant of [`InstantiationOutcome`]
849pub struct StoredInstantiationOutcome {
850    pub module_addr: Stored<ModuleAddr>,
851    pub maybe_remaining_fuel: Option<u32>,
852}
853
854impl AbstractStored for StoredInstantiationOutcome {
855    type BareTy = InstantiationOutcome;
856
857    unsafe fn from_bare(bare_value: Self::BareTy, id: StoreId) -> Self {
858        Self {
859            module_addr: Stored::from_bare(bare_value.module_addr, id),
860            maybe_remaining_fuel: bare_value.maybe_remaining_fuel,
861        }
862    }
863
864    fn id(&self) -> Option<StoreId> {
865        self.module_addr.id()
866    }
867
868    fn into_bare(self) -> Self::BareTy {
869        InstantiationOutcome {
870            module_addr: self.module_addr.into_bare(),
871            maybe_remaining_fuel: self.maybe_remaining_fuel,
872        }
873    }
874}
875
876/// Helper method for associating every element in a [`Vec`] with a [`StoreId`].
877///
878/// # Safety
879///
880/// It must be guaranteed that all given elements come from the [`Store`] with
881/// the given [`StoreId`].
882unsafe fn wrap_vec_elements<S: AbstractStored>(values: Vec<S::BareTy>, id: StoreId) -> Vec<S> {
883    values
884        .into_iter()
885        .map(|value| {
886            // Safety: The caller guarantees that all values in this Vec come
887            // from the store with given id. Therefore, this is also true for
888            // this specific `Value`.
889            unsafe { S::from_bare(value, id) }
890        })
891        .collect()
892}
893
894/// Helper method for checking if all [`Value`](crate::execution::Value)s in a slice have the given
895/// [`StoreId`] and then, if the check was true, converting them to a
896/// [`Vec<Value>`].
897///
898/// # Errors
899/// - [`RuntimeError::StoreIdMismatch`]
900fn try_unwrap_values<S: AbstractStored>(
901    stored_values: Vec<S>,
902    expected_store_id: StoreId,
903) -> Result<Vec<S::BareTy>, RuntimeError> {
904    stored_values
905        .into_iter()
906        .map(|stored_value| stored_value.try_unwrap_into_bare(expected_store_id))
907        .collect()
908}