use crate::{types::Val, TableType, WasmEdgeResult};
use wasmedge_sys as sys;
#[derive(Debug, Clone)]
pub struct Table {
pub(crate) inner: sys::Table,
pub(crate) name: Option<String>,
pub(crate) mod_name: Option<String>,
pub(crate) ty: TableType,
}
impl Table {
pub fn new(ty: TableType) -> WasmEdgeResult<Self> {
let inner = sys::Table::create(&ty.clone().into())?;
Ok(Self {
inner,
name: None,
mod_name: None,
ty,
})
}
pub fn name(&self) -> Option<&str> {
match &self.name {
Some(name) => Some(name.as_ref()),
None => None,
}
}
pub fn mod_name(&self) -> Option<&str> {
match &self.mod_name {
Some(mod_name) => Some(mod_name.as_ref()),
None => None,
}
}
pub fn ty(&self) -> &TableType {
&self.ty
}
pub fn size(&self) -> u32 {
self.inner.capacity() as u32
}
pub fn grow(&mut self, delta: u32, init: Option<Val>) -> WasmEdgeResult<u32> {
let original_size = self.size();
self.inner.grow(delta)?;
if let Some(init) = init {
for idx in original_size..original_size + delta {
self.inner.set_data(init.clone().into(), idx)?;
}
}
Ok(original_size)
}
pub fn get(&self, index: u32) -> WasmEdgeResult<Val> {
let value = self.inner.get_data(index)?;
Ok(value.into())
}
pub fn set(&mut self, index: u32, data: Val) -> WasmEdgeResult<()> {
self.inner.set_data(data.into(), index)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
config::{CommonConfigOptions, ConfigBuilder},
error::HostFuncError,
types::Val,
CallingFrame, Executor, ImportObjectBuilder, NeverType, RefType, Statistics, Store,
ValType, WasmValue,
};
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_table_type() {
let ty = TableType::new(RefType::FuncRef, 10, Some(20));
assert_eq!(ty.elem_ty(), RefType::FuncRef);
assert_eq!(ty.minimum(), 10);
assert_eq!(ty.maximum(), Some(20));
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_table_basic() {
let result = Table::new(TableType::new(RefType::FuncRef, 10, Some(20)));
assert!(result.is_ok());
let table = result.unwrap();
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32, NeverType>("add", real_add, None)
.expect("failed to add host func")
.with_table("table", table)
.build::<NeverType>("extern", None);
assert!(result.is_ok());
let import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &import);
assert!(result.is_ok());
let result = store.named_instance("extern");
assert!(result.is_ok());
let instance = result.unwrap();
let result = instance.func("add");
assert!(result.is_ok());
let host_func = result.unwrap();
let result = instance.table("table");
assert!(result.is_ok());
let mut table = result.unwrap();
assert!(table.name().is_some());
assert_eq!(table.name().unwrap(), "table");
assert!(table.mod_name().is_some());
assert_eq!(table.mod_name().unwrap(), "extern");
assert_eq!(table.size(), 10);
let ty = table.ty();
assert_eq!(ty.elem_ty(), RefType::FuncRef);
assert_eq!(ty.minimum(), 10);
assert_eq!(ty.maximum(), Some(20));
let result = table.get(0);
assert!(result.is_ok());
if let Val::FuncRef(func_ref) = result.unwrap() {
assert!(func_ref.is_none());
}
let func_ref = host_func.as_ref();
let result = table.set(0, Val::FuncRef(Some(func_ref)));
assert!(result.is_ok());
let result = table.get(0);
assert!(result.is_ok());
if let Val::FuncRef(func_ref) = result.unwrap() {
assert!(func_ref.is_some());
let func_ref = func_ref.unwrap();
let func_ty = func_ref.ty();
assert!(func_ty.args().is_some());
assert_eq!(func_ty.args().unwrap(), [ValType::I32; 2]);
assert!(func_ty.returns().is_some());
assert_eq!(func_ty.returns().unwrap(), [ValType::I32]);
}
let result = store.named_instance("extern");
assert!(result.is_ok());
let instance = result.unwrap();
let result = instance.table("table");
assert!(result.is_ok());
let table = result.unwrap();
let result = table.get(0);
assert!(result.is_ok());
if let Val::FuncRef(func_ref) = result.unwrap() {
assert!(func_ref.is_some());
let func_ref = func_ref.unwrap();
let func_ty = func_ref.ty();
assert!(func_ty.args().is_some());
assert_eq!(func_ty.args().unwrap(), [ValType::I32; 2]);
assert!(func_ty.returns().is_some());
assert_eq!(func_ty.returns().unwrap(), [ValType::I32]);
}
}
fn real_add(
_frame: CallingFrame,
inputs: Vec<WasmValue>,
_data: *mut std::os::raw::c_void,
) -> std::result::Result<Vec<WasmValue>, HostFuncError> {
if inputs.len() != 2 {
return Err(HostFuncError::User(1));
}
let a = if inputs[0].ty() == ValType::I32 {
inputs[0].to_i32()
} else {
return Err(HostFuncError::User(2));
};
let b = if inputs[1].ty() == ValType::I32 {
inputs[1].to_i32()
} else {
return Err(HostFuncError::User(3));
};
let c = a + b;
Ok(vec![WasmValue::from_i32(c)])
}
}