linera_wasmer/externals/
table.rs

1#[cfg(feature = "js")]
2use crate::js::externals::table as table_impl;
3#[cfg(feature = "jsc")]
4use crate::jsc::externals::table as table_impl;
5#[cfg(feature = "sys")]
6use crate::sys::externals::table as table_impl;
7
8use crate::exports::{ExportError, Exportable};
9use crate::store::{AsStoreMut, AsStoreRef};
10use crate::vm::{VMExtern, VMExternTable};
11use crate::Extern;
12use crate::RuntimeError;
13use crate::TableType;
14use crate::Value;
15
16/// A WebAssembly `table` instance.
17///
18/// The `Table` struct is an array-like structure representing a WebAssembly Table,
19/// which stores function references.
20///
21/// A table created by the host or in WebAssembly code will be accessible and
22/// mutable from both host and WebAssembly.
23///
24/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
25#[derive(Debug, Clone, PartialEq)]
26#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
27pub struct Table(pub(crate) table_impl::Table);
28
29impl Table {
30    /// Creates a new `Table` with the provided [`TableType`] definition.
31    ///
32    /// All the elements in the table will be set to the `init` value.
33    ///
34    /// This function will construct the `Table` using the store `BaseTunables`.
35    pub fn new(
36        store: &mut impl AsStoreMut,
37        ty: TableType,
38        init: Value,
39    ) -> Result<Self, RuntimeError> {
40        Ok(Self(table_impl::Table::new(store, ty, init)?))
41    }
42
43    /// Returns the [`TableType`] of the `Table`.
44    pub fn ty(&self, store: &impl AsStoreRef) -> TableType {
45        self.0.ty(store)
46    }
47
48    /// Retrieves an element of the table at the provided `index`.
49    pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option<Value> {
50        self.0.get(store, index)
51    }
52
53    /// Sets an element `val` in the Table at the provided `index`.
54    pub fn set(
55        &self,
56        store: &mut impl AsStoreMut,
57        index: u32,
58        val: Value,
59    ) -> Result<(), RuntimeError> {
60        self.0.set(store, index, val)
61    }
62
63    /// Retrieves the size of the `Table` (in elements)
64    pub fn size(&self, store: &impl AsStoreRef) -> u32 {
65        self.0.size(store)
66    }
67
68    /// Grows the size of the `Table` by `delta`, initializating
69    /// the elements with the provided `init` value.
70    ///
71    /// It returns the previous size of the `Table` in case is able
72    /// to grow the Table successfully.
73    ///
74    /// # Errors
75    ///
76    /// Returns an error if the `delta` is out of bounds for the table.
77    pub fn grow(
78        &self,
79        store: &mut impl AsStoreMut,
80        delta: u32,
81        init: Value,
82    ) -> Result<u32, RuntimeError> {
83        self.0.grow(store, delta, init)
84    }
85
86    /// Copies the `len` elements of `src_table` starting at `src_index`
87    /// to the destination table `dst_table` at index `dst_index`.
88    ///
89    /// # Errors
90    ///
91    /// Returns an error if the range is out of bounds of either the source or
92    /// destination tables.
93    pub fn copy(
94        store: &mut impl AsStoreMut,
95        dst_table: &Self,
96        dst_index: u32,
97        src_table: &Self,
98        src_index: u32,
99        len: u32,
100    ) -> Result<(), RuntimeError> {
101        table_impl::Table::copy(store, &dst_table.0, dst_index, &src_table.0, src_index, len)
102    }
103
104    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, extern_: VMExternTable) -> Self {
105        Self(table_impl::Table::from_vm_extern(store, extern_))
106    }
107
108    /// Checks whether this `Table` can be used with the given context.
109    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
110        self.0.is_from_store(store)
111    }
112
113    pub(crate) fn to_vm_extern(&self) -> VMExtern {
114        self.0.to_vm_extern()
115    }
116}
117
118impl std::cmp::Eq for Table {}
119
120impl<'a> Exportable<'a> for Table {
121    fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
122        match _extern {
123            Extern::Table(table) => Ok(table),
124            _ => Err(ExportError::IncompatibleType),
125        }
126    }
127}
128
129/// Check the example from <https://github.com/wasmerio/wasmer/issues/3197>.
130#[test]
131fn test_table_grow_issue_3197() {
132    use crate::{imports, Instance, Module, Store, Table, TableType, Type, Value};
133
134    const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#;
135
136    // Tests that the table type of `table` is compatible with the export in the WAT
137    // This tests that `wasmer_types::types::is_table_compatible` works as expected.
138    let mut store = Store::default();
139    let module = Module::new(&store, WAT).unwrap();
140    let ty = TableType::new(Type::FuncRef, 0, None);
141    let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap();
142    table.grow(&mut store, 100, Value::FuncRef(None)).unwrap();
143    assert_eq!(table.ty(&store).minimum, 0);
144    let imports = imports! {"env" => {"table" => table}};
145    let _instance = Instance::new(&mut store, &module, &imports).unwrap();
146}