wasmi_c_api/
val.rs

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