use crate::js::export::VMFunction;
use crate::js::export::{Export, VMTable};
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::{Extern, Function as WasmerFunction};
use crate::js::store::Store;
use crate::js::types::Val;
use crate::js::RuntimeError;
use crate::js::TableType;
use js_sys::Function;
use wasmer_types::FunctionType;
#[derive(Debug, Clone, PartialEq)]
pub struct Table {
store: Store,
vm_table: VMTable,
}
fn set_table_item(table: &VMTable, item_index: u32, item: &Function) -> Result<(), RuntimeError> {
table.table.set(item_index, item).map_err(|e| e.into())
}
fn get_function(val: Val) -> Result<Function, RuntimeError> {
match val {
Val::FuncRef(func) => Ok(func.as_ref().unwrap().exported.function.clone().into()),
_ => unimplemented!(),
}
}
impl Table {
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
let descriptor = js_sys::Object::new();
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?;
if let Some(max) = ty.maximum {
js_sys::Reflect::set(&descriptor, &"maximum".into(), &max.into())?;
}
js_sys::Reflect::set(&descriptor, &"element".into(), &"anyfunc".into())?;
let js_table = js_sys::WebAssembly::Table::new(&descriptor)?;
let table = VMTable::new(js_table, ty);
let num_elements = table.table.length();
let func = get_function(init)?;
for i in 0..num_elements {
set_table_item(&table, i, &func)?;
}
Ok(Self {
store: store.clone(),
vm_table: table,
})
}
pub fn ty(&self) -> &TableType {
&self.vm_table.ty
}
pub fn store(&self) -> &Store {
&self.store
}
pub fn get(&self, index: u32) -> Option<Val> {
let func = self.vm_table.table.get(index).ok()?;
let ty = FunctionType::new(vec![], vec![]);
Some(Val::FuncRef(Some(WasmerFunction::from_vm_export(
&self.store,
VMFunction::new(func, ty, None),
))))
}
pub fn set(&self, index: u32, val: Val) -> Result<(), RuntimeError> {
let func = get_function(val)?;
set_table_item(&self.vm_table, index, &func)?;
Ok(())
}
pub fn size(&self) -> u32 {
self.vm_table.table.length()
}
pub fn grow(&self, _delta: u32, _init: Val) -> Result<u32, RuntimeError> {
unimplemented!();
}
pub fn copy(
_dst_table: &Self,
_dst_index: u32,
_src_table: &Self,
_src_index: u32,
_len: u32,
) -> Result<(), RuntimeError> {
unimplemented!("Table.copy is not natively supported in Javascript");
}
pub(crate) fn from_vm_export(store: &Store, vm_table: VMTable) -> Self {
Self {
store: store.clone(),
vm_table,
}
}
pub fn same(&self, other: &Self) -> bool {
self.vm_table == other.vm_table
}
#[doc(hidden)]
pub unsafe fn get_vm_table(&self) -> &VMTable {
&self.vm_table
}
}
impl<'a> Exportable<'a> for Table {
fn to_export(&self) -> Export {
Export::Table(self.vm_table.clone())
}
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
match _extern {
Extern::Table(table) => Ok(table),
_ => Err(ExportError::IncompatibleType),
}
}
}