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}