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