use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::{Store, StoreObject};
use crate::types::Val;
use crate::GlobalType;
use crate::Mutability;
use crate::RuntimeError;
use std::fmt;
use std::sync::Arc;
use wasmer_engine::{Export, ExportGlobal};
use wasmer_vm::{Global as RuntimeGlobal, VMExportGlobal};
#[derive(Clone)]
pub struct Global {
store: Store,
global: Arc<RuntimeGlobal>,
}
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> {
if !val.comes_from_same_store(store) {
return Err(RuntimeError::new("cross-`Store` globals are not supported"));
}
let global = RuntimeGlobal::new(GlobalType {
mutability,
ty: val.ty(),
});
unsafe {
global
.set_unchecked(val.clone())
.map_err(|e| RuntimeError::new(format!("create global for {:?}: {}", val, e)))?;
};
Ok(Self {
store: store.clone(),
global: Arc::new(global),
})
}
pub fn ty(&self) -> &GlobalType {
self.global.ty()
}
pub fn store(&self) -> &Store {
&self.store
}
pub fn get(&self) -> Val {
self.global.get()
}
pub fn set(&self, val: Val) -> Result<(), RuntimeError> {
if !val.comes_from_same_store(&self.store) {
return Err(RuntimeError::new("cross-`Store` values are not supported"));
}
unsafe {
self.global
.set(val)
.map_err(|e| RuntimeError::new(format!("{}", e)))?;
}
Ok(())
}
pub(crate) fn from_vm_export(store: &Store, wasmer_export: ExportGlobal) -> Self {
Self {
store: store.clone(),
global: wasmer_export.vm_global.from,
}
}
pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.global, &other.global)
}
}
impl fmt::Debug for Global {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_struct("Global")
.field("ty", &self.ty())
.field("value", &self.get())
.finish()
}
}
impl<'a> Exportable<'a> for Global {
fn to_export(&self) -> Export {
ExportGlobal {
vm_global: VMExportGlobal {
from: self.global.clone(),
instance_ref: None,
},
}
.into()
}
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
match _extern {
Extern::Global(global) => Ok(global),
_ => Err(ExportError::IncompatibleType),
}
}
}