radix_wasmi/module/instantiate/
pre.rs

1use super::InstantiationError;
2use crate::{module::FuncIdx, AsContextMut, Error, Instance, InstanceEntityBuilder};
3
4/// A partially instantiated [`Instance`] where the `start` function has not yet been executed.
5///
6/// # Note
7///
8/// Some users require Wasm modules to not have a `start` function that is required for
9/// conformant module instantiation. This API provides control over the precise instantiation
10/// process with regard to this need.
11#[derive(Debug)]
12pub struct InstancePre {
13    handle: Instance,
14    builder: InstanceEntityBuilder,
15}
16
17impl InstancePre {
18    /// Creates a new [`InstancePre`].
19    pub(super) fn new(handle: Instance, builder: InstanceEntityBuilder) -> Self {
20        Self { handle, builder }
21    }
22
23    /// Returns the index of the `start` function if any.
24    ///
25    /// Returns `None` if the Wasm module does not have a `start` function.
26    fn start_fn(&self) -> Option<u32> {
27        self.builder.get_start().map(FuncIdx::into_u32)
28    }
29
30    /// Runs the `start` function of the [`Instance`] and returns its handle.
31    ///
32    /// # Note
33    ///
34    /// This finishes the instantiation procedure.
35    ///
36    /// # Errors
37    ///
38    /// If executing the `start` function traps.
39    ///
40    /// # Panics
41    ///
42    /// If the `start` function is invalid albeit successful validation.
43    pub fn start(self, mut context: impl AsContextMut) -> Result<Instance, Error> {
44        let opt_start_index = self.start_fn();
45        context
46            .as_context_mut()
47            .store
48            .initialize_instance(self.handle, self.builder.finish());
49        if let Some(start_index) = opt_start_index {
50            let start_func = self
51                .handle
52                .get_func_by_index(&mut context, start_index)
53                .unwrap_or_else(|| {
54                    panic!("encountered invalid start function after validation: {start_index}")
55                });
56            start_func.call(context.as_context_mut(), &[], &mut [])?
57        }
58        Ok(self.handle)
59    }
60
61    /// Finishes instantiation ensuring that no `start` function exists.
62    ///
63    /// # Errors
64    ///
65    /// If a `start` function exists that needs to be called for conformant module instantiation.
66    pub fn ensure_no_start(
67        self,
68        mut context: impl AsContextMut,
69    ) -> Result<Instance, InstantiationError> {
70        if let Some(index) = self.start_fn() {
71            return Err(InstantiationError::FoundStartFn { index });
72        }
73        context
74            .as_context_mut()
75            .store
76            .initialize_instance(self.handle, self.builder.finish());
77        Ok(self.handle)
78    }
79}