xref: /wasmtime-44.0.1/crates/c-api/src/val.rs (revision bd2ea901)
1 use crate::r#ref::ref_to_val;
2 use crate::{
3     from_valtype, into_valtype, wasm_ref_t, wasm_valkind_t, wasmtime_valkind_t, CStoreContextMut,
4     WASM_I32,
5 };
6 use std::mem::{self, ManuallyDrop, MaybeUninit};
7 use std::ptr;
8 use wasmtime::{AsContextMut, Func, HeapType, Ref, Val, ValType};
9 
10 #[repr(C)]
11 pub struct wasm_val_t {
12     pub kind: wasm_valkind_t,
13     pub of: wasm_val_union,
14 }
15 
16 #[repr(C)]
17 #[derive(Copy, Clone)]
18 pub union wasm_val_union {
19     pub i32: i32,
20     pub i64: i64,
21     pub u32: u32,
22     pub u64: u64,
23     pub f32: f32,
24     pub f64: f64,
25     pub ref_: *mut wasm_ref_t,
26 }
27 
28 impl Drop for wasm_val_t {
29     fn drop(&mut self) {
30         match into_valtype(self.kind) {
31             ValType::Ref(_) => unsafe {
32                 if !self.of.ref_.is_null() {
33                     drop(Box::from_raw(self.of.ref_));
34                 }
35             },
36             _ => {}
37         }
38     }
39 }
40 
41 impl Clone for wasm_val_t {
42     fn clone(&self) -> Self {
43         let mut ret = wasm_val_t {
44             kind: self.kind,
45             of: self.of,
46         };
47         unsafe {
48             match into_valtype(self.kind) {
49                 ValType::Ref(_) if !self.of.ref_.is_null() => {
50                     ret.of.ref_ = Box::into_raw(Box::new((*self.of.ref_).clone()));
51                 }
52                 _ => {}
53             }
54         }
55         return ret;
56     }
57 }
58 
59 impl Default for wasm_val_t {
60     fn default() -> Self {
61         wasm_val_t {
62             kind: WASM_I32,
63             of: wasm_val_union { i32: 0 },
64         }
65     }
66 }
67 
68 impl wasm_val_t {
69     pub fn from_val(val: Val) -> wasm_val_t {
70         match val {
71             Val::I32(i) => wasm_val_t {
72                 kind: from_valtype(&ValType::I32),
73                 of: wasm_val_union { i32: i },
74             },
75             Val::I64(i) => wasm_val_t {
76                 kind: from_valtype(&ValType::I64),
77                 of: wasm_val_union { i64: i },
78             },
79             Val::F32(f) => wasm_val_t {
80                 kind: from_valtype(&ValType::F32),
81                 of: wasm_val_union { u32: f },
82             },
83             Val::F64(f) => wasm_val_t {
84                 kind: from_valtype(&ValType::F64),
85                 of: wasm_val_union { u64: f },
86             },
87             Val::ExternRef(_) => crate::abort("externref"),
88             Val::FuncRef(f) => wasm_val_t {
89                 kind: from_valtype(&ValType::FUNCREF),
90                 of: wasm_val_union {
91                     ref_: f.map_or(ptr::null_mut(), |f| {
92                         Box::into_raw(Box::new(wasm_ref_t {
93                             r: Ref::Func(Some(f)),
94                         }))
95                     }),
96                 },
97             },
98             _ => unimplemented!("wasm_val_t::from_val {:?}", val),
99         }
100     }
101 
102     pub fn val(&self) -> Val {
103         match into_valtype(self.kind) {
104             ValType::I32 => Val::from(unsafe { self.of.i32 }),
105             ValType::I64 => Val::from(unsafe { self.of.i64 }),
106             ValType::F32 => Val::from(unsafe { self.of.f32 }),
107             ValType::F64 => Val::from(unsafe { self.of.f64 }),
108             ValType::Ref(r) => match (r.is_nullable(), r.heap_type()) {
109                 (true, HeapType::Extern) => unsafe {
110                     if self.of.ref_.is_null() {
111                         Val::ExternRef(None)
112                     } else {
113                         ref_to_val(&*self.of.ref_)
114                     }
115                 },
116                 (true, HeapType::Func) => unsafe {
117                     if self.of.ref_.is_null() {
118                         Val::FuncRef(None)
119                     } else {
120                         ref_to_val(&*self.of.ref_)
121                     }
122                 },
123                 _ => unimplemented!("wasm_val_t: non-funcref and non-externref reference types"),
124             },
125             ValType::V128 => unimplemented!("wasm_val_t: v128"),
126         }
127     }
128 }
129 
130 #[no_mangle]
131 pub unsafe extern "C" fn wasm_val_copy(out: &mut MaybeUninit<wasm_val_t>, source: &wasm_val_t) {
132     crate::initialize(out, source.clone());
133 }
134 
135 #[no_mangle]
136 pub unsafe extern "C" fn wasm_val_delete(val: *mut wasm_val_t) {
137     ptr::drop_in_place(val);
138 }
139 
140 #[repr(C)]
141 pub struct wasmtime_val_t {
142     pub kind: wasmtime_valkind_t,
143     pub of: wasmtime_val_union,
144 }
145 
146 #[repr(C)]
147 pub union wasmtime_val_union {
148     pub i32: i32,
149     pub i64: i64,
150     pub f32: u32,
151     pub f64: u64,
152     pub funcref: wasmtime_func_t,
153     pub v128: [u8; 16],
154 }
155 
156 #[repr(C)]
157 #[derive(Clone, Copy)]
158 pub struct wasmtime_func_t {
159     pub store_id: u64,
160     pub index: usize,
161 }
162 
163 impl wasmtime_val_t {
164     pub fn from_val(cx: impl AsContextMut, val: Val) -> wasmtime_val_t {
165         // TODO: Needed for when we re-add externref support.
166         let _ = cx;
167 
168         match val {
169             Val::I32(i) => wasmtime_val_t {
170                 kind: crate::WASMTIME_I32,
171                 of: wasmtime_val_union { i32: i },
172             },
173             Val::I64(i) => wasmtime_val_t {
174                 kind: crate::WASMTIME_I64,
175                 of: wasmtime_val_union { i64: i },
176             },
177             Val::F32(i) => wasmtime_val_t {
178                 kind: crate::WASMTIME_F32,
179                 of: wasmtime_val_union { f32: i },
180             },
181             Val::F64(i) => wasmtime_val_t {
182                 kind: crate::WASMTIME_F64,
183                 of: wasmtime_val_union { f64: i },
184             },
185             Val::ExternRef(_) => crate::abort("externref"),
186             Val::FuncRef(func) => wasmtime_val_t {
187                 kind: crate::WASMTIME_FUNCREF,
188                 of: wasmtime_val_union {
189                     funcref: match func {
190                         None => wasmtime_func_t {
191                             store_id: 0,
192                             index: 0,
193                         },
194                         Some(func) => unsafe { mem::transmute::<Func, wasmtime_func_t>(func) },
195                     },
196                 },
197             },
198             Val::V128(val) => wasmtime_val_t {
199                 kind: crate::WASMTIME_V128,
200                 of: wasmtime_val_union {
201                     v128: val.as_u128().to_le_bytes(),
202                 },
203             },
204         }
205     }
206 
207     pub unsafe fn to_val(&self, cx: impl AsContextMut) -> Val {
208         // TODO: needed for when we re-add externref support.
209         let _ = cx;
210 
211         match self.kind {
212             crate::WASMTIME_I32 => Val::I32(self.of.i32),
213             crate::WASMTIME_I64 => Val::I64(self.of.i64),
214             crate::WASMTIME_F32 => Val::F32(self.of.f32),
215             crate::WASMTIME_F64 => Val::F64(self.of.f64),
216             crate::WASMTIME_V128 => Val::V128(u128::from_le_bytes(self.of.v128).into()),
217             crate::WASMTIME_FUNCREF => {
218                 let store = self.of.funcref.store_id;
219                 let index = self.of.funcref.index;
220                 Val::FuncRef(if store == 0 && index == 0 {
221                     None
222                 } else {
223                     Some(mem::transmute::<wasmtime_func_t, Func>(self.of.funcref))
224                 })
225             }
226             other => panic!("unknown wasmtime_valkind_t: {}", other),
227         }
228     }
229 }
230 
231 impl Drop for wasmtime_val_t {
232     fn drop(&mut self) {
233         // TODO: this drop impl is needed for when we re-add externref support.
234     }
235 }
236 
237 #[no_mangle]
238 pub unsafe extern "C" fn wasmtime_val_delete(
239     cx: CStoreContextMut<'_>,
240     val: &mut ManuallyDrop<wasmtime_val_t>,
241 ) {
242     // TODO: needed for when we re-add externref support.
243     let _ = cx;
244 
245     ManuallyDrop::drop(val)
246 }
247 
248 #[no_mangle]
249 pub unsafe extern "C" fn wasmtime_val_copy(
250     mut cx: CStoreContextMut<'_>,
251     dst: &mut MaybeUninit<wasmtime_val_t>,
252     src: &wasmtime_val_t,
253 ) {
254     let val = src.to_val(&mut cx);
255     crate::initialize(dst, wasmtime_val_t::from_val(cx, val))
256 }
257