wasmedge_sys/instance/
global.rsuse crate::{ffi, WasmEdgeResult, WasmValue};
use wasmedge_types::{
error::{GlobalError, WasmEdgeError},
Mutability, ValType,
};
#[derive(Debug)]
pub struct Global {
pub(crate) inner: InnerGlobal,
}
impl Global {
pub fn create(ty: &wasmedge_types::GlobalType, val: WasmValue) -> WasmEdgeResult<Self> {
let ty: GlobalType = ty.into();
let ctx = unsafe { ffi::WasmEdge_GlobalInstanceCreate(ty.inner.0, val.as_raw()) };
if ctx.is_null() {
Err(Box::new(WasmEdgeError::Global(GlobalError::Create)))
} else {
Ok(Self {
inner: InnerGlobal(ctx),
})
}
}
pub fn ty(&self) -> WasmEdgeResult<wasmedge_types::GlobalType> {
let ty_ctx = unsafe { ffi::WasmEdge_GlobalInstanceGetGlobalType(self.inner.0) };
match ty_ctx.is_null() {
true => Err(Box::new(WasmEdgeError::Global(GlobalError::Type))),
false => {
let ty = std::mem::ManuallyDrop::new(GlobalType {
inner: InnerGlobalType(ty_ctx as *mut _),
});
Ok((&*ty).into())
}
}
}
pub fn get_value(&self) -> WasmValue {
let val = unsafe { ffi::WasmEdge_GlobalInstanceGetValue(self.inner.0) };
val.into()
}
pub fn set_value(&mut self, val: WasmValue) -> WasmEdgeResult<()> {
let ty = self.ty()?;
if ty.mutability() == Mutability::Const {
return Err(Box::new(WasmEdgeError::Global(GlobalError::ModifyConst)));
}
if ty.value_ty() != val.ty() {
return Err(Box::new(WasmEdgeError::Global(
GlobalError::UnmatchedValType,
)));
}
unsafe {
let result = ffi::WasmEdge_GlobalInstanceSetValue(self.inner.0, val.as_raw());
crate::utils::check(result)?;
}
Ok(())
}
pub unsafe fn as_ptr(&self) -> *const ffi::WasmEdge_GlobalInstanceContext {
self.inner.0 as *const _
}
pub unsafe fn from_raw(ptr: *mut ffi::WasmEdge_GlobalInstanceContext) -> Self {
Self {
inner: InnerGlobal(ptr),
}
}
}
impl Drop for Global {
fn drop(&mut self) {
unsafe { ffi::WasmEdge_GlobalInstanceDelete(self.inner.0) };
}
}
#[derive(Debug)]
pub(crate) struct InnerGlobal(pub(crate) *mut ffi::WasmEdge_GlobalInstanceContext);
unsafe impl Send for InnerGlobal {}
unsafe impl Sync for InnerGlobal {}
#[derive(Debug)]
pub(crate) struct GlobalType {
pub(crate) inner: InnerGlobalType,
}
impl GlobalType {
pub(crate) fn create(val_ty: ValType, mutable: Mutability) -> WasmEdgeResult<Self> {
let ctx = unsafe { ffi::WasmEdge_GlobalTypeCreate(val_ty.into(), mutable.into()) };
match ctx.is_null() {
true => Err(Box::new(WasmEdgeError::GlobalTypeCreate)),
false => Ok(Self {
inner: InnerGlobalType(ctx),
}),
}
}
pub(crate) fn value_type(&self) -> ValType {
let val = unsafe { ffi::WasmEdge_GlobalTypeGetValType(self.inner.0 as *const _) };
val.into()
}
pub(crate) fn mutability(&self) -> Mutability {
let val = unsafe { ffi::WasmEdge_GlobalTypeGetMutability(self.inner.0) };
val.into()
}
}
impl Drop for GlobalType {
fn drop(&mut self) {
unsafe { ffi::WasmEdge_GlobalTypeDelete(self.inner.0) };
}
}
impl From<&wasmedge_types::GlobalType> for GlobalType {
fn from(ty: &wasmedge_types::GlobalType) -> Self {
GlobalType::create(ty.value_ty(), ty.mutability()).expect(
"[wasmedge-sys] Failed to convert wasmedge_types::GlobalType into wasmedge_sys::GlobalType.",
)
}
}
impl From<wasmedge_types::GlobalType> for GlobalType {
fn from(ty: wasmedge_types::GlobalType) -> Self {
(&ty).into()
}
}
impl From<&GlobalType> for wasmedge_types::GlobalType {
fn from(ty: &GlobalType) -> Self {
wasmedge_types::GlobalType::new(ty.value_type(), ty.mutability())
}
}
#[derive(Debug)]
pub(crate) struct InnerGlobalType(pub(crate) *mut ffi::WasmEdge_GlobalTypeContext);
unsafe impl Send for InnerGlobalType {}
unsafe impl Sync for InnerGlobalType {}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
use wasmedge_types::{Mutability, ValType};
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_global_type() {
let result = GlobalType::create(ValType::I32, Mutability::Const);
assert!(result.is_ok());
let global_ty = result.unwrap();
assert!(!global_ty.inner.0.is_null());
assert_eq!(global_ty.value_type(), ValType::I32);
assert_eq!(global_ty.mutability(), Mutability::Const);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_global_const_i32() {
let ty = wasmedge_types::GlobalType::new(ValType::I32, Mutability::Const);
let result = Global::create(&ty, WasmValue::from_i32(99));
assert!(result.is_ok());
let mut global_const = result.unwrap();
assert_eq!(global_const.get_value().to_i32(), 99);
let result = global_const.set_value(WasmValue::from_i32(0));
assert!(result.is_err());
let result = global_const.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.value_ty(), ValType::I32);
assert_eq!(ty.mutability(), Mutability::Const);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_global_var_f32() {
let ty = wasmedge_types::GlobalType::new(ValType::F32, Mutability::Var);
let result = Global::create(&ty, WasmValue::from_f32(13.14));
assert!(result.is_ok());
let mut global_var = result.unwrap();
assert_eq!(global_var.get_value().to_f32(), 13.14);
let result = global_var.set_value(WasmValue::from_f32(1.314));
assert!(result.is_ok());
assert_eq!(global_var.get_value().to_f32(), 1.314);
let result = global_var.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.value_ty(), ValType::F32);
assert_eq!(ty.mutability(), Mutability::Var);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_global_conflict() {
{
let ty = wasmedge_types::GlobalType::new(ValType::F32, Mutability::Var);
let result = Global::create(&ty, WasmValue::from_i32(520));
assert!(result.is_err());
}
{
let ty = wasmedge_types::GlobalType::new(ValType::F32, Mutability::Var);
let result = Global::create(&ty, WasmValue::from_f32(13.14));
assert!(result.is_ok());
let mut global_var = result.unwrap();
let result = global_var.set_value(WasmValue::from_i32(1314));
assert!(result.is_err());
assert_eq!(global_var.get_value().to_f32(), 13.14);
let result = global_var.set_value(WasmValue::from_f32(1.314));
assert!(result.is_ok());
assert_eq!(global_var.get_value().to_f32(), 1.314);
}
}
#[test]
fn test_global_send() {
{
let global_ty = wasmedge_types::GlobalType::new(ValType::I32, Mutability::Const);
let result = Global::create(&global_ty, WasmValue::from_i32(5));
assert!(result.is_ok());
let global = result.unwrap();
let handle = thread::spawn(move || {
assert_eq!(global.get_value().to_i32(), 5);
});
handle.join().unwrap()
}
}
#[test]
fn test_global_sync() {
let global_ty = wasmedge_types::GlobalType::new(ValType::I32, Mutability::Const);
let result = Global::create(&global_ty, WasmValue::from_i32(5));
assert!(result.is_ok());
let global = result.unwrap();
let global = &global;
std::thread::scope(|s| {
let _ = s
.spawn(move || {
assert_eq!(global.get_value().to_i32(), 5);
})
.join();
})
}
}