use js_sys::WebAssembly;
use crate::{
AsStoreMut, BackendInstance, Exports, Extern, Imports, InstantiationError, Module,
js::{
utils::{convert::AsJs, js_handle::JsHandle},
vm::VMInstance,
},
};
#[derive(Clone, PartialEq, Eq)]
pub struct Instance {
pub(crate) _handle: JsHandle<VMInstance>,
}
impl Instance {
pub(crate) fn new(
mut store: &mut impl AsStoreMut,
module: &Module,
imports: &Imports,
) -> Result<(Self, Exports), InstantiationError> {
let instance = module
.as_js()
.instantiate(&mut store, imports)
.map_err(InstantiationError::Start)?;
Self::from_module_and_instance(store, module, instance)
}
pub(crate) fn new_by_index(
store: &mut impl AsStoreMut,
module: &Module,
externs: &[Extern],
) -> Result<(Self, Exports), InstantiationError> {
let mut imports = Imports::new();
for (import_ty, extern_ty) in module.imports().zip(externs.iter()) {
imports.define(import_ty.module(), import_ty.name(), extern_ty.clone());
}
Self::new(store, module, &imports)
}
pub(crate) fn from_module_and_instance(
mut store: &mut impl AsStoreMut,
module: &Module,
instance: WebAssembly::Instance,
) -> Result<(Self, Exports), InstantiationError> {
let instance_exports = instance.exports();
let exports = module
.exports()
.map(|export_type| {
let name = export_type.name();
let extern_type = export_type.ty();
#[allow(unused_unsafe)]
let js_export =
unsafe { js_sys::Reflect::get(&instance_exports, &name.into()).unwrap() };
let extern_ = Extern::from_jsvalue(&mut store, extern_type, &js_export)
.map_err(wasm_bindgen::JsValue::from)
.unwrap();
Ok((name.to_string(), extern_))
})
.collect::<Result<Exports, InstantiationError>>()?;
let instance = Self {
_handle: JsHandle::new(instance),
};
Ok((instance, exports))
}
}
impl crate::Instance {
pub fn into_js(self) -> crate::backend::js::instance::Instance {
match self._inner {
BackendInstance::Js(s) => s,
_ => panic!("Not a `js` global!"),
}
}
pub fn as_js(&self) -> &crate::backend::js::instance::Instance {
match self._inner {
BackendInstance::Js(ref s) => s,
_ => panic!("Not a `js` global!"),
}
}
pub fn as_js_mut(&mut self) -> &mut crate::backend::js::instance::Instance {
match self._inner {
BackendInstance::Js(ref mut s) => s,
_ => panic!("Not a `js` global!"),
}
}
}