wasmer_c_api/wasm_c_api/
value.rs

1use super::types::{wasm_ref_t, wasm_valkind_enum};
2use std::convert::{TryFrom, TryInto};
3use wasmer_api::Value;
4
5/// Represents the kind of values. The variants of this C enum is
6/// defined in `wasm.h` to list the following:
7///
8/// * `WASM_I32`, a 32-bit integer,
9/// * `WASM_I64`, a 64-bit integer,
10/// * `WASM_F32`, a 32-bit float,
11/// * `WASM_F64`, a 64-bit float,
12/// * `WASM_EXTERNREF`, a WebAssembly reference,
13/// * `WASM_FUNCREF`, a WebAssembly reference.
14#[allow(non_camel_case_types)]
15pub type wasm_valkind_t = u8;
16
17/// A Rust union, compatible with C, that holds a value of kind
18/// [`wasm_valkind_t`] (see [`wasm_val_t`] to get the complete
19/// picture). Members of the union are:
20///
21/// * `int32_t` if the value is a 32-bit integer,
22/// * `int64_t` if the value is a 64-bit integer,
23/// * `float32_t` if the value is a 32-bit float,
24/// * `float64_t` if the value is a 64-bit float,
25/// * `wref` (`wasm_ref_t`) if the value is a WebAssembly reference.
26#[allow(non_camel_case_types)]
27#[derive(Clone, Copy)]
28pub union wasm_val_inner {
29    pub(crate) int32_t: i32,
30    pub(crate) int64_t: i64,
31    pub(crate) float32_t: f32,
32    pub(crate) float64_t: f64,
33    pub(crate) wref: *mut wasm_ref_t,
34}
35
36/// A WebAssembly value composed of its type and its value.
37///
38/// Note that `wasm.h` defines macros to create Wasm values more
39/// easily: `WASM_I32_VAL`, `WASM_I64_VAL`, `WASM_F32_VAL`,
40/// `WASM_F64_VAL`, and `WASM_REF_VAL`.
41///
42/// # Example
43///
44/// ```rust
45/// # use wasmer_inline_c::assert_c;
46/// # fn main() {
47/// #    (assert_c! {
48/// # #include "tests/wasmer.h"
49/// #
50/// int main() {
51///     // Create a 32-bit integer Wasm value.
52///     wasm_val_t value1 = {
53///         .kind = WASM_I32,
54///         .of = { .i32 = 7 },
55///     };
56///
57///     // Create the same value with the `wasm.h` macro.
58///     wasm_val_t value2 = WASM_I32_VAL(7);
59///
60///     assert(value2.kind == WASM_I32);
61///     assert(value1.of.i32 == value2.of.i32);
62///
63///     return 0;
64/// }
65/// #    })
66/// #    .success();
67/// # }
68/// ```
69#[allow(non_camel_case_types)]
70#[repr(C)]
71pub struct wasm_val_t {
72    /// The kind of the value.
73    pub kind: wasm_valkind_t,
74
75    /// The real value.
76    pub of: wasm_val_inner,
77}
78
79impl std::fmt::Debug for wasm_val_t {
80    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
81        let mut ds = f.debug_struct("wasm_val_t");
82        ds.field("kind", &self.kind);
83
84        match self.kind.try_into() {
85            Ok(wasm_valkind_enum::WASM_I32) => {
86                ds.field("i32", &unsafe { self.of.int32_t });
87            }
88            Ok(wasm_valkind_enum::WASM_I64) => {
89                ds.field("i64", &unsafe { self.of.int64_t });
90            }
91            Ok(wasm_valkind_enum::WASM_F32) => {
92                ds.field("f32", &unsafe { self.of.float32_t });
93            }
94            Ok(wasm_valkind_enum::WASM_F64) => {
95                ds.field("f64", &unsafe { self.of.float64_t });
96            }
97            Ok(wasm_valkind_enum::WASM_EXTERNREF) => {
98                ds.field("anyref", &unsafe { self.of.wref });
99            }
100            Ok(wasm_valkind_enum::WASM_FUNCREF) => {
101                ds.field("funcref", &unsafe { self.of.wref });
102            }
103            Ok(wasm_valkind_enum::WASM_EXNREF) => {
104                ds.field("exnref", &unsafe { self.of.wref });
105            }
106            Err(_) => {
107                ds.field("value", &"Invalid value type");
108            }
109        }
110        ds.finish()
111    }
112}
113
114wasm_declare_vec!(val);
115
116impl Clone for wasm_val_t {
117    fn clone(&self) -> Self {
118        wasm_val_t {
119            kind: self.kind,
120            of: self.of,
121        }
122    }
123}
124
125impl Default for wasm_val_t {
126    fn default() -> Self {
127        Self {
128            kind: wasm_valkind_enum::WASM_I64 as _,
129            of: wasm_val_inner { int64_t: 0 },
130        }
131    }
132}
133
134#[unsafe(no_mangle)]
135pub unsafe extern "C" fn wasm_val_copy(
136    // own
137    out: &mut wasm_val_t,
138    val: &wasm_val_t,
139) {
140    out.kind = val.kind;
141    out.of = c_try!(val.kind.try_into().map(|kind| unsafe {
142        match kind {
143            wasm_valkind_enum::WASM_I32 => wasm_val_inner {
144                int32_t: val.of.int32_t,
145            },
146            wasm_valkind_enum::WASM_I64 => wasm_val_inner {
147                int64_t: val.of.int64_t,
148            },
149            wasm_valkind_enum::WASM_F32 => wasm_val_inner {
150                float32_t: val.of.float32_t,
151            },
152            wasm_valkind_enum::WASM_F64 => wasm_val_inner {
153                float64_t: val.of.float64_t,
154            },
155            wasm_valkind_enum::WASM_EXTERNREF => wasm_val_inner { wref: val.of.wref },
156            wasm_valkind_enum::WASM_FUNCREF => wasm_val_inner { wref: val.of.wref },
157            wasm_valkind_enum::WASM_EXNREF => wasm_val_inner { wref: val.of.wref },
158        }
159    }); otherwise ());
160}
161
162impl Drop for wasm_val_t {
163    fn drop(&mut self) {
164        let kind: Result<wasm_valkind_enum, _> = self.kind.try_into();
165        match kind {
166            Ok(wasm_valkind_enum::WASM_EXTERNREF) | Ok(wasm_valkind_enum::WASM_FUNCREF) => unsafe {
167                if !self.of.wref.is_null() {
168                    drop(Box::from_raw(self.of.wref));
169                }
170            },
171            _ => {}
172        }
173    }
174}
175
176#[unsafe(no_mangle)]
177pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
178    if !val.is_null() {
179        unsafe {
180            std::ptr::drop_in_place(val);
181        }
182    }
183}
184
185impl TryFrom<wasm_valkind_t> for wasm_valkind_enum {
186    type Error = &'static str;
187
188    fn try_from(item: wasm_valkind_t) -> Result<Self, Self::Error> {
189        Ok(match item {
190            0 => wasm_valkind_enum::WASM_I32,
191            1 => wasm_valkind_enum::WASM_I64,
192            2 => wasm_valkind_enum::WASM_F32,
193            3 => wasm_valkind_enum::WASM_F64,
194            128 => wasm_valkind_enum::WASM_EXTERNREF,
195            129 => wasm_valkind_enum::WASM_FUNCREF,
196            130 => wasm_valkind_enum::WASM_EXNREF,
197            _ => return Err("valkind value out of bounds"),
198        })
199    }
200}
201
202impl TryFrom<wasm_val_t> for Value {
203    type Error = &'static str;
204
205    fn try_from(item: wasm_val_t) -> Result<Self, Self::Error> {
206        (&item).try_into()
207    }
208}
209
210impl TryFrom<&wasm_val_t> for Value {
211    type Error = &'static str;
212
213    fn try_from(item: &wasm_val_t) -> Result<Self, Self::Error> {
214        Ok(match item.kind.try_into()? {
215            wasm_valkind_enum::WASM_I32 => Value::I32(unsafe { item.of.int32_t }),
216            wasm_valkind_enum::WASM_I64 => Value::I64(unsafe { item.of.int64_t }),
217            wasm_valkind_enum::WASM_F32 => Value::F32(unsafe { item.of.float32_t }),
218            wasm_valkind_enum::WASM_F64 => Value::F64(unsafe { item.of.float64_t }),
219            wasm_valkind_enum::WASM_EXTERNREF => {
220                return Err("EXTERNREF not supported at this time");
221            }
222            wasm_valkind_enum::WASM_FUNCREF => return Err("FUNCREF not supported at this time"),
223            wasm_valkind_enum::WASM_EXNREF => return Err("EXNREF not supported at this time"),
224        })
225    }
226}
227
228impl TryFrom<Value> for wasm_val_t {
229    type Error = &'static str;
230
231    fn try_from(item: Value) -> Result<Self, Self::Error> {
232        wasm_val_t::try_from(&item)
233    }
234}
235
236impl TryFrom<&Value> for wasm_val_t {
237    type Error = &'static str;
238
239    fn try_from(item: &Value) -> Result<Self, Self::Error> {
240        Ok(match *item {
241            Value::I32(v) => wasm_val_t {
242                of: wasm_val_inner { int32_t: v },
243                kind: wasm_valkind_enum::WASM_I32 as _,
244            },
245            Value::I64(v) => wasm_val_t {
246                of: wasm_val_inner { int64_t: v },
247                kind: wasm_valkind_enum::WASM_I64 as _,
248            },
249            Value::F32(v) => wasm_val_t {
250                of: wasm_val_inner { float32_t: v },
251                kind: wasm_valkind_enum::WASM_F32 as _,
252            },
253            Value::F64(v) => wasm_val_t {
254                of: wasm_val_inner { float64_t: v },
255                kind: wasm_valkind_enum::WASM_F64 as _,
256            },
257            Value::V128(_) => return Err("128bit SIMD types not yet supported in Wasm C API"),
258            _ => todo!("Handle these values in TryFrom<Value> for wasm_val_t"),
259        })
260    }
261}