Skip to main content

wasmedge_sys/
types.rs

1//! Defines the WebAssembly primitive types.
2
3use crate::{ffi, instance::function::AsFunc, FuncRef, Function};
4use core::ffi::c_void;
5use std::ffi::CString;
6use wasmedge_types::ValType;
7
8#[derive(Debug, Clone)]
9pub(crate) struct WasmEdgeLimit {
10    min: u32,
11    max: Option<u32>,
12    shared: bool,
13}
14impl WasmEdgeLimit {
15    pub(crate) fn new(min: u32, max: Option<u32>, shared: bool) -> Self {
16        Self { min, max, shared }
17    }
18
19    pub(crate) fn min(&self) -> u32 {
20        self.min
21    }
22
23    pub(crate) fn max(&self) -> Option<u32> {
24        self.max
25    }
26
27    pub(crate) fn shared(&self) -> bool {
28        self.shared
29    }
30}
31impl WasmEdgeLimit {
32    /// Build an owned `WasmEdge_LimitContext`. Caller must release the
33    /// returned pointer with `WasmEdge_LimitDelete` once any downstream API
34    /// that needs it has been called — all current consumers (`MemoryTypeCreate`,
35    /// `TableTypeCreate`) borrow the limit (declared `const` in the C API),
36    /// so ownership stays with the caller.
37    pub(crate) fn to_context(&self) -> *mut ffi::WasmEdge_LimitContext {
38        unsafe {
39            match self.max {
40                Some(max) => ffi::WasmEdge_LimitCreateWithMax(
41                    self.min as u64,
42                    max as u64,
43                    false, // Is64Bit — wasm32 only for now
44                    self.shared,
45                ),
46                None => ffi::WasmEdge_LimitCreate(self.min as u64, false),
47            }
48        }
49    }
50
51    /// Construct from a borrowed `WasmEdge_LimitContext` (does NOT delete).
52    pub(crate) fn from_context(ctx: *const ffi::WasmEdge_LimitContext) -> Self {
53        unsafe {
54            let min = ffi::WasmEdge_LimitGetMin(ctx) as u32;
55            let max = if ffi::WasmEdge_LimitHasMax(ctx) {
56                Some(ffi::WasmEdge_LimitGetMax(ctx) as u32)
57            } else {
58                None
59            };
60            let shared = ffi::WasmEdge_LimitIsShared(ctx);
61            Self { min, max, shared }
62        }
63    }
64}
65
66/// Struct of WasmEdge String.
67#[derive(Debug)]
68pub struct WasmEdgeString {
69    inner: InnerWasmEdgeString,
70}
71impl Drop for WasmEdgeString {
72    fn drop(&mut self) {
73        unsafe { ffi::WasmEdge_StringDelete(self.inner.0) }
74    }
75}
76impl WasmEdgeString {
77    pub(crate) fn as_raw(&self) -> ffi::WasmEdge_String {
78        self.inner.0
79    }
80
81    /// # Safety
82    ///
83    /// After calling this function, the caller is responsible for managing the lifetime of `ffi::WasmEdge_String`` and should call `ffi::WasmEdge_StringDelete`` at the appropriate time.
84    pub unsafe fn into_raw(self) -> ffi::WasmEdge_String {
85        let s = self.inner.0;
86        std::mem::forget(self);
87        s
88    }
89
90    /// # Safety
91    ///
92    /// This function takes ownership of `s`, so do not call `ffi::WasmEdge_StringDelete` on `s` after this.
93    pub unsafe fn from_raw(s: ffi::WasmEdge_String) -> Self {
94        Self {
95            inner: InnerWasmEdgeString(s),
96        }
97    }
98}
99impl<T: AsRef<str>> From<T> for WasmEdgeString {
100    fn from(s: T) -> Self {
101        let ctx = if s.as_ref().contains('\0') {
102            let buffer = s.as_ref().as_bytes();
103            unsafe {
104                ffi::WasmEdge_StringCreateByBuffer(buffer.as_ptr() as *const _, buffer.len() as u32)
105            }
106        } else {
107            let cs = CString::new(s.as_ref()).expect(
108                "Failed to create a CString: the supplied bytes contain an internal 0 byte",
109            );
110            unsafe { ffi::WasmEdge_StringCreateByCString(cs.as_ptr()) }
111        };
112
113        Self {
114            inner: InnerWasmEdgeString(ctx),
115        }
116    }
117}
118impl PartialEq for WasmEdgeString {
119    fn eq(&self, other: &Self) -> bool {
120        unsafe { ffi::WasmEdge_StringIsEqual(self.inner.0, other.inner.0) }
121    }
122}
123impl Eq for WasmEdgeString {}
124
125impl AsRef<ffi::WasmEdge_String> for WasmEdgeString {
126    fn as_ref(&self) -> &ffi::WasmEdge_String {
127        &self.inner.0
128    }
129}
130impl AsMut<ffi::WasmEdge_String> for WasmEdgeString {
131    fn as_mut(&mut self) -> &mut ffi::WasmEdge_String {
132        &mut self.inner.0
133    }
134}
135
136impl From<&WasmEdgeString> for String {
137    fn from(s: &WasmEdgeString) -> Self {
138        s.as_ref().into()
139    }
140}
141impl From<&WasmEdgeString> for &std::ffi::CStr {
142    fn from(s: &WasmEdgeString) -> Self {
143        s.as_ref().into()
144    }
145}
146impl From<WasmEdgeString> for String {
147    fn from(s: WasmEdgeString) -> Self {
148        s.as_ref().into()
149    }
150}
151impl From<WasmEdgeString> for &std::ffi::CStr {
152    fn from(s: WasmEdgeString) -> Self {
153        s.as_ref().into()
154    }
155}
156
157impl From<&ffi::WasmEdge_String> for String {
158    fn from(s: &ffi::WasmEdge_String) -> Self {
159        let cstr = unsafe { std::slice::from_raw_parts(s.Buf as *mut u8, s.Length as usize) };
160        String::from_utf8(cstr.to_vec()).unwrap_or_default()
161    }
162}
163impl From<&ffi::WasmEdge_String> for &std::ffi::CStr {
164    fn from(s: &ffi::WasmEdge_String) -> Self {
165        unsafe { std::ffi::CStr::from_ptr(s.Buf as *const _) }
166    }
167}
168impl From<ffi::WasmEdge_String> for String {
169    fn from(s: ffi::WasmEdge_String) -> Self {
170        (&s).into()
171    }
172}
173impl From<ffi::WasmEdge_String> for &std::ffi::CStr {
174    fn from(s: ffi::WasmEdge_String) -> Self {
175        (&s).into()
176    }
177}
178
179#[derive(Debug)]
180pub(crate) struct InnerWasmEdgeString(pub(crate) ffi::WasmEdge_String);
181unsafe impl Send for InnerWasmEdgeString {}
182unsafe impl Sync for InnerWasmEdgeString {}
183
184/// Defines a WebAssembly value.
185#[derive(Debug, Clone, Copy)]
186pub struct WasmValue {
187    ctx: ffi::WasmEdge_Value,
188    ty: ValType,
189}
190impl WasmValue {
191    /// Returns the raw `WasmEdge_Value`.
192    pub fn as_raw(&self) -> ffi::WasmEdge_Value {
193        self.ctx
194    }
195
196    /// Returns the type of a [WasmValue].
197    pub fn ty(&self) -> ValType {
198        self.ty
199    }
200
201    /// Creates a [WasmValue] from a `i32` value.
202    ///
203    /// # Argument
204    ///
205    /// * `val` - The source `i32` value.
206    pub fn from_i32(val: i32) -> Self {
207        Self {
208            ctx: unsafe { ffi::WasmEdge_ValueGenI32(val) },
209            ty: ValType::I32,
210        }
211    }
212
213    /// Generates a `i32` value from a [WasmValue].
214    pub fn to_i32(&self) -> i32 {
215        unsafe { ffi::WasmEdge_ValueGetI32(self.ctx) }
216    }
217
218    /// Creates a [WasmValue] from a `i64` value.
219    ///
220    /// # Argument
221    ///
222    /// * `val` - The source `i64` value.
223    pub fn from_i64(val: i64) -> Self {
224        Self {
225            ctx: unsafe { ffi::WasmEdge_ValueGenI64(val) },
226            ty: ValType::I64,
227        }
228    }
229
230    /// Generates a `i64` value from a [WasmValue].
231    pub fn to_i64(&self) -> i64 {
232        unsafe { ffi::WasmEdge_ValueGetI64(self.ctx) }
233    }
234
235    /// Creates a [WasmValue] from a `f32` value.
236    ///
237    /// # Argument
238    ///
239    /// * `val` - The source `f32` value.
240    pub fn from_f32(val: f32) -> Self {
241        Self {
242            ctx: unsafe { ffi::WasmEdge_ValueGenF32(val) },
243            ty: ValType::F32,
244        }
245    }
246
247    /// Generates a `f32` value from a [WasmValue].
248    pub fn to_f32(&self) -> f32 {
249        unsafe { ffi::WasmEdge_ValueGetF32(self.ctx) }
250    }
251
252    /// Creates a [WasmValue] from a `f64` value.
253    ///
254    /// # Argument
255    ///
256    /// * `val` - The source `f64` value.
257    pub fn from_f64(val: f64) -> Self {
258        Self {
259            ctx: unsafe { ffi::WasmEdge_ValueGenF64(val) },
260            ty: ValType::F64,
261        }
262    }
263
264    /// Generates a `f64` value from a [WasmValue].
265    pub fn to_f64(&self) -> f64 {
266        unsafe { ffi::WasmEdge_ValueGetF64(self.ctx) }
267    }
268
269    /// Creates a [WasmValue] from a `i128` value.
270    ///
271    /// # Argument
272    ///
273    /// * `val` - The source `i128` value.
274    pub fn from_v128(val: i128) -> Self {
275        Self {
276            ctx: unsafe { ffi::WasmEdge_ValueGenV128(val) },
277            ty: ValType::V128,
278        }
279    }
280
281    /// Generates a `v128` value from a [WasmValue].
282    pub fn to_v128(&self) -> i128 {
283        unsafe { ffi::WasmEdge_ValueGetV128(self.ctx) }
284    }
285
286    /// Checks if a [WasmValue] is NullRef or not.
287    pub fn is_null_ref(&self) -> bool {
288        unsafe { ffi::WasmEdge_ValueIsNullRef(self.ctx) }
289    }
290
291    /// Creates a [WasmValue] from a [FuncRef](crate::FuncRef).
292    ///
293    /// Notice that the [WasmValue]s generated from [FuncRef](crate::FuncRef)s are only meaningful when the `bulk_memory_operations` or `reference_types` option is enabled in the [Config](crate::Config).
294    ///
295    /// # Argument
296    ///
297    /// * `func_ref` - A [FuncRef] instance.
298    pub fn from_func_ref<Func: AsFunc>(func_ref: &Func) -> Self {
299        Self {
300            ctx: unsafe { ffi::WasmEdge_ValueGenFuncRef(func_ref.get_func_raw()) },
301            ty: ValType::FuncRef,
302        }
303    }
304
305    /// Returns the FuncRef(crate::FuncRef).
306    ///
307    /// If the [WasmValue] is a `NullRef`, then `None` is returned.
308    pub fn func_ref(&self) -> Option<FuncRef<&Self>> {
309        unsafe {
310            match ffi::WasmEdge_ValueIsNullRef(self.ctx) {
311                true => None,
312                false => {
313                    let ctx = ffi::WasmEdge_ValueGetFuncRef(self.ctx);
314                    let f = Function::from_raw(ctx as _);
315                    Some(FuncRef::create_from_ref(
316                        std::mem::ManuallyDrop::new(f),
317                        self,
318                    ))
319                }
320            }
321        }
322    }
323
324    /// Creates a [WasmValue] from a reference to an external object.
325    ///
326    /// The [WasmValue]s generated by this function are only meaningful when the `reference_types` option is enabled in
327    /// the [Config](crate::Config).
328    ///
329    /// # Argument
330    ///
331    /// * `extern_obj` - The reference to an external object.
332    pub fn from_extern_ref<T>(extern_obj: &mut T) -> Self {
333        let ptr = extern_obj as *mut T as *mut c_void;
334        Self {
335            ctx: unsafe { ffi::WasmEdge_ValueGenExternRef(ptr) },
336            ty: ValType::ExternRef,
337        }
338    }
339
340    /// Creates a null [WasmValue] with a [ExternRef](wasmedge_types::RefType::ExternRef).
341    ///
342    /// # Argument
343    ///
344    /// * `val` - The `[`RefType`] value.
345    pub fn null_extern_ref() -> Self {
346        Self {
347            ctx: unsafe { ffi::WasmEdge_ValueGenExternRef(std::ptr::null_mut()) },
348            ty: ValType::ExternRef,
349        }
350    }
351
352    /// Returns the reference to an external object.
353    ///
354    /// If the [WasmValue] is a `NullRef`, then `None` is returned.
355    pub fn extern_ref<T>(&self) -> Option<&T> {
356        unsafe {
357            match ffi::WasmEdge_ValueIsNullRef(self.ctx) {
358                true => None,
359                false => {
360                    let ptr = ffi::WasmEdge_ValueGetExternRef(self.ctx);
361                    let x = ptr as *mut T;
362                    Some(&*x)
363                }
364            }
365        }
366    }
367}
368impl From<ffi::WasmEdge_Value> for WasmValue {
369    fn from(raw_val: ffi::WasmEdge_Value) -> Self {
370        let ty = raw_val.Type.into();
371        Self { ctx: raw_val, ty }
372    }
373}
374
375impl From<ffi::WasmEdge_ValType> for ValType {
376    fn from(value: ffi::WasmEdge_ValType) -> Self {
377        unsafe {
378            if ffi::WasmEdge_ValTypeIsI32(value) {
379                ValType::I32
380            } else if ffi::WasmEdge_ValTypeIsI64(value) {
381                ValType::I64
382            } else if ffi::WasmEdge_ValTypeIsF32(value) {
383                ValType::F32
384            } else if ffi::WasmEdge_ValTypeIsF64(value) {
385                ValType::F64
386            } else if ffi::WasmEdge_ValTypeIsV128(value) {
387                ValType::V128
388            } else if ffi::WasmEdge_ValTypeIsRef(value) {
389                if ffi::WasmEdge_ValTypeIsFuncRef(value) {
390                    ValType::FuncRef
391                } else if ffi::WasmEdge_ValTypeIsExternRef(value) {
392                    ValType::ExternRef
393                } else {
394                    log::warn!(
395                        "capi unsupport WasmEdge_RefType `{:x}`",
396                        u64::from_be_bytes(value.Data)
397                    );
398                    ValType::UnsupportedRef
399                }
400            } else {
401                log::warn!(
402                    "unknown WasmEdge_ValType `{:x}`",
403                    u64::from_be_bytes(value.Data)
404                );
405                ValType::UnsupportedRef
406            }
407        }
408    }
409}
410impl From<ValType> for ffi::WasmEdge_ValType {
411    fn from(value: ValType) -> Self {
412        unsafe {
413            match value {
414                ValType::I32 => ffi::WasmEdge_ValTypeGenI32(),
415                ValType::I64 => ffi::WasmEdge_ValTypeGenI64(),
416                ValType::F32 => ffi::WasmEdge_ValTypeGenF32(),
417                ValType::F64 => ffi::WasmEdge_ValTypeGenF64(),
418                ValType::V128 => ffi::WasmEdge_ValTypeGenV128(),
419                ValType::FuncRef => ffi::WasmEdge_ValTypeGenFuncRef(),
420                ValType::ExternRef => ffi::WasmEdge_ValTypeGenExternRef(),
421                // C API is temporarily unsupported.
422                ValType::UnsupportedRef => ffi::WasmEdge_ValTypeGenExternRef(),
423            }
424        }
425    }
426}
427
428#[cfg(test)]
429mod tests {
430    use super::*;
431    #[cfg(unix)]
432    use crate::{Table, TableType};
433    use std::{
434        sync::{Arc, Mutex},
435        thread,
436    };
437    #[cfg(unix)]
438    use wasmedge_types::RefType;
439
440    #[test]
441    #[cfg(unix)]
442    fn test_types_value() {
443        // I32
444        let val = WasmValue::from_i32(1314);
445        assert_eq!(val.ty(), ValType::I32);
446
447        // I64
448        let val = WasmValue::from_i64(1314);
449        assert_eq!(val.ty(), ValType::I64);
450
451        // F32
452        let val = WasmValue::from_f32(13.14);
453        assert_eq!(val.ty(), ValType::F32);
454
455        // F64
456        let val = WasmValue::from_f64(13.14);
457        assert_eq!(val.ty(), ValType::F64);
458
459        // V128
460        let val = WasmValue::from_v128(1314);
461        assert_eq!(val.ty(), ValType::V128);
462
463        // ExternRef
464        let ty = TableType::new(RefType::FuncRef, 10, Some(20));
465        let result = Table::create(ty);
466        assert!(result.is_ok());
467        let mut table = result.unwrap();
468        let value = WasmValue::from_extern_ref(&mut table);
469        assert_eq!(value.ty(), ValType::ExternRef);
470        assert!(value.extern_ref::<Table>().is_some());
471
472        let val1 = WasmValue::from_i32(1314);
473        let val2 = WasmValue::from_i32(1314);
474        assert_eq!(val1.to_i32(), val2.to_i32());
475    }
476
477    #[test]
478    #[cfg(unix)]
479    fn test_types_value_send() {
480        // I32
481        let val_i32 = WasmValue::from_i32(1314);
482        // I64
483        let val_i64 = WasmValue::from_i64(1314);
484        // F32
485        let val_f32 = WasmValue::from_f32(13.14);
486        // F64
487        let val_f64 = WasmValue::from_f64(13.14);
488        // V128
489        let val_v128 = WasmValue::from_v128(1314);
490
491        // ExternRef
492        let ty = TableType::new(RefType::FuncRef, 10, Some(20));
493        let result = Table::create(ty);
494        assert!(result.is_ok());
495        let mut table = result.unwrap();
496        let val_extern_ref = WasmValue::from_extern_ref(&mut table);
497
498        let handle = thread::spawn(move || {
499            let val_i32_c = val_i32;
500            assert_eq!(val_i32_c.ty(), ValType::I32);
501
502            let val_i64_c = val_i64;
503            assert_eq!(val_i64_c.ty(), ValType::I64);
504
505            let val_f32_c = val_f32;
506            assert_eq!(val_f32_c.ty(), ValType::F32);
507
508            let val_f64_c = val_f64;
509            assert_eq!(val_f64_c.ty(), ValType::F64);
510
511            let val_v128_c = val_v128;
512            assert_eq!(val_v128_c.ty(), ValType::V128);
513
514            let val_extern_ref_c = val_extern_ref;
515            assert_eq!(val_extern_ref_c.ty(), ValType::ExternRef);
516            assert!(val_extern_ref_c.extern_ref::<Table>().is_some());
517        });
518
519        handle.join().unwrap();
520    }
521
522    #[test]
523    #[cfg(unix)]
524    fn test_types_value_sync() {
525        // I32
526        let val_i32 = Arc::new(Mutex::new(WasmValue::from_i32(1314)));
527        let val_i32_cloned = Arc::clone(&val_i32);
528
529        // I64
530        let val_i64 = Arc::new(Mutex::new(WasmValue::from_i64(1314)));
531        let val_i64_cloned = Arc::clone(&val_i64);
532
533        // F32
534        let val_f32 = Arc::new(Mutex::new(WasmValue::from_f32(13.14)));
535        let val_f32_cloned = Arc::clone(&val_f32);
536
537        // F64
538        let val_f64 = Arc::new(Mutex::new(WasmValue::from_f64(13.14)));
539        let val_f64_cloned = Arc::clone(&val_f64);
540
541        // V128
542        let val_v128 = Arc::new(Mutex::new(WasmValue::from_v128(1314)));
543        let val_v128_cloned = Arc::clone(&val_v128);
544
545        // ExternRef
546        let ty = TableType::new(RefType::FuncRef, 10, Some(20));
547        let result = Table::create(ty);
548        assert!(result.is_ok());
549        let mut table = result.unwrap();
550        let val_extern_ref = Arc::new(Mutex::new(WasmValue::from_extern_ref(&mut table)));
551        let val_extern_ref_cloned = Arc::clone(&val_extern_ref);
552
553        let handle = thread::spawn(move || {
554            let result = val_i32_cloned.lock();
555            assert!(result.is_ok());
556            let val_i32_c = result.unwrap();
557            assert_eq!(val_i32_c.ty(), ValType::I32);
558
559            let result = val_i64_cloned.lock();
560            assert!(result.is_ok());
561            let val_i64_c = result.unwrap();
562            assert_eq!(val_i64_c.ty(), ValType::I64);
563
564            let result = val_f32_cloned.lock();
565            assert!(result.is_ok());
566            let val_f32_c = result.unwrap();
567            assert_eq!(val_f32_c.ty(), ValType::F32);
568
569            let result = val_f64_cloned.lock();
570            assert!(result.is_ok());
571            let val_f64_c = result.unwrap();
572            assert_eq!(val_f64_c.ty(), ValType::F64);
573
574            let result = val_v128_cloned.lock();
575            assert!(result.is_ok());
576            let val_v128_c = result.unwrap();
577            assert_eq!(val_v128_c.ty(), ValType::V128);
578
579            let result = val_extern_ref_cloned.lock();
580            assert!(result.is_ok());
581            let val_extern_ref_c = result.unwrap();
582            assert_eq!(val_extern_ref_c.ty(), ValType::ExternRef);
583            assert!(val_extern_ref_c.extern_ref::<Table>().is_some());
584        });
585
586        handle.join().unwrap();
587    }
588
589    #[test]
590    fn test_types_string() {
591        let s: WasmEdgeString = "hello".into();
592        let t: WasmEdgeString = "hello".into();
593        assert_eq!(s, t);
594
595        let s: WasmEdgeString = "hello".into();
596        let t = String::from(s);
597        assert_eq!(t, "hello");
598
599        let s: WasmEdgeString = "hello".into();
600        let t: WasmEdgeString = "hello\0".into();
601        assert_ne!(s, t);
602
603        let s: WasmEdgeString = "hello\0".into();
604        let t = String::from(s);
605        assert_eq!(t, "hello\0");
606
607        let s: WasmEdgeString = "he\0llo\0".into();
608        let t = String::from(s);
609        assert_eq!(t, "he\0llo\0");
610    }
611
612    #[test]
613    fn test_types_string_send() {
614        let s: WasmEdgeString = "hello".into();
615
616        let handle = thread::spawn(move || {
617            let t: WasmEdgeString = "hello".into();
618            assert_eq!(s, t);
619        });
620
621        handle.join().unwrap();
622    }
623
624    #[test]
625    fn test_types_string_sync() {
626        let s: WasmEdgeString = "hello".into();
627        let p = Arc::new(Mutex::new(s));
628
629        let s_cloned = Arc::clone(&p);
630        let handle = thread::spawn(move || {
631            let result = s_cloned.lock();
632            assert!(result.is_ok());
633            let s = result.unwrap();
634
635            let t: WasmEdgeString = "hello".into();
636            assert_eq!(*s, t);
637        });
638
639        handle.join().unwrap();
640    }
641}