Skip to main content

wasmedge_sys/instance/
global.rs

1//! Defines WasmEdge Global and GlobalType structs.
2//!
3//! A WasmEdge `Global` defines a global variable, which stores a single value of the given `GlobalType`.
4//! `GlobalType` specifies whether a global variable is immutable or mutable.
5
6use crate::{ffi, WasmEdgeResult, WasmValue};
7use wasmedge_types::{
8    error::{GlobalError, WasmEdgeError},
9    Mutability, ValType,
10};
11
12/// Defines a WebAssembly global variable, which stores a single value of the given [type](crate::GlobalType) and a flag indicating whether it is mutable or not.
13#[derive(Debug)]
14pub struct Global {
15    pub(crate) inner: InnerGlobal,
16}
17impl Global {
18    /// Creates a new [Global] instance to be associated with the given [GlobalType] and [WasmValue](crate::WasmValue).
19    ///
20    /// The type of the given [WasmValue](crate::WasmValue) must be matched with [GlobalType]; otherwise, it causes a failure. For example, `WasmValue::I32(520)` conflicts with a [GlobalType] with a value type defined as `ValType::F32`.
21    ///
22    /// # Errors
23    ///
24    /// * If fail to create the Global instance, then WasmEdgeError::Global(GlobalError::Create)(crate::error::GlobalError) is returned.
25    ///
26    pub fn create(ty: &wasmedge_types::GlobalType, val: WasmValue) -> WasmEdgeResult<Self> {
27        let ty: GlobalType = ty.into();
28        let ctx = unsafe { ffi::WasmEdge_GlobalInstanceCreate(ty.inner.0, val.as_raw()) };
29
30        if ctx.is_null() {
31            Err(Box::new(WasmEdgeError::Global(GlobalError::Create)))
32        } else {
33            Ok(Self {
34                inner: InnerGlobal(ctx),
35            })
36        }
37    }
38
39    /// Returns the underlying wasm type of a [Global] instance.
40    ///
41    /// # Errors
42    ///
43    /// If fail to get the type, then an error is returned.
44    ///
45    pub fn ty(&self) -> WasmEdgeResult<wasmedge_types::GlobalType> {
46        let ty_ctx = unsafe { ffi::WasmEdge_GlobalInstanceGetGlobalType(self.inner.0) };
47        match ty_ctx.is_null() {
48            true => Err(Box::new(WasmEdgeError::Global(GlobalError::Type))),
49            false => {
50                let ty = std::mem::ManuallyDrop::new(GlobalType {
51                    inner: InnerGlobalType(ty_ctx as *mut _),
52                });
53                Ok((&*ty).into())
54            }
55        }
56    }
57
58    /// Returns the value of the [Global] instance.
59    pub fn get_value(&self) -> WasmValue {
60        let val = unsafe { ffi::WasmEdge_GlobalInstanceGetValue(self.inner.0) };
61        val.into()
62    }
63
64    /// Sets the value of the [Global] instance.
65    ///
66    /// Notice that only the [Global] instance of [Mutability::Var](wasmedge_types::Mutability::Var) type can be set a new value. Setting a new value for a [Global] of [Mutability::Const](wasmedge_types::Mutability::Const) causes a failure.
67    ///
68    /// # Argument
69    ///
70    /// * `val` - The new wasm value to be set.
71    ///
72    /// # Errors
73    ///
74    /// If fail to set value, then an error is returned.
75    ///
76    pub fn set_value(&mut self, val: WasmValue) -> WasmEdgeResult<()> {
77        let ty = self.ty()?;
78        if ty.mutability() == Mutability::Const {
79            return Err(Box::new(WasmEdgeError::Global(GlobalError::ModifyConst)));
80        }
81        if ty.value_ty() != val.ty() {
82            return Err(Box::new(WasmEdgeError::Global(
83                GlobalError::UnmatchedValType,
84            )));
85        }
86        unsafe {
87            let result = ffi::WasmEdge_GlobalInstanceSetValue(self.inner.0, val.as_raw());
88            crate::utils::check(result)?;
89        }
90        Ok(())
91    }
92
93    /// # Safety
94    ///
95    /// The lifetime of the returned pointer must not exceed that of the object itself.
96    pub unsafe fn as_ptr(&self) -> *const ffi::WasmEdge_GlobalInstanceContext {
97        self.inner.0 as *const _
98    }
99
100    /// # Safety
101    ///
102    /// This function takes ownership of `ptr`, so do not call `ffi::WasmEdge_GlobalInstanceDelete` on `ptr` after this.
103    pub unsafe fn from_raw(ptr: *mut ffi::WasmEdge_GlobalInstanceContext) -> Self {
104        Self {
105            inner: InnerGlobal(ptr),
106        }
107    }
108}
109impl Drop for Global {
110    fn drop(&mut self) {
111        unsafe { ffi::WasmEdge_GlobalInstanceDelete(self.inner.0) };
112    }
113}
114
115#[derive(Debug)]
116pub(crate) struct InnerGlobal(pub(crate) *mut ffi::WasmEdge_GlobalInstanceContext);
117unsafe impl Send for InnerGlobal {}
118unsafe impl Sync for InnerGlobal {}
119
120/// Defines the type of a wasm global variable.
121///
122/// A [GlobalType] classifies a global variable that hold a value and can either be mutable or immutable.
123#[derive(Debug)]
124pub(crate) struct GlobalType {
125    pub(crate) inner: InnerGlobalType,
126}
127impl GlobalType {
128    /// Create a new [GlobalType] to be associated with the given [ValType](wasmedge_types::ValType) and [Mutability](wasmedge_types::Mutability).
129    ///
130    /// # Arguments
131    ///
132    /// * `val_type` - The value type of the global variable.
133    ///
134    /// * `mutability` - The mutability of the global variable.
135    ///
136    /// # Errors
137    ///
138    /// If fail to create a new [GlobalType], then an error is returned.
139    pub(crate) fn create(val_ty: ValType, mutable: Mutability) -> WasmEdgeResult<Self> {
140        let ctx = unsafe { ffi::WasmEdge_GlobalTypeCreate(val_ty.into(), mutable.into()) };
141        match ctx.is_null() {
142            true => Err(Box::new(WasmEdgeError::GlobalTypeCreate)),
143            false => Ok(Self {
144                inner: InnerGlobalType(ctx),
145            }),
146        }
147    }
148
149    /// Returns the value type of the [GlobalType].
150    pub(crate) fn value_type(&self) -> ValType {
151        let val = unsafe { ffi::WasmEdge_GlobalTypeGetValType(self.inner.0 as *const _) };
152        val.into()
153    }
154
155    /// Returns the [Mutability](wasmedge_types::Mutability) value of the [GlobalType].
156    pub(crate) fn mutability(&self) -> Mutability {
157        let val = unsafe { ffi::WasmEdge_GlobalTypeGetMutability(self.inner.0) };
158        val.into()
159    }
160}
161impl Drop for GlobalType {
162    fn drop(&mut self) {
163        unsafe { ffi::WasmEdge_GlobalTypeDelete(self.inner.0) };
164    }
165}
166impl From<&wasmedge_types::GlobalType> for GlobalType {
167    fn from(ty: &wasmedge_types::GlobalType) -> Self {
168        GlobalType::create(ty.value_ty(), ty.mutability()).expect(
169            "[wasmedge-sys] Failed to convert wasmedge_types::GlobalType into wasmedge_sys::GlobalType.",
170        )
171    }
172}
173impl From<wasmedge_types::GlobalType> for GlobalType {
174    fn from(ty: wasmedge_types::GlobalType) -> Self {
175        (&ty).into()
176    }
177}
178impl From<&GlobalType> for wasmedge_types::GlobalType {
179    fn from(ty: &GlobalType) -> Self {
180        wasmedge_types::GlobalType::new(ty.value_type(), ty.mutability())
181    }
182}
183
184#[derive(Debug)]
185pub(crate) struct InnerGlobalType(pub(crate) *mut ffi::WasmEdge_GlobalTypeContext);
186unsafe impl Send for InnerGlobalType {}
187unsafe impl Sync for InnerGlobalType {}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192    use std::thread;
193    use wasmedge_types::{Mutability, ValType};
194
195    #[test]
196    #[allow(clippy::assertions_on_result_states)]
197    fn test_global_type() {
198        // create a GlobalType instance
199        let result = GlobalType::create(ValType::I32, Mutability::Const);
200        assert!(result.is_ok());
201        let global_ty = result.unwrap();
202        assert!(!global_ty.inner.0.is_null());
203
204        // value type
205        assert_eq!(global_ty.value_type(), ValType::I32);
206        // Mutability
207        assert_eq!(global_ty.mutability(), Mutability::Const);
208    }
209
210    #[test]
211    #[allow(clippy::assertions_on_result_states)]
212    fn test_global_const_i32() {
213        // create a GlobalType instance
214        let ty = wasmedge_types::GlobalType::new(ValType::I32, Mutability::Const);
215
216        // create a const Global instance
217        let result = Global::create(&ty, WasmValue::from_i32(99));
218        assert!(result.is_ok());
219        let mut global_const = result.unwrap();
220
221        // access the value held by global_const
222        assert_eq!(global_const.get_value().to_i32(), 99);
223        let result = global_const.set_value(WasmValue::from_i32(0));
224        assert!(result.is_err());
225
226        // access the global type
227        let result = global_const.ty();
228        assert!(result.is_ok());
229        let ty = result.unwrap();
230        assert_eq!(ty.value_ty(), ValType::I32);
231        assert_eq!(ty.mutability(), Mutability::Const);
232    }
233
234    #[test]
235    #[allow(clippy::assertions_on_result_states)]
236    fn test_global_var_f32() {
237        // create a GlobalType instance
238        let ty = wasmedge_types::GlobalType::new(ValType::F32, Mutability::Var);
239
240        // create a Var Global instance
241        let result = Global::create(&ty, WasmValue::from_f32(13.14));
242        assert!(result.is_ok());
243        let mut global_var = result.unwrap();
244
245        // access the value held by global_var
246        assert_eq!(global_var.get_value().to_f32(), 13.14);
247        let result = global_var.set_value(WasmValue::from_f32(1.314));
248        assert!(result.is_ok());
249        assert_eq!(global_var.get_value().to_f32(), 1.314);
250
251        // access the global type
252        let result = global_var.ty();
253        assert!(result.is_ok());
254        let ty = result.unwrap();
255        assert_eq!(ty.value_ty(), ValType::F32);
256        assert_eq!(ty.mutability(), Mutability::Var);
257    }
258
259    #[test]
260    #[allow(clippy::assertions_on_result_states)]
261    fn test_global_conflict() {
262        {
263            // create a GlobalType instance
264            let ty = wasmedge_types::GlobalType::new(ValType::F32, Mutability::Var);
265
266            // create a Var Global instance with a value of mis-matched Value::I32 type
267            let result = Global::create(&ty, WasmValue::from_i32(520));
268            assert!(result.is_err());
269        }
270
271        {
272            // create a GlobalType instance
273            let ty = wasmedge_types::GlobalType::new(ValType::F32, Mutability::Var);
274
275            // create a Var Global instance with a value of Value::F32 type
276            let result = Global::create(&ty, WasmValue::from_f32(13.14));
277            assert!(result.is_ok());
278            let mut global_var = result.unwrap();
279
280            // set a new value of mis-matched Value::I32 type
281            let result = global_var.set_value(WasmValue::from_i32(1314));
282            assert!(result.is_err());
283            assert_eq!(global_var.get_value().to_f32(), 13.14);
284
285            // set a new value of Value::F32 type
286            let result = global_var.set_value(WasmValue::from_f32(1.314));
287            assert!(result.is_ok());
288            assert_eq!(global_var.get_value().to_f32(), 1.314);
289        }
290    }
291
292    #[test]
293    fn test_global_send() {
294        {
295            // create a GlobalType instance
296            let global_ty = wasmedge_types::GlobalType::new(ValType::I32, Mutability::Const);
297
298            // create a Global instance
299            let result = Global::create(&global_ty, WasmValue::from_i32(5));
300            assert!(result.is_ok());
301            let global = result.unwrap();
302
303            let handle = thread::spawn(move || {
304                // access the value held by global
305                assert_eq!(global.get_value().to_i32(), 5);
306            });
307
308            handle.join().unwrap()
309        }
310    }
311
312    #[test]
313    fn test_global_sync() {
314        // create a GlobalType instance
315        let global_ty = wasmedge_types::GlobalType::new(ValType::I32, Mutability::Const);
316
317        // create a Global instance
318        let result = Global::create(&global_ty, WasmValue::from_i32(5));
319        assert!(result.is_ok());
320        let global = result.unwrap();
321        let global = &global;
322
323        std::thread::scope(|s| {
324            let _ = s
325                .spawn(move || {
326                    assert_eq!(global.get_value().to_i32(), 5);
327                })
328                .join();
329        })
330    }
331}