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