wasmtime/
externals.rs

1use crate::store::{StoreData, StoreOpaque, Stored};
2use crate::trampoline::{generate_global_export, generate_table_export};
3use crate::{
4    AsContext, AsContextMut, Engine, ExternRef, ExternType, Func, GlobalType, Memory, Mutability,
5    SharedMemory, TableType, Val, ValType,
6};
7use anyhow::{anyhow, bail, Result};
8use std::mem;
9use std::ptr;
10use wasmtime_runtime::{self as runtime, InstanceHandle};
11
12// Externals
13
14/// An external item to a WebAssembly module, or a list of what can possibly be
15/// exported from a wasm module.
16///
17/// This is both returned from [`Instance::exports`](crate::Instance::exports)
18/// as well as required by [`Instance::new`](crate::Instance::new). In other
19/// words, this is the type of extracted values from an instantiated module, and
20/// it's also used to provide imported values when instantiating a module.
21#[derive(Clone, Debug)]
22pub enum Extern {
23    /// A WebAssembly `func` which can be called.
24    Func(Func),
25    /// A WebAssembly `global` which acts like a `Cell<T>` of sorts, supporting
26    /// `get` and `set` operations.
27    Global(Global),
28    /// A WebAssembly `table` which is an array of `Val` reference types.
29    Table(Table),
30    /// A WebAssembly linear memory.
31    Memory(Memory),
32    /// A WebAssembly shared memory; these are handled separately from
33    /// [`Memory`].
34    SharedMemory(SharedMemory),
35}
36
37impl Extern {
38    /// Returns the underlying `Func`, if this external is a function.
39    ///
40    /// Returns `None` if this is not a function.
41    pub fn into_func(self) -> Option<Func> {
42        match self {
43            Extern::Func(func) => Some(func),
44            _ => None,
45        }
46    }
47
48    /// Returns the underlying `Global`, if this external is a global.
49    ///
50    /// Returns `None` if this is not a global.
51    pub fn into_global(self) -> Option<Global> {
52        match self {
53            Extern::Global(global) => Some(global),
54            _ => None,
55        }
56    }
57
58    /// Returns the underlying `Table`, if this external is a table.
59    ///
60    /// Returns `None` if this is not a table.
61    pub fn into_table(self) -> Option<Table> {
62        match self {
63            Extern::Table(table) => Some(table),
64            _ => None,
65        }
66    }
67
68    /// Returns the underlying `Memory`, if this external is a memory.
69    ///
70    /// Returns `None` if this is not a memory.
71    pub fn into_memory(self) -> Option<Memory> {
72        match self {
73            Extern::Memory(memory) => Some(memory),
74            _ => None,
75        }
76    }
77
78    /// Returns the underlying `SharedMemory`, if this external is a shared
79    /// memory.
80    ///
81    /// Returns `None` if this is not a shared memory.
82    pub fn into_shared_memory(self) -> Option<SharedMemory> {
83        match self {
84            Extern::SharedMemory(memory) => Some(memory),
85            _ => None,
86        }
87    }
88
89    /// Returns the type associated with this `Extern`.
90    ///
91    /// The `store` argument provided must own this `Extern` and is used to look
92    /// up type information.
93    ///
94    /// # Panics
95    ///
96    /// Panics if this item does not belong to the `store` provided.
97    pub fn ty(&self, store: impl AsContext) -> ExternType {
98        let store = store.as_context();
99        match self {
100            Extern::Func(ft) => ExternType::Func(ft.ty(store)),
101            Extern::Memory(ft) => ExternType::Memory(ft.ty(store)),
102            Extern::SharedMemory(ft) => ExternType::Memory(ft.ty()),
103            Extern::Table(tt) => ExternType::Table(tt.ty(store)),
104            Extern::Global(gt) => ExternType::Global(gt.ty(store)),
105        }
106    }
107
108    pub(crate) unsafe fn from_wasmtime_export(
109        wasmtime_export: wasmtime_runtime::Export,
110        store: &mut StoreOpaque,
111    ) -> Extern {
112        match wasmtime_export {
113            wasmtime_runtime::Export::Function(f) => {
114                Extern::Func(Func::from_wasmtime_function(f, store))
115            }
116            wasmtime_runtime::Export::Memory(m) => {
117                if m.memory.memory.shared {
118                    Extern::SharedMemory(SharedMemory::from_wasmtime_memory(m, store))
119                } else {
120                    Extern::Memory(Memory::from_wasmtime_memory(m, store))
121                }
122            }
123            wasmtime_runtime::Export::Global(g) => {
124                Extern::Global(Global::from_wasmtime_global(g, store))
125            }
126            wasmtime_runtime::Export::Table(t) => {
127                Extern::Table(Table::from_wasmtime_table(t, store))
128            }
129        }
130    }
131
132    pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool {
133        match self {
134            Extern::Func(f) => f.comes_from_same_store(store),
135            Extern::Global(g) => store.store_data().contains(g.0),
136            Extern::Memory(m) => m.comes_from_same_store(store),
137            Extern::SharedMemory(m) => Engine::same(m.engine(), store.engine()),
138            Extern::Table(t) => store.store_data().contains(t.0),
139        }
140    }
141}
142
143impl From<Func> for Extern {
144    fn from(r: Func) -> Self {
145        Extern::Func(r)
146    }
147}
148
149impl From<Global> for Extern {
150    fn from(r: Global) -> Self {
151        Extern::Global(r)
152    }
153}
154
155impl From<Memory> for Extern {
156    fn from(r: Memory) -> Self {
157        Extern::Memory(r)
158    }
159}
160
161impl From<SharedMemory> for Extern {
162    fn from(r: SharedMemory) -> Self {
163        Extern::SharedMemory(r)
164    }
165}
166
167impl From<Table> for Extern {
168    fn from(r: Table) -> Self {
169        Extern::Table(r)
170    }
171}
172
173/// A WebAssembly `global` value which can be read and written to.
174///
175/// A `global` in WebAssembly is sort of like a global variable within an
176/// [`Instance`](crate::Instance). The `global.get` and `global.set`
177/// instructions will modify and read global values in a wasm module. Globals
178/// can either be imported or exported from wasm modules.
179///
180/// A [`Global`] "belongs" to the store that it was originally created within
181/// (either via [`Global::new`] or via instantiating a
182/// [`Module`](crate::Module)). Operations on a [`Global`] only work with the
183/// store it belongs to, and if another store is passed in by accident then
184/// methods will panic.
185#[derive(Copy, Clone, Debug)]
186#[repr(transparent)] // here for the C API
187pub struct Global(Stored<wasmtime_runtime::ExportGlobal>);
188
189impl Global {
190    /// Creates a new WebAssembly `global` value with the provide type `ty` and
191    /// initial value `val`.
192    ///
193    /// The `store` argument will be the owner of the [`Global`] returned. Using
194    /// the returned [`Global`] other items in the store may access this global.
195    /// For example this could be provided as an argument to
196    /// [`Instance::new`](crate::Instance::new) or
197    /// [`Linker::define`](crate::Linker::define).
198    ///
199    /// # Errors
200    ///
201    /// Returns an error if the `ty` provided does not match the type of the
202    /// value `val`, or if `val` comes from a different store than `store`.
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// # use wasmtime::*;
208    /// # fn main() -> anyhow::Result<()> {
209    /// let engine = Engine::default();
210    /// let mut store = Store::new(&engine, ());
211    ///
212    /// let ty = GlobalType::new(ValType::I32, Mutability::Const);
213    /// let i32_const = Global::new(&mut store, ty, 1i32.into())?;
214    /// let ty = GlobalType::new(ValType::F64, Mutability::Var);
215    /// let f64_mut = Global::new(&mut store, ty, 2.0f64.into())?;
216    ///
217    /// let module = Module::new(
218    ///     &engine,
219    ///     "(module
220    ///         (global (import \"\" \"i32-const\") i32)
221    ///         (global (import \"\" \"f64-mut\") (mut f64))
222    ///     )"
223    /// )?;
224    ///
225    /// let mut linker = Linker::new(&engine);
226    /// linker.define(&store, "", "i32-const", i32_const)?;
227    /// linker.define(&store, "", "f64-mut", f64_mut)?;
228    ///
229    /// let instance = linker.instantiate(&mut store, &module)?;
230    /// // ...
231    /// # Ok(())
232    /// # }
233    /// ```
234    pub fn new(mut store: impl AsContextMut, ty: GlobalType, val: Val) -> Result<Global> {
235        Global::_new(store.as_context_mut().0, ty, val)
236    }
237
238    fn _new(store: &mut StoreOpaque, ty: GlobalType, val: Val) -> Result<Global> {
239        if !val.comes_from_same_store(store) {
240            bail!("cross-`Store` globals are not supported");
241        }
242        if val.ty() != *ty.content() {
243            bail!("value provided does not match the type of this global");
244        }
245        unsafe {
246            let wasmtime_export = generate_global_export(store, &ty, val)?;
247            Ok(Global::from_wasmtime_global(wasmtime_export, store))
248        }
249    }
250
251    /// Returns the underlying type of this `global`.
252    ///
253    /// # Panics
254    ///
255    /// Panics if `store` does not own this global.
256    pub fn ty(&self, store: impl AsContext) -> GlobalType {
257        let store = store.as_context();
258        let ty = &store[self.0].global;
259        GlobalType::from_wasmtime_global(&ty)
260    }
261
262    /// Returns the current [`Val`] of this global.
263    ///
264    /// # Panics
265    ///
266    /// Panics if `store` does not own this global.
267    pub fn get(&self, mut store: impl AsContextMut) -> Val {
268        unsafe {
269            let store = store.as_context_mut();
270            let definition = &*store[self.0].definition;
271            match self.ty(&store).content() {
272                ValType::I32 => Val::from(*definition.as_i32()),
273                ValType::I64 => Val::from(*definition.as_i64()),
274                ValType::F32 => Val::F32(*definition.as_u32()),
275                ValType::F64 => Val::F64(*definition.as_u64()),
276                ValType::ExternRef => Val::ExternRef(
277                    definition
278                        .as_externref()
279                        .clone()
280                        .map(|inner| ExternRef { inner }),
281                ),
282                ValType::FuncRef => {
283                    Val::FuncRef(Func::from_raw(store, definition.as_anyfunc() as usize))
284                }
285                ValType::V128 => Val::V128(*definition.as_u128()),
286            }
287        }
288    }
289
290    /// Attempts to set the current value of this global to [`Val`].
291    ///
292    /// # Errors
293    ///
294    /// Returns an error if this global has a different type than `Val`, if
295    /// it's not a mutable global, or if `val` comes from a different store than
296    /// the one provided.
297    ///
298    /// # Panics
299    ///
300    /// Panics if `store` does not own this global.
301    pub fn set(&self, mut store: impl AsContextMut, val: Val) -> Result<()> {
302        let store = store.as_context_mut().0;
303        let ty = self.ty(&store);
304        if ty.mutability() != Mutability::Var {
305            bail!("immutable global cannot be set");
306        }
307        let ty = ty.content();
308        if val.ty() != *ty {
309            bail!("global of type {:?} cannot be set to {:?}", ty, val.ty());
310        }
311        if !val.comes_from_same_store(store) {
312            bail!("cross-`Store` values are not supported");
313        }
314        unsafe {
315            let definition = &mut *store[self.0].definition;
316            match val {
317                Val::I32(i) => *definition.as_i32_mut() = i,
318                Val::I64(i) => *definition.as_i64_mut() = i,
319                Val::F32(f) => *definition.as_u32_mut() = f,
320                Val::F64(f) => *definition.as_u64_mut() = f,
321                Val::FuncRef(f) => {
322                    *definition.as_anyfunc_mut() = f.map_or(ptr::null(), |f| {
323                        f.caller_checked_anyfunc(store).as_ptr().cast()
324                    });
325                }
326                Val::ExternRef(x) => {
327                    let old = mem::replace(definition.as_externref_mut(), x.map(|x| x.inner));
328                    drop(old);
329                }
330                Val::V128(i) => *definition.as_u128_mut() = i,
331            }
332        }
333        Ok(())
334    }
335
336    pub(crate) unsafe fn from_wasmtime_global(
337        wasmtime_export: wasmtime_runtime::ExportGlobal,
338        store: &mut StoreOpaque,
339    ) -> Global {
340        Global(store.store_data_mut().insert(wasmtime_export))
341    }
342
343    pub(crate) fn wasmtime_ty<'a>(&self, data: &'a StoreData) -> &'a wasmtime_environ::Global {
344        &data[self.0].global
345    }
346
347    pub(crate) fn vmimport(&self, store: &StoreOpaque) -> wasmtime_runtime::VMGlobalImport {
348        wasmtime_runtime::VMGlobalImport {
349            from: store[self.0].definition,
350        }
351    }
352}
353
354/// A WebAssembly `table`, or an array of values.
355///
356/// Like [`Memory`] a table is an indexed array of values, but unlike [`Memory`]
357/// it's an array of WebAssembly reference type values rather than bytes. One of
358/// the most common usages of a table is a function table for wasm modules (a
359/// `funcref` table), where each element has the `ValType::FuncRef` type.
360///
361/// A [`Table`] "belongs" to the store that it was originally created within
362/// (either via [`Table::new`] or via instantiating a
363/// [`Module`](crate::Module)). Operations on a [`Table`] only work with the
364/// store it belongs to, and if another store is passed in by accident then
365/// methods will panic.
366#[derive(Copy, Clone, Debug)]
367#[repr(transparent)] // here for the C API
368pub struct Table(Stored<wasmtime_runtime::ExportTable>);
369
370impl Table {
371    /// Creates a new [`Table`] with the given parameters.
372    ///
373    /// * `store` - the owner of the resulting [`Table`]
374    /// * `ty` - the type of this table, containing both the element type as
375    ///   well as the initial size and maximum size, if any.
376    /// * `init` - the initial value to fill all table entries with, if the
377    ///   table starts with an initial size.
378    ///
379    /// # Errors
380    ///
381    /// Returns an error if `init` does not match the element type of the table,
382    /// or if `init` does not belong to the `store` provided.
383    ///
384    /// # Panics
385    ///
386    /// This function will panic when used with a [`Store`](`crate::Store`)
387    /// which has a [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`)
388    /// (see also: [`Store::limiter_async`](`crate::Store::limiter_async`).
389    /// When using an async resource limiter, use [`Table::new_async`]
390    /// instead.
391    ///
392    /// # Examples
393    ///
394    /// ```
395    /// # use wasmtime::*;
396    /// # fn main() -> anyhow::Result<()> {
397    /// let engine = Engine::default();
398    /// let mut store = Store::new(&engine, ());
399    ///
400    /// let ty = TableType::new(ValType::FuncRef, 2, None);
401    /// let table = Table::new(&mut store, ty, Val::FuncRef(None))?;
402    ///
403    /// let module = Module::new(
404    ///     &engine,
405    ///     "(module
406    ///         (table (import \"\" \"\") 2 funcref)
407    ///         (func $f (result i32)
408    ///             i32.const 10)
409    ///         (elem (i32.const 0) $f)
410    ///     )"
411    /// )?;
412    ///
413    /// let instance = Instance::new(&mut store, &module, &[table.into()])?;
414    /// // ...
415    /// # Ok(())
416    /// # }
417    /// ```
418    pub fn new(mut store: impl AsContextMut, ty: TableType, init: Val) -> Result<Table> {
419        Table::_new(store.as_context_mut().0, ty, init)
420    }
421
422    #[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
423    /// Async variant of [`Table::new`]. You must use this variant with
424    /// [`Store`](`crate::Store`)s which have a
425    /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
426    ///
427    /// # Panics
428    ///
429    /// This function will panic when used with a non-async
430    /// [`Store`](`crate::Store`)
431    #[cfg(feature = "async")]
432    pub async fn new_async<T>(
433        mut store: impl AsContextMut<Data = T>,
434        ty: TableType,
435        init: Val,
436    ) -> Result<Table>
437    where
438        T: Send,
439    {
440        let mut store = store.as_context_mut();
441        assert!(
442            store.0.async_support(),
443            "cannot use `new_async` without enabling async support on the config"
444        );
445        store
446            .on_fiber(|store| Table::_new(store.0, ty, init))
447            .await?
448    }
449
450    fn _new(store: &mut StoreOpaque, ty: TableType, init: Val) -> Result<Table> {
451        let wasmtime_export = generate_table_export(store, &ty)?;
452        let init = init.into_table_element(store, ty.element())?;
453        unsafe {
454            let table = Table::from_wasmtime_table(wasmtime_export, store);
455            (*table.wasmtime_table(store, std::iter::empty())).fill(0, init, ty.minimum())?;
456
457            Ok(table)
458        }
459    }
460
461    /// Returns the underlying type of this table, including its element type as
462    /// well as the maximum/minimum lower bounds.
463    ///
464    /// # Panics
465    ///
466    /// Panics if `store` does not own this table.
467    pub fn ty(&self, store: impl AsContext) -> TableType {
468        let store = store.as_context();
469        let ty = &store[self.0].table.table;
470        TableType::from_wasmtime_table(ty)
471    }
472
473    fn wasmtime_table(
474        &self,
475        store: &mut StoreOpaque,
476        lazy_init_range: impl Iterator<Item = u32>,
477    ) -> *mut runtime::Table {
478        unsafe {
479            let export = &store[self.0];
480            let mut handle = InstanceHandle::from_vmctx(export.vmctx);
481            let idx = handle.table_index(&*export.definition);
482            handle.get_defined_table_with_lazy_init(idx, lazy_init_range)
483        }
484    }
485
486    /// Returns the table element value at `index`.
487    ///
488    /// Returns `None` if `index` is out of bounds.
489    ///
490    /// # Panics
491    ///
492    /// Panics if `store` does not own this table.
493    pub fn get(&self, mut store: impl AsContextMut, index: u32) -> Option<Val> {
494        let store = store.as_context_mut().0;
495        let table = self.wasmtime_table(store, std::iter::once(index));
496        unsafe {
497            match (*table).get(index)? {
498                runtime::TableElement::FuncRef(f) => {
499                    let func = Func::from_caller_checked_anyfunc(store, f);
500                    Some(Val::FuncRef(func))
501                }
502                runtime::TableElement::ExternRef(None) => Some(Val::ExternRef(None)),
503                runtime::TableElement::ExternRef(Some(x)) => {
504                    Some(Val::ExternRef(Some(ExternRef { inner: x })))
505                }
506                runtime::TableElement::UninitFunc => {
507                    unreachable!("lazy init above should have converted UninitFunc")
508                }
509            }
510        }
511    }
512
513    /// Writes the `val` provided into `index` within this table.
514    ///
515    /// # Errors
516    ///
517    /// Returns an error if `index` is out of bounds, if `val` does not have
518    /// the right type to be stored in this table, or if `val` belongs to a
519    /// different store.
520    ///
521    /// # Panics
522    ///
523    /// Panics if `store` does not own this table.
524    pub fn set(&self, mut store: impl AsContextMut, index: u32, val: Val) -> Result<()> {
525        let store = store.as_context_mut().0;
526        let ty = self.ty(&store).element().clone();
527        let val = val.into_table_element(store, ty)?;
528        let table = self.wasmtime_table(store, std::iter::empty());
529        unsafe {
530            (*table)
531                .set(index, val)
532                .map_err(|()| anyhow!("table element index out of bounds"))
533        }
534    }
535
536    /// Returns the current size of this table.
537    ///
538    /// # Panics
539    ///
540    /// Panics if `store` does not own this table.
541    pub fn size(&self, store: impl AsContext) -> u32 {
542        self.internal_size(store.as_context().0)
543    }
544
545    pub(crate) fn internal_size(&self, store: &StoreOpaque) -> u32 {
546        unsafe { (*store[self.0].definition).current_elements }
547    }
548
549    /// Grows the size of this table by `delta` more elements, initialization
550    /// all new elements to `init`.
551    ///
552    /// Returns the previous size of this table if successful.
553    ///
554    /// # Errors
555    ///
556    /// Returns an error if the table cannot be grown by `delta`, for example
557    /// if it would cause the table to exceed its maximum size. Also returns an
558    /// error if `init` is not of the right type or if `init` does not belong to
559    /// `store`.
560    ///
561    /// # Panics
562    ///
563    /// Panics if `store` does not own this table.
564    ///
565    /// This function will panic when used with a [`Store`](`crate::Store`)
566    /// which has a [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`)
567    /// (see also: [`Store::limiter_async`](`crate::Store::limiter_async`)).
568    /// When using an async resource limiter, use [`Table::grow_async`]
569    /// instead.
570    pub fn grow(&self, mut store: impl AsContextMut, delta: u32, init: Val) -> Result<u32> {
571        let store = store.as_context_mut().0;
572        let ty = self.ty(&store).element().clone();
573        let init = init.into_table_element(store, ty)?;
574        let table = self.wasmtime_table(store, std::iter::empty());
575        unsafe {
576            match (*table).grow(delta, init, store)? {
577                Some(size) => {
578                    let vm = (*table).vmtable();
579                    *store[self.0].definition = vm;
580                    Ok(size)
581                }
582                None => bail!("failed to grow table by `{}`", delta),
583            }
584        }
585    }
586
587    #[cfg_attr(nightlydoc, doc(cfg(feature = "async")))]
588    /// Async variant of [`Table::grow`]. Required when using a
589    /// [`ResourceLimiterAsync`](`crate::ResourceLimiterAsync`).
590    ///
591    /// # Panics
592    ///
593    /// This function will panic when used with a non-async
594    /// [`Store`](`crate::Store`).
595    #[cfg(feature = "async")]
596    pub async fn grow_async<T>(
597        &self,
598        mut store: impl AsContextMut<Data = T>,
599        delta: u32,
600        init: Val,
601    ) -> Result<u32>
602    where
603        T: Send,
604    {
605        let mut store = store.as_context_mut();
606        assert!(
607            store.0.async_support(),
608            "cannot use `grow_async` without enabling async support on the config"
609        );
610        store
611            .on_fiber(|store| self.grow(store, delta, init))
612            .await?
613    }
614
615    /// Copy `len` elements from `src_table[src_index..]` into
616    /// `dst_table[dst_index..]`.
617    ///
618    /// # Errors
619    ///
620    /// Returns an error if the range is out of bounds of either the source or
621    /// destination tables.
622    ///
623    /// # Panics
624    ///
625    /// Panics if `store` does not own either `dst_table` or `src_table`.
626    pub fn copy(
627        mut store: impl AsContextMut,
628        dst_table: &Table,
629        dst_index: u32,
630        src_table: &Table,
631        src_index: u32,
632        len: u32,
633    ) -> Result<()> {
634        let store = store.as_context_mut().0;
635        if dst_table.ty(&store).element() != src_table.ty(&store).element() {
636            bail!("tables do not have the same element type");
637        }
638
639        let dst_table = dst_table.wasmtime_table(store, std::iter::empty());
640        let src_range = src_index..(src_index.checked_add(len).unwrap_or(u32::MAX));
641        let src_table = src_table.wasmtime_table(store, src_range);
642        unsafe {
643            runtime::Table::copy(dst_table, src_table, dst_index, src_index, len)?;
644        }
645        Ok(())
646    }
647
648    /// Fill `table[dst..(dst + len)]` with the given value.
649    ///
650    /// # Errors
651    ///
652    /// Returns an error if
653    ///
654    /// * `val` is not of the same type as this table's
655    ///   element type,
656    ///
657    /// * the region to be filled is out of bounds, or
658    ///
659    /// * `val` comes from a different `Store` from this table.
660    ///
661    /// # Panics
662    ///
663    /// Panics if `store` does not own either `dst_table` or `src_table`.
664    pub fn fill(&self, mut store: impl AsContextMut, dst: u32, val: Val, len: u32) -> Result<()> {
665        let store = store.as_context_mut().0;
666        let ty = self.ty(&store).element().clone();
667        let val = val.into_table_element(store, ty)?;
668
669        let table = self.wasmtime_table(store, std::iter::empty());
670        unsafe {
671            (*table).fill(dst, val, len)?;
672        }
673
674        Ok(())
675    }
676
677    pub(crate) unsafe fn from_wasmtime_table(
678        wasmtime_export: wasmtime_runtime::ExportTable,
679        store: &mut StoreOpaque,
680    ) -> Table {
681        Table(store.store_data_mut().insert(wasmtime_export))
682    }
683
684    pub(crate) fn wasmtime_ty<'a>(&self, data: &'a StoreData) -> &'a wasmtime_environ::Table {
685        &data[self.0].table.table
686    }
687
688    pub(crate) fn vmimport(&self, store: &StoreOpaque) -> wasmtime_runtime::VMTableImport {
689        let export = &store[self.0];
690        wasmtime_runtime::VMTableImport {
691            from: export.definition,
692            vmctx: export.vmctx,
693        }
694    }
695}
696
697// Exports
698
699/// An exported WebAssembly value.
700///
701/// This type is primarily accessed from the
702/// [`Instance::exports`](crate::Instance::exports) accessor and describes what
703/// names and items are exported from a wasm instance.
704#[derive(Clone)]
705pub struct Export<'instance> {
706    /// The name of the export.
707    name: &'instance str,
708
709    /// The definition of the export.
710    definition: Extern,
711}
712
713impl<'instance> Export<'instance> {
714    /// Creates a new export which is exported with the given `name` and has the
715    /// given `definition`.
716    pub(crate) fn new(name: &'instance str, definition: Extern) -> Export<'instance> {
717        Export { name, definition }
718    }
719
720    /// Returns the name by which this export is known.
721    pub fn name(&self) -> &'instance str {
722        self.name
723    }
724
725    /// Return the `ExternType` of this export.
726    ///
727    /// # Panics
728    ///
729    /// Panics if `store` does not own this `Extern`.
730    pub fn ty(&self, store: impl AsContext) -> ExternType {
731        self.definition.ty(store)
732    }
733
734    /// Consume this `Export` and return the contained `Extern`.
735    pub fn into_extern(self) -> Extern {
736        self.definition
737    }
738
739    /// Consume this `Export` and return the contained `Func`, if it's a function,
740    /// or `None` otherwise.
741    pub fn into_func(self) -> Option<Func> {
742        self.definition.into_func()
743    }
744
745    /// Consume this `Export` and return the contained `Table`, if it's a table,
746    /// or `None` otherwise.
747    pub fn into_table(self) -> Option<Table> {
748        self.definition.into_table()
749    }
750
751    /// Consume this `Export` and return the contained `Memory`, if it's a memory,
752    /// or `None` otherwise.
753    pub fn into_memory(self) -> Option<Memory> {
754        self.definition.into_memory()
755    }
756
757    /// Consume this `Export` and return the contained `Global`, if it's a global,
758    /// or `None` otherwise.
759    pub fn into_global(self) -> Option<Global> {
760        self.definition.into_global()
761    }
762}