use crate::js::export::Export;
use crate::js::export::VMGlobal;
use crate::js::exports::{ExportError, Exportable};
use crate::js::externals::Extern;
use crate::js::store::Store;
use crate::js::types::{Val, ValType};
use crate::js::wasm_bindgen_polyfill::Global as JSGlobal;
use crate::js::GlobalType;
use crate::js::Mutability;
use crate::js::RuntimeError;
use wasm_bindgen::JsValue;
#[derive(Debug, Clone, PartialEq)]
pub struct Global {
store: Store,
vm_global: VMGlobal,
}
impl Global {
pub fn new(store: &Store, val: Val) -> Self {
Self::from_value(store, val, Mutability::Const).unwrap()
}
pub fn new_mut(store: &Store, val: Val) -> Self {
Self::from_value(store, val, Mutability::Var).unwrap()
}
fn from_value(store: &Store, val: Val, mutability: Mutability) -> Result<Self, RuntimeError> {
let global_ty = GlobalType {
mutability,
ty: val.ty(),
};
let descriptor = js_sys::Object::new();
let (type_str, value) = match val {
Val::I32(i) => ("i32", JsValue::from_f64(i as _)),
Val::I64(i) => ("i64", JsValue::from_f64(i as _)),
Val::F32(f) => ("f32", JsValue::from_f64(f as _)),
Val::F64(f) => ("f64", JsValue::from_f64(f)),
_ => unimplemented!("The type is not yet supported in the JS Global API"),
};
js_sys::Reflect::set(&descriptor, &"value".into(), &type_str.into())?;
js_sys::Reflect::set(
&descriptor,
&"mutable".into(),
&mutability.is_mutable().into(),
)?;
let js_global = JSGlobal::new(&descriptor, &value).unwrap();
let global = VMGlobal::new(js_global, global_ty);
Ok(Self {
store: store.clone(),
vm_global: global,
})
}
pub fn ty(&self) -> &GlobalType {
&self.vm_global.ty
}
pub fn store(&self) -> &Store {
&self.store
}
pub fn get(&self) -> Val {
match self.vm_global.ty.ty {
ValType::I32 => Val::I32(self.vm_global.global.value().as_f64().unwrap() as _),
ValType::I64 => Val::I64(self.vm_global.global.value().as_f64().unwrap() as _),
ValType::F32 => Val::F32(self.vm_global.global.value().as_f64().unwrap() as _),
ValType::F64 => Val::F64(self.vm_global.global.value().as_f64().unwrap()),
_ => unimplemented!("The type is not yet supported in the JS Global API"),
}
}
pub fn set(&self, val: Val) -> Result<(), RuntimeError> {
if self.vm_global.ty.mutability == Mutability::Const {
return Err(RuntimeError::new("The global is immutable".to_owned()));
}
if val.ty() != self.vm_global.ty.ty {
return Err(RuntimeError::new("The types don't match".to_owned()));
}
let new_value = match val {
Val::I32(i) => JsValue::from_f64(i as _),
Val::I64(i) => JsValue::from_f64(i as _),
Val::F32(f) => JsValue::from_f64(f as _),
Val::F64(f) => JsValue::from_f64(f),
_ => unimplemented!("The type is not yet supported in the JS Global API"),
};
self.vm_global.global.set_value(&new_value);
Ok(())
}
pub(crate) fn from_vm_export(store: &Store, vm_global: VMGlobal) -> Self {
Self {
store: store.clone(),
vm_global,
}
}
pub fn same(&self, other: &Self) -> bool {
self.vm_global == other.vm_global
}
}
impl<'a> Exportable<'a> for Global {
fn to_export(&self) -> Export {
Export::Global(self.vm_global.clone())
}
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
match _extern {
Extern::Global(global) => Ok(global),
_ => Err(ExportError::IncompatibleType),
}
}
}