gwasmi/instance/
mod.rs

1pub(crate) use self::builder::InstanceEntityBuilder;
2pub use self::exports::{Export, ExportsIter, Extern, ExternType};
3use super::{
4    engine::DedupFuncType,
5    AsContext,
6    Func,
7    Global,
8    Memory,
9    Module,
10    StoreContext,
11    Stored,
12    Table,
13};
14use crate::{
15    func::FuncError,
16    memory::DataSegment,
17    ElementSegment,
18    Error,
19    TypedFunc,
20    WasmParams,
21    WasmResults,
22};
23use alloc::{boxed::Box, collections::BTreeMap, sync::Arc};
24use wasmi_arena::ArenaIndex;
25
26mod builder;
27mod exports;
28
29/// A raw index to a module instance entity.
30#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
31pub struct InstanceIdx(u32);
32
33impl ArenaIndex for InstanceIdx {
34    fn into_usize(self) -> usize {
35        self.0 as usize
36    }
37
38    fn from_usize(value: usize) -> Self {
39        let value = value.try_into().unwrap_or_else(|error| {
40            panic!("index {value} is out of bounds as instance index: {error}")
41        });
42        Self(value)
43    }
44}
45
46/// A module instance entity.
47#[derive(Debug)]
48pub struct InstanceEntity {
49    initialized: bool,
50    func_types: Arc<[DedupFuncType]>,
51    tables: Box<[Table]>,
52    funcs: Box<[Func]>,
53    memories: Box<[Memory]>,
54    globals: Box<[Global]>,
55    exports: BTreeMap<Box<str>, Extern>,
56    data_segments: Box<[DataSegment]>,
57    elem_segments: Box<[ElementSegment]>,
58}
59
60impl InstanceEntity {
61    /// Creates an uninitialized [`InstanceEntity`].
62    pub fn uninitialized() -> InstanceEntity {
63        Self {
64            initialized: false,
65            func_types: Arc::new([]),
66            tables: [].into(),
67            funcs: [].into(),
68            memories: [].into(),
69            globals: [].into(),
70            exports: BTreeMap::new(),
71            data_segments: [].into(),
72            elem_segments: [].into(),
73        }
74    }
75
76    /// Creates a new [`InstanceEntityBuilder`].
77    pub fn build(module: &Module) -> InstanceEntityBuilder {
78        InstanceEntityBuilder::new(module)
79    }
80
81    /// Returns `true` if the [`InstanceEntity`] has been fully initialized.
82    pub fn is_initialized(&self) -> bool {
83        self.initialized
84    }
85
86    /// Returns the linear memory at the `index` if any.
87    pub fn get_memory(&self, index: u32) -> Option<Memory> {
88        self.memories.get(index as usize).copied()
89    }
90
91    /// Returns the table at the `index` if any.
92    pub fn get_table(&self, index: u32) -> Option<Table> {
93        self.tables.get(index as usize).copied()
94    }
95
96    /// Returns the global variable at the `index` if any.
97    pub fn get_global(&self, index: u32) -> Option<Global> {
98        self.globals.get(index as usize).copied()
99    }
100
101    /// Returns the function at the `index` if any.
102    pub fn get_func(&self, index: u32) -> Option<Func> {
103        self.funcs.get(index as usize).copied()
104    }
105
106    /// Returns the signature at the `index` if any.
107    pub fn get_signature(&self, index: u32) -> Option<&DedupFuncType> {
108        self.func_types.get(index as usize)
109    }
110
111    /// Returns the [`DataSegment`] at the `index` if any.
112    pub fn get_data_segment(&self, index: u32) -> Option<DataSegment> {
113        self.data_segments.get(index as usize).copied()
114    }
115
116    /// Returns the [`ElementSegment`] at the `index` if any.
117    pub fn get_element_segment(&self, index: u32) -> Option<ElementSegment> {
118        self.elem_segments.get(index as usize).copied()
119    }
120
121    /// Returns the value exported to the given `name` if any.
122    pub fn get_export(&self, name: &str) -> Option<Extern> {
123        self.exports.get(name).copied()
124    }
125
126    /// Returns an iterator over the exports of the [`Instance`].
127    ///
128    /// The order of the yielded exports is not specified.
129    pub fn exports(&self) -> ExportsIter {
130        ExportsIter::new(self.exports.iter())
131    }
132}
133
134/// An instantiated WebAssembly [`Module`].
135///
136/// This type represents an instantiation of a [`Module`].
137/// It primarily allows to access its [`exports`](Instance::exports)
138/// to call functions, get or set globals, read or write memory, etc.
139///
140/// When interacting with any Wasm code you will want to create an
141/// [`Instance`] in order to execute anything.
142///
143/// Instances are owned by a [`Store`](crate::Store).
144/// Create new instances using [`Linker::instantiate`](crate::Linker::instantiate).
145#[derive(Debug, Copy, Clone, PartialEq, Eq)]
146#[repr(transparent)]
147pub struct Instance(Stored<InstanceIdx>);
148
149impl Instance {
150    /// Creates a new stored instance reference.
151    ///
152    /// # Note
153    ///
154    /// This API is primarily used by the [`Store`] itself.
155    ///
156    /// [`Store`]: [`crate::Store`]
157    pub(super) fn from_inner(stored: Stored<InstanceIdx>) -> Self {
158        Self(stored)
159    }
160
161    /// Returns the underlying stored representation.
162    pub(super) fn as_inner(&self) -> &Stored<InstanceIdx> {
163        &self.0
164    }
165
166    /// Returns the function at the `index` if any.
167    ///
168    /// # Panics
169    ///
170    /// Panics if `store` does not own this [`Instance`].
171    pub(crate) fn get_func_by_index(&self, store: impl AsContext, index: u32) -> Option<Func> {
172        store
173            .as_context()
174            .store
175            .inner
176            .resolve_instance(self)
177            .get_func(index)
178    }
179
180    /// Returns the value exported to the given `name` if any.
181    ///
182    /// # Panics
183    ///
184    /// Panics if `store` does not own this [`Instance`].
185    pub fn get_export(&self, store: impl AsContext, name: &str) -> Option<Extern> {
186        store
187            .as_context()
188            .store
189            .inner
190            .resolve_instance(self)
191            .get_export(name)
192    }
193
194    /// Looks up an exported [`Func`] value by `name`.
195    ///
196    /// Returns `None` if there was no export named `name`,
197    /// or if there was but it wasn’t a function.
198    ///
199    /// # Panics
200    ///
201    /// If `store` does not own this [`Instance`].
202    pub fn get_func(&self, store: impl AsContext, name: &str) -> Option<Func> {
203        self.get_export(store, name)?.into_func()
204    }
205
206    /// Looks up an exported [`Func`] value by `name`.
207    ///
208    /// Returns `None` if there was no export named `name`,
209    /// or if there was but it wasn’t a function.
210    ///
211    /// # Errors
212    ///
213    /// - If there is no export named `name`.
214    /// - If there is no exported function named `name`.
215    /// - If `Params` or `Results` do not match the exported function type.
216    ///
217    /// # Panics
218    ///
219    /// If `store` does not own this [`Instance`].
220    pub fn get_typed_func<Params, Results>(
221        &self,
222        store: impl AsContext,
223        name: &str,
224    ) -> Result<TypedFunc<Params, Results>, Error>
225    where
226        Params: WasmParams,
227        Results: WasmResults,
228    {
229        self.get_export(&store, name)
230            .and_then(Extern::into_func)
231            .ok_or_else(|| Error::Func(FuncError::ExportedFuncNotFound))?
232            .typed::<Params, Results>(store)
233    }
234
235    /// Looks up an exported [`Global`] value by `name`.
236    ///
237    /// Returns `None` if there was no export named `name`,
238    /// or if there was but it wasn’t a global variable.
239    ///
240    /// # Panics
241    ///
242    /// If `store` does not own this [`Instance`].
243    pub fn get_global(&self, store: impl AsContext, name: &str) -> Option<Global> {
244        self.get_export(store, name)?.into_global()
245    }
246
247    /// Looks up an exported [`Table`] value by `name`.
248    ///
249    /// Returns `None` if there was no export named `name`,
250    /// or if there was but it wasn’t a table.
251    ///
252    /// # Panics
253    ///
254    /// If `store` does not own this [`Instance`].
255    pub fn get_table(&self, store: impl AsContext, name: &str) -> Option<Table> {
256        self.get_export(store, name)?.into_table()
257    }
258
259    /// Looks up an exported [`Memory`] value by `name`.
260    ///
261    /// Returns `None` if there was no export named `name`,
262    /// or if there was but it wasn’t a table.
263    ///
264    /// # Panics
265    ///
266    /// If `store` does not own this [`Instance`].
267    pub fn get_memory(&self, store: impl AsContext, name: &str) -> Option<Memory> {
268        self.get_export(store, name)?.into_memory()
269    }
270
271    /// Returns an iterator over the exports of the [`Instance`].
272    ///
273    /// The order of the yielded exports is not specified.
274    ///
275    /// # Panics
276    ///
277    /// Panics if `store` does not own this [`Instance`].
278    pub fn exports<'ctx, T: 'ctx>(
279        &self,
280        store: impl Into<StoreContext<'ctx, T>>,
281    ) -> ExportsIter<'ctx> {
282        store.into().store.inner.resolve_instance(self).exports()
283    }
284}