wasmi/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 collections::{arena::ArenaIndex, Map},
16 func::FuncError,
17 memory::DataSegment,
18 ElementSegment,
19 Error,
20 TypedFunc,
21 WasmParams,
22 WasmResults,
23};
24use std::{boxed::Box, sync::Arc};
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: Map<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: Map::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::from(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}