use crate::sys::exports::{ExportError, Exportable};
use crate::sys::externals::Extern;
use crate::sys::store::{Store, StoreObject};
use crate::sys::types::Val;
use crate::sys::GlobalType;
use crate::sys::Mutability;
use crate::sys::RuntimeError;
use loupe::MemoryUsage;
use std::fmt;
use std::sync::Arc;
use wasmer_engine::Export;
use wasmer_vm::{Global as RuntimeGlobal, VMGlobal};
#[derive(MemoryUsage)]
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> {
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(),
vm_global: VMGlobal {
from: Arc::new(global),
instance_ref: None,
},
})
}
pub fn ty(&self) -> &GlobalType {
self.vm_global.from.ty()
}
pub fn store(&self) -> &Store {
&self.store
}
pub fn get(&self) -> Val {
self.vm_global.from.get(&self.store)
}
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.vm_global
.from
.set(val)
.map_err(|e| RuntimeError::new(format!("{}", e)))?;
}
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 {
Arc::ptr_eq(&self.vm_global.from, &other.vm_global.from)
}
#[doc(hidden)]
pub unsafe fn get_vm_global(&self) -> &VMGlobal {
&self.vm_global
}
}
impl Clone for Global {
fn clone(&self) -> Self {
let mut vm_global = self.vm_global.clone();
vm_global.upgrade_instance_ref().unwrap();
Self {
store: self.store.clone(),
vm_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 {
self.vm_global.clone().into()
}
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
match _extern {
Extern::Global(global) => Ok(global),
_ => Err(ExportError::IncompatibleType),
}
}
fn into_weak_instance_ref(&mut self) {
self.vm_global
.instance_ref
.as_mut()
.map(|v| *v = v.downgrade());
}
}