wasmer_c_api/wasm_c_api/
value.rs1use super::store::StoreRef;
2use super::types::{wasm_ref_t, wasm_valkind_enum};
3use std::convert::{TryFrom, TryInto};
4use wasmer_api::Value;
5
6#[allow(non_camel_case_types)]
16pub type wasm_valkind_t = u8;
17
18#[allow(non_camel_case_types)]
28#[derive(Clone, Copy)]
29pub union wasm_val_inner {
30 pub(crate) int32_t: i32,
31 pub(crate) int64_t: i64,
32 pub(crate) float32_t: f32,
33 pub(crate) float64_t: f64,
34 pub(crate) wref: *mut wasm_ref_t,
35}
36
37#[allow(non_camel_case_types)]
71#[repr(C)]
72pub struct wasm_val_t {
73 pub kind: wasm_valkind_t,
75
76 pub of: wasm_val_inner,
78}
79
80impl std::fmt::Debug for wasm_val_t {
81 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
82 let mut ds = f.debug_struct("wasm_val_t");
83 ds.field("kind", &self.kind);
84
85 match self.kind.try_into() {
86 Ok(wasm_valkind_enum::WASM_I32) => {
87 ds.field("i32", &unsafe { self.of.int32_t });
88 }
89 Ok(wasm_valkind_enum::WASM_I64) => {
90 ds.field("i64", &unsafe { self.of.int64_t });
91 }
92 Ok(wasm_valkind_enum::WASM_F32) => {
93 ds.field("f32", &unsafe { self.of.float32_t });
94 }
95 Ok(wasm_valkind_enum::WASM_F64) => {
96 ds.field("f64", &unsafe { self.of.float64_t });
97 }
98 Ok(wasm_valkind_enum::WASM_EXTERNREF) => {
99 ds.field("anyref", &unsafe { self.of.wref });
100 }
101 Ok(wasm_valkind_enum::WASM_FUNCREF) => {
102 ds.field("funcref", &unsafe { self.of.wref });
103 }
104 Ok(wasm_valkind_enum::WASM_EXNREF) => {
105 ds.field("exnref", &unsafe { self.of.wref });
106 }
107 Err(_) => {
108 ds.field("value", &"Invalid value type");
109 }
110 }
111 ds.finish()
112 }
113}
114
115wasm_declare_vec!(val);
116
117impl Clone for wasm_val_t {
118 fn clone(&self) -> Self {
119 match self.kind.try_into() {
124 Ok(wasm_valkind_enum::WASM_EXTERNREF) | Ok(wasm_valkind_enum::WASM_FUNCREF) => {
125 let wref = unsafe { self.of.wref };
126 let cloned = if wref.is_null() {
127 std::ptr::null_mut()
128 } else {
129 Box::into_raw(Box::new(unsafe { &*wref }.clone()))
130 };
131 wasm_val_t {
132 kind: self.kind,
133 of: wasm_val_inner { wref: cloned },
134 }
135 }
136 _ => wasm_val_t {
137 kind: self.kind,
138 of: self.of,
139 },
140 }
141 }
142}
143
144impl Default for wasm_val_t {
145 fn default() -> Self {
146 Self {
147 kind: wasm_valkind_enum::WASM_I64 as _,
148 of: wasm_val_inner { int64_t: 0 },
149 }
150 }
151}
152
153#[unsafe(no_mangle)]
154pub unsafe extern "C" fn wasm_val_copy(
155 out: &mut wasm_val_t,
157 val: &wasm_val_t,
158) {
159 unsafe { std::ptr::write(out, val.clone()) };
162}
163
164impl Drop for wasm_val_t {
165 fn drop(&mut self) {
166 let kind: Result<wasm_valkind_enum, _> = self.kind.try_into();
167 match kind {
168 Ok(wasm_valkind_enum::WASM_EXTERNREF) | Ok(wasm_valkind_enum::WASM_FUNCREF) => unsafe {
169 if !self.of.wref.is_null() {
170 drop(Box::from_raw(self.of.wref));
171 }
172 },
173 _ => {}
174 }
175 }
176}
177
178#[unsafe(no_mangle)]
179pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
180 if !val.is_null() {
181 unsafe {
182 std::ptr::drop_in_place(val);
183 }
184 }
185}
186
187impl TryFrom<wasm_valkind_t> for wasm_valkind_enum {
188 type Error = &'static str;
189
190 fn try_from(item: wasm_valkind_t) -> Result<Self, Self::Error> {
191 Ok(match item {
192 0 => wasm_valkind_enum::WASM_I32,
193 1 => wasm_valkind_enum::WASM_I64,
194 2 => wasm_valkind_enum::WASM_F32,
195 3 => wasm_valkind_enum::WASM_F64,
196 128 => wasm_valkind_enum::WASM_EXTERNREF,
197 129 => wasm_valkind_enum::WASM_FUNCREF,
198 130 => wasm_valkind_enum::WASM_EXNREF,
199 _ => return Err("valkind value out of bounds"),
200 })
201 }
202}
203
204impl TryFrom<wasm_val_t> for Value {
205 type Error = &'static str;
206
207 fn try_from(item: wasm_val_t) -> Result<Self, Self::Error> {
208 (&item).try_into()
209 }
210}
211
212impl TryFrom<&wasm_val_t> for Value {
213 type Error = &'static str;
214
215 fn try_from(item: &wasm_val_t) -> Result<Self, Self::Error> {
216 Ok(match item.kind.try_into()? {
217 wasm_valkind_enum::WASM_I32 => Value::I32(unsafe { item.of.int32_t }),
218 wasm_valkind_enum::WASM_I64 => Value::I64(unsafe { item.of.int64_t }),
219 wasm_valkind_enum::WASM_F32 => Value::F32(unsafe { item.of.float32_t }),
220 wasm_valkind_enum::WASM_F64 => Value::F64(unsafe { item.of.float64_t }),
221 wasm_valkind_enum::WASM_EXTERNREF => {
222 let wref = unsafe { item.of.wref };
223 if wref.is_null() {
224 Value::ExternRef(None)
225 } else {
226 unsafe { &*wref }.inner.clone()
228 }
229 }
230 wasm_valkind_enum::WASM_FUNCREF => {
231 let wref = unsafe { item.of.wref };
232 if wref.is_null() {
233 Value::FuncRef(None)
234 } else {
235 unsafe { &*wref }.inner.clone()
236 }
237 }
238 wasm_valkind_enum::WASM_EXNREF => return Err("EXNREF not supported at this time"),
239 })
240 }
241}
242
243impl wasm_val_t {
244 pub(crate) fn from_value(value: &Value, store: &StoreRef) -> Result<wasm_val_t, &'static str> {
247 Ok(match value {
248 Value::ExternRef(None) => wasm_val_t {
249 kind: wasm_valkind_enum::WASM_EXTERNREF as _,
250 of: wasm_val_inner {
251 wref: std::ptr::null_mut(),
252 },
253 },
254 Value::FuncRef(None) => wasm_val_t {
255 kind: wasm_valkind_enum::WASM_FUNCREF as _,
256 of: wasm_val_inner {
257 wref: std::ptr::null_mut(),
258 },
259 },
260 Value::ExternRef(Some(_)) | Value::FuncRef(Some(_)) => {
261 let kind = if matches!(value, Value::ExternRef(_)) {
262 wasm_valkind_enum::WASM_EXTERNREF
263 } else {
264 wasm_valkind_enum::WASM_FUNCREF
265 };
266 let boxed = wasm_ref_t::new(store.clone(), value.clone())
268 .ok_or("failed to box reference value")?;
269 wasm_val_t {
270 kind: kind as _,
271 of: wasm_val_inner {
272 wref: Box::into_raw(boxed),
273 },
274 }
275 }
276 other => wasm_val_t::try_from(other)?,
277 })
278 }
279}
280
281impl TryFrom<Value> for wasm_val_t {
282 type Error = &'static str;
283
284 fn try_from(item: Value) -> Result<Self, Self::Error> {
285 wasm_val_t::try_from(&item)
286 }
287}
288
289impl TryFrom<&Value> for wasm_val_t {
290 type Error = &'static str;
291
292 fn try_from(item: &Value) -> Result<Self, Self::Error> {
293 Ok(match *item {
294 Value::I32(v) => wasm_val_t {
295 of: wasm_val_inner { int32_t: v },
296 kind: wasm_valkind_enum::WASM_I32 as _,
297 },
298 Value::I64(v) => wasm_val_t {
299 of: wasm_val_inner { int64_t: v },
300 kind: wasm_valkind_enum::WASM_I64 as _,
301 },
302 Value::F32(v) => wasm_val_t {
303 of: wasm_val_inner { float32_t: v },
304 kind: wasm_valkind_enum::WASM_F32 as _,
305 },
306 Value::F64(v) => wasm_val_t {
307 of: wasm_val_inner { float64_t: v },
308 kind: wasm_valkind_enum::WASM_F64 as _,
309 },
310 Value::V128(_) => return Err("128bit SIMD types not yet supported in Wasm C API"),
311 Value::ExternRef(_) | Value::FuncRef(_) | Value::ExceptionRef(_) => {
314 return Err("reference values require a store; use wasm_val_t::from_value");
315 }
316 })
317 }
318}