Skip to main content

wasmi_c_api/
val.rs

1use crate::{from_valtype, into_valtype, utils, wasm_ref_t, wasm_valkind_t};
2use alloc::boxed::Box;
3use core::{mem::MaybeUninit, ptr};
4use wasmi::{F32, F64, Func, Nullable, Ref, Val, ValType};
5
6/// A Wasm value.
7///
8/// Mirrors [`Val`].
9#[repr(C)]
10pub struct wasm_val_t {
11    /// The kind of the Wasm value.
12    pub kind: wasm_valkind_t,
13    /// The underlying data of the Wasm value classified by `kind`.
14    pub of: wasm_val_union,
15}
16
17/// The underlying data of a [`wasm_val_t`].
18#[repr(C)]
19#[derive(Copy, Clone)]
20pub union wasm_val_union {
21    /// A Wasm 32-bit signed integer.
22    pub i32: i32,
23    /// A Wasm 64-bit signed integer.
24    pub i64: i64,
25    /// A Wasm 32-bit unsigned integer.
26    pub u32: u32,
27    /// A Wasm 64-bit unsigned integer.
28    pub u64: u64,
29    /// A Wasm 32-bit float.
30    pub f32: f32,
31    /// A Wasm 64-bit float.
32    pub f64: f64,
33    /// A Wasm referenced object.
34    pub ref_: *mut wasm_ref_t,
35}
36
37impl Drop for wasm_val_t {
38    fn drop(&mut self) {
39        if into_valtype(self.kind).is_ref() && !unsafe { self.of.ref_ }.is_null() {
40            drop(unsafe { Box::from_raw(self.of.ref_) });
41        }
42    }
43}
44
45impl Clone for wasm_val_t {
46    fn clone(&self) -> Self {
47        let mut ret = wasm_val_t {
48            kind: self.kind,
49            of: self.of,
50        };
51        unsafe {
52            if into_valtype(self.kind).is_ref() && !self.of.ref_.is_null() {
53                ret.of.ref_ = Box::into_raw(Box::new((*self.of.ref_).clone()));
54            }
55        }
56        ret
57    }
58}
59
60impl Default for wasm_val_t {
61    fn default() -> Self {
62        wasm_val_t {
63            kind: wasm_valkind_t::WASM_I32,
64            of: wasm_val_union { i32: 0 },
65        }
66    }
67}
68
69impl From<Val> for wasm_val_t {
70    fn from(val: Val) -> Self {
71        match val {
72            Val::I32(value) => Self {
73                kind: from_valtype(&ValType::I32),
74                of: wasm_val_union { i32: value },
75            },
76            Val::I64(value) => Self {
77                kind: from_valtype(&ValType::I64),
78                of: wasm_val_union { i64: value },
79            },
80            Val::F32(value) => Self {
81                kind: from_valtype(&ValType::F32),
82                of: wasm_val_union {
83                    u32: value.to_bits(),
84                },
85            },
86            Val::F64(value) => Self {
87                kind: from_valtype(&ValType::F64),
88                of: wasm_val_union {
89                    u64: value.to_bits(),
90                },
91            },
92            Val::V128(value) => core::panic!(
93                "`wasm_val_t`: creating a `wasm_val_t` from an `v128` value is not supported but found: {value:?}"
94            ),
95            Val::FuncRef(funcref) => Self {
96                kind: from_valtype(&ValType::FuncRef),
97                of: wasm_val_union {
98                    ref_: {
99                        match funcref.is_null() {
100                            true => ptr::null_mut(),
101                            false => Box::into_raw(Box::new(wasm_ref_t {
102                                inner: Ref::Func(funcref),
103                            })),
104                        }
105                    },
106                },
107            },
108            Val::ExternRef(_) => {
109                core::panic!("`wasm_val_t`: creating a `wasm_val_t` from an `externref`")
110            }
111        }
112    }
113}
114
115impl wasm_val_t {
116    /// Creates a new [`Val`] from the [`wasm_val_t`].
117    ///
118    /// # Note
119    ///
120    /// This effectively clones the [`wasm_val_t`] if necessary.
121    pub fn to_val(&self) -> Val {
122        match self.kind {
123            wasm_valkind_t::WASM_I32 => Val::from(unsafe { self.of.i32 }),
124            wasm_valkind_t::WASM_I64 => Val::from(unsafe { self.of.i64 }),
125            wasm_valkind_t::WASM_F32 => Val::from(F32::from(unsafe { self.of.f32 })),
126            wasm_valkind_t::WASM_F64 => Val::from(F64::from(unsafe { self.of.f64 })),
127            wasm_valkind_t::WASM_FUNCREF => match unsafe { self.of.ref_ }.is_null() {
128                true => Val::FuncRef(<Nullable<Func>>::Null),
129                false => Val::from((unsafe { &*self.of.ref_ }).inner),
130            },
131            wasm_valkind_t::WASM_EXTERNREF => {
132                core::unreachable!("`wasm_val_t`: cannot contain non-function reference values")
133            }
134        }
135    }
136}
137
138/// Copies the [`wasm_val_t`] and stores the result in `out`.
139///
140/// # Safety
141///
142/// The caller is responsible to provide a valid [`wasm_val_t`] that can safely be copied.
143#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
144#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
145pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t) {
146    utils::initialize(out, source.clone());
147}
148
149/// Deletes the [`wasm_val_t`].
150///
151/// # Safety
152///
153/// The caller is responsible to provide a valid [`wasm_val_t`] that can safely be deleted.
154/// The same [`wasm_val_t`] must not be deleted more than once.
155#[cfg_attr(not(feature = "prefix-symbols"), unsafe(no_mangle))]
156#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
157pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
158    unsafe {
159        ptr::drop_in_place(val);
160    }
161}