soroban_wasmi/instance/
exports.rs

1use crate::{
2    collections::map::Iter as MapIter,
3    AsContext,
4    Func,
5    FuncType,
6    Global,
7    GlobalType,
8    Memory,
9    MemoryType,
10    Table,
11    TableType,
12};
13use core::iter::FusedIterator;
14use std::boxed::Box;
15
16/// An external item to a WebAssembly module.
17///
18/// This is returned from [`Instance::exports`](crate::Instance::exports)
19/// or [`Instance::get_export`](crate::Instance::get_export).
20#[derive(Debug, Copy, Clone)]
21pub enum Extern {
22    /// A WebAssembly global which acts like a [`Cell<T>`] of sorts, supporting `get` and `set` operations.
23    ///
24    /// [`Cell<T>`]: https://doc.rust-lang.org/core/cell/struct.Cell.html
25    Global(Global),
26    /// A WebAssembly table which is an array of function references.
27    Table(Table),
28    /// A WebAssembly linear memory.
29    Memory(Memory),
30    /// A WebAssembly function which can be called.
31    Func(Func),
32}
33
34impl From<Global> for Extern {
35    fn from(global: Global) -> Self {
36        Self::Global(global)
37    }
38}
39
40impl From<Table> for Extern {
41    fn from(table: Table) -> Self {
42        Self::Table(table)
43    }
44}
45
46impl From<Memory> for Extern {
47    fn from(memory: Memory) -> Self {
48        Self::Memory(memory)
49    }
50}
51
52impl From<Func> for Extern {
53    fn from(func: Func) -> Self {
54        Self::Func(func)
55    }
56}
57
58impl Extern {
59    /// Returns the underlying global variable if `self` is a global variable.
60    ///
61    /// Returns `None` otherwise.
62    pub fn into_global(self) -> Option<Global> {
63        if let Self::Global(global) = self {
64            return Some(global);
65        }
66        None
67    }
68
69    /// Returns the underlying table if `self` is a table.
70    ///
71    /// Returns `None` otherwise.
72    pub fn into_table(self) -> Option<Table> {
73        if let Self::Table(table) = self {
74            return Some(table);
75        }
76        None
77    }
78
79    /// Returns the underlying linear memory if `self` is a linear memory.
80    ///
81    /// Returns `None` otherwise.
82    pub fn into_memory(self) -> Option<Memory> {
83        if let Self::Memory(memory) = self {
84            return Some(memory);
85        }
86        None
87    }
88
89    /// Returns the underlying function if `self` is a function.
90    ///
91    /// Returns `None` otherwise.
92    pub fn into_func(self) -> Option<Func> {
93        if let Self::Func(func) = self {
94            return Some(func);
95        }
96        None
97    }
98
99    /// Returns the type associated with this [`Extern`].
100    ///
101    /// # Panics
102    ///
103    /// If this item does not belong to the `store` provided.
104    pub fn ty(&self, ctx: impl AsContext) -> ExternType {
105        match self {
106            Extern::Global(global) => global.ty(ctx).into(),
107            Extern::Table(table) => table.ty(ctx).into(),
108            Extern::Memory(memory) => memory.ty(ctx).into(),
109            Extern::Func(func) => func.ty(ctx).into(),
110        }
111    }
112}
113
114/// The type of an [`Extern`] item.
115///
116/// A list of all possible types which can be externally referenced from a WebAssembly module.
117#[derive(Debug, Clone)]
118pub enum ExternType {
119    /// The type of an [`Extern::Global`].
120    Global(GlobalType),
121    /// The type of an [`Extern::Table`].
122    Table(TableType),
123    /// The type of an [`Extern::Memory`].
124    Memory(MemoryType),
125    /// The type of an [`Extern::Func`].
126    Func(FuncType),
127}
128
129impl From<GlobalType> for ExternType {
130    fn from(global: GlobalType) -> Self {
131        Self::Global(global)
132    }
133}
134
135impl From<TableType> for ExternType {
136    fn from(table: TableType) -> Self {
137        Self::Table(table)
138    }
139}
140
141impl From<MemoryType> for ExternType {
142    fn from(memory: MemoryType) -> Self {
143        Self::Memory(memory)
144    }
145}
146
147impl From<FuncType> for ExternType {
148    fn from(func: FuncType) -> Self {
149        Self::Func(func)
150    }
151}
152
153impl ExternType {
154    /// Returns the underlying [`GlobalType`] or `None` if it is of a different type.
155    pub fn global(&self) -> Option<&GlobalType> {
156        match self {
157            Self::Global(ty) => Some(ty),
158            _ => None,
159        }
160    }
161
162    /// Returns the underlying [`TableType`] or `None` if it is of a different type.
163    pub fn table(&self) -> Option<&TableType> {
164        match self {
165            Self::Table(ty) => Some(ty),
166            _ => None,
167        }
168    }
169
170    /// Returns the underlying [`MemoryType`] or `None` if it is of a different type.
171    pub fn memory(&self) -> Option<&MemoryType> {
172        match self {
173            Self::Memory(ty) => Some(ty),
174            _ => None,
175        }
176    }
177
178    /// Returns the underlying [`FuncType`] or `None` if it is of a different type.
179    pub fn func(&self) -> Option<&FuncType> {
180        match self {
181            Self::Func(ty) => Some(ty),
182            _ => None,
183        }
184    }
185}
186
187/// An exported WebAssembly value.
188///
189/// This type is primarily accessed from the [`Instance::exports`](crate::Instance::exports) method
190/// and describes what names and items are exported from a Wasm [`Instance`](crate::Instance).
191#[derive(Debug, Clone)]
192pub struct Export<'instance> {
193    /// The name of the exported item.
194    name: &'instance str,
195    /// The definition of the exported item.
196    definition: Extern,
197}
198
199impl<'instance> Export<'instance> {
200    /// Creates a new [`Export`] with the given `name` and `definition`.
201    pub(crate) fn new(name: &'instance str, definition: Extern) -> Export<'instance> {
202        Self { name, definition }
203    }
204
205    /// Returns the name by which this export is known.
206    pub fn name(&self) -> &'instance str {
207        self.name
208    }
209
210    /// Return the [`ExternType`] of this export.
211    ///
212    /// # Panics
213    ///
214    /// If `ctx` does not own this [`Export`].
215    pub fn ty(&self, ctx: impl AsContext) -> ExternType {
216        self.definition.ty(ctx)
217    }
218
219    /// Consume this [`Export`] and return the underlying [`Extern`].
220    pub fn into_extern(self) -> Extern {
221        self.definition
222    }
223
224    /// Returns the underlying [`Func`], if the [`Export`] is a function or `None` otherwise.
225    pub fn into_func(self) -> Option<Func> {
226        self.definition.into_func()
227    }
228
229    /// Returns the underlying [`Table`], if the [`Export`] is a table or `None` otherwise.
230    pub fn into_table(self) -> Option<Table> {
231        self.definition.into_table()
232    }
233
234    /// Returns the underlying [`Memory`], if the [`Export`] is a linear memory or `None` otherwise.
235    pub fn into_memory(self) -> Option<Memory> {
236        self.definition.into_memory()
237    }
238
239    /// Returns the underlying [`Global`], if the [`Export`] is a global variable or `None` otherwise.
240    pub fn into_global(self) -> Option<Global> {
241        self.definition.into_global()
242    }
243}
244
245/// An iterator over the [`Extern`] declarations of an [`Instance`](crate::Instance).
246#[derive(Debug)]
247pub struct ExportsIter<'instance> {
248    iter: MapIter<'instance, Box<str>, Extern>,
249}
250
251impl<'instance> ExportsIter<'instance> {
252    /// Creates a new [`ExportsIter`].
253    pub(super) fn new(iter: MapIter<'instance, Box<str>, Extern>) -> Self {
254        Self { iter }
255    }
256
257    /// Prepares an item to match the expected iterator `Item` signature.
258    #[allow(clippy::borrowed_box)]
259    fn convert_item((name, export): (&'instance Box<str>, &'instance Extern)) -> Export<'instance> {
260        Export::new(name, *export)
261    }
262}
263
264impl<'instance> Iterator for ExportsIter<'instance> {
265    type Item = Export<'instance>;
266
267    fn next(&mut self) -> Option<Self::Item> {
268        self.iter.next().map(Self::convert_item)
269    }
270
271    fn size_hint(&self) -> (usize, Option<usize>) {
272        self.iter.size_hint()
273    }
274}
275
276impl ExactSizeIterator for ExportsIter<'_> {}
277impl FusedIterator for ExportsIter<'_> {}