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},
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 referenced object.
46    pub ref_: *mut wasm_ref_t,
47}
48
49impl Drop for wasm_val_t {
50    fn drop(&mut self) {
51        if into_valtype(self.kind).is_ref() && !unsafe { self.of.ref_ }.is_null() {
52            drop(unsafe { Box::from_raw(self.of.ref_) });
53        }
54    }
55}
56
57impl Clone for wasm_val_t {
58    fn clone(&self) -> Self {
59        let mut ret = wasm_val_t {
60            kind: self.kind,
61            of: self.of,
62        };
63        unsafe {
64            if into_valtype(self.kind).is_ref() && !self.of.ref_.is_null() {
65                ret.of.ref_ = Box::into_raw(Box::new((*self.of.ref_).clone()));
66            }
67        }
68        ret
69    }
70}
71
72impl Default for wasm_val_t {
73    fn default() -> Self {
74        wasm_val_t {
75            kind: wasm_valkind_t::WASM_I32,
76            of: wasm_val_union { i32: 0 },
77        }
78    }
79}
80
81impl From<Val> for wasm_val_t {
82    fn from(val: Val) -> Self {
83        match val {
84            Val::I32(value) => Self {
85                kind: from_valtype(&ValType::I32),
86                of: wasm_val_union { i32: value },
87            },
88            Val::I64(value) => Self {
89                kind: from_valtype(&ValType::I64),
90                of: wasm_val_union { i64: value },
91            },
92            Val::F32(value) => Self {
93                kind: from_valtype(&ValType::F32),
94                of: wasm_val_union { u32: value.into() },
95            },
96            Val::F64(value) => Self {
97                kind: from_valtype(&ValType::F64),
98                of: wasm_val_union { u64: value.into() },
99            },
100            Val::FuncRef(funcref) => Self {
101                kind: from_valtype(&ValType::FuncRef),
102                of: wasm_val_union {
103                    ref_: {
104                        match funcref.is_null() {
105                            true => ptr::null_mut(),
106                            false => Box::into_raw(Box::new(wasm_ref_t {
107                                inner: WasmRef::Func(funcref),
108                            })),
109                        }
110                    },
111                },
112            },
113            Val::ExternRef(_) => {
114                core::panic!("`wasm_val_t`: creating a `wasm_val_t` from an `externref`")
115            }
116        }
117    }
118}
119
120impl wasm_val_t {
121    /// Creates a new [`Val`] from the [`wasm_val_t`].
122    ///
123    /// # Note
124    ///
125    /// This effectively clones the [`wasm_val_t`] if necessary.
126    pub fn to_val(&self) -> Val {
127        match into_valtype(self.kind) {
128            ValType::I32 => Val::from(unsafe { self.of.i32 }),
129            ValType::I64 => Val::from(unsafe { self.of.i64 }),
130            ValType::F32 => Val::from(F32::from(unsafe { self.of.f32 })),
131            ValType::F64 => Val::from(F64::from(unsafe { self.of.f64 })),
132            ValType::FuncRef => match unsafe { self.of.ref_ }.is_null() {
133                true => Val::FuncRef(FuncRef::null()),
134                false => ref_to_val(unsafe { &*self.of.ref_ }),
135            },
136            ValType::ExternRef => {
137                core::unreachable!("`wasm_val_t`: cannot contain non-function reference values")
138            }
139        }
140    }
141}
142
143/// Copies the [`wasm_val_t`] and stores the result in `out`.
144///
145/// # Safety
146///
147/// The caller is responsible to provide a valid [`wasm_val_t`] that can safely be copied.
148#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
149#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
150pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t) {
151    utils::initialize(out, source.clone());
152}
153
154/// Deletes the [`wasm_val_t`].
155///
156/// # Safety
157///
158/// The caller is responsible to provide a valid [`wasm_val_t`] that can safely be deleted.
159/// The same [`wasm_val_t`] must not be deleted more than once.
160#[cfg_attr(not(feature = "prefix-symbols"), no_mangle)]
161#[cfg_attr(feature = "prefix-symbols", wasmi_c_api_macros::prefix_symbol)]
162pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
163    ptr::drop_in_place(val);
164}