wasmtime_c_api/
ref.rs

1use crate::{abort, WasmtimeStoreContextMut};
2use std::{mem::MaybeUninit, num::NonZeroU64, os::raw::c_void, ptr};
3use wasmtime::{AnyRef, ExternRef, ManuallyRooted, Ref, RootScope, Val, I31};
4
5/// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
6/// the C API. Because we do not have a uniform representation for `funcref`s
7/// and `externref`s, a `*mut wasm_ref_t` is morally a
8/// `Option<Box<Either<ExternRef, Func>>>`.
9///
10/// A null `*mut wasm_ref_t` is either a null `funcref` or a null `externref`
11/// depending on context (e.g. the table's element type that it is going into or
12/// coming out of).
13///
14/// Note: this is not `#[repr(C)]` because it is an opaque type in the header,
15/// and only ever referenced as `*mut wasm_ref_t`. This also lets us use a
16/// regular, non-`repr(C)` `enum` to define `WasmRefInner`.
17#[derive(Clone)]
18pub struct wasm_ref_t {
19    pub(crate) r: Ref,
20}
21
22wasmtime_c_api_macros::declare_own!(wasm_ref_t);
23
24impl wasm_ref_t {
25    pub(crate) fn new(r: Ref) -> Option<Box<wasm_ref_t>> {
26        if r.is_null() || !r.is_func() {
27            None
28        } else {
29            Some(Box::new(wasm_ref_t { r }))
30        }
31    }
32}
33
34pub(crate) fn ref_to_val(r: &wasm_ref_t) -> Val {
35    Val::from(r.r.clone())
36}
37
38#[unsafe(no_mangle)]
39pub extern "C" fn wasm_ref_copy(r: Option<&wasm_ref_t>) -> Option<Box<wasm_ref_t>> {
40    r.map(|r| Box::new(r.clone()))
41}
42
43#[unsafe(no_mangle)]
44pub extern "C" fn wasm_ref_same(_a: Option<&wasm_ref_t>, _b: Option<&wasm_ref_t>) -> bool {
45    // We need a store to determine whether these are the same reference or not.
46    abort("wasm_ref_same")
47}
48
49#[unsafe(no_mangle)]
50pub extern "C" fn wasm_ref_get_host_info(_ref: Option<&wasm_ref_t>) -> *mut c_void {
51    std::ptr::null_mut()
52}
53
54#[unsafe(no_mangle)]
55pub extern "C" fn wasm_ref_set_host_info(_ref: Option<&wasm_ref_t>, _info: *mut c_void) {
56    abort("wasm_ref_set_host_info")
57}
58
59#[unsafe(no_mangle)]
60pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
61    _ref: Option<&wasm_ref_t>,
62    _info: *mut c_void,
63    _finalizer: Option<extern "C" fn(*mut c_void)>,
64) {
65    abort("wasm_ref_set_host_info_with_finalizer")
66}
67
68#[unsafe(no_mangle)]
69pub extern "C" fn wasm_ref_as_extern(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_extern_t> {
70    abort("wasm_ref_as_extern")
71}
72
73#[unsafe(no_mangle)]
74pub extern "C" fn wasm_ref_as_extern_const(
75    _ref: Option<&wasm_ref_t>,
76) -> Option<&crate::wasm_extern_t> {
77    abort("wasm_ref_as_extern_const")
78}
79
80#[unsafe(no_mangle)]
81pub extern "C" fn wasm_ref_as_foreign(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_foreign_t> {
82    abort("wasm_ref_as_foreign")
83}
84
85#[unsafe(no_mangle)]
86pub extern "C" fn wasm_ref_as_foreign_const(
87    _ref: Option<&wasm_ref_t>,
88) -> Option<&crate::wasm_foreign_t> {
89    abort("wasm_ref_as_foreign_const")
90}
91
92#[unsafe(no_mangle)]
93pub extern "C" fn wasm_ref_as_func(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
94    abort("wasm_ref_as_func")
95}
96
97#[unsafe(no_mangle)]
98pub extern "C" fn wasm_ref_as_func_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
99    abort("wasm_ref_as_func_const")
100}
101
102#[unsafe(no_mangle)]
103pub extern "C" fn wasm_ref_as_global(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_global_t> {
104    abort("wasm_ref_as_global")
105}
106
107#[unsafe(no_mangle)]
108pub extern "C" fn wasm_ref_as_global_const(
109    _ref: Option<&wasm_ref_t>,
110) -> Option<&crate::wasm_global_t> {
111    abort("wasm_ref_as_global_const")
112}
113
114#[unsafe(no_mangle)]
115pub extern "C" fn wasm_ref_as_instance(
116    _ref: Option<&wasm_ref_t>,
117) -> Option<&crate::wasm_instance_t> {
118    abort("wasm_ref_as_instance")
119}
120
121#[unsafe(no_mangle)]
122pub extern "C" fn wasm_ref_as_instance_const(
123    _ref: Option<&wasm_ref_t>,
124) -> Option<&crate::wasm_instance_t> {
125    abort("wasm_ref_as_instance_const")
126}
127
128#[unsafe(no_mangle)]
129pub extern "C" fn wasm_ref_as_memory(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_memory_t> {
130    abort("wasm_ref_as_memory")
131}
132
133#[unsafe(no_mangle)]
134pub extern "C" fn wasm_ref_as_memory_const(
135    _ref: Option<&wasm_ref_t>,
136) -> Option<&crate::wasm_memory_t> {
137    abort("wasm_ref_as_memory_const")
138}
139
140#[unsafe(no_mangle)]
141pub extern "C" fn wasm_ref_as_module(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_module_t> {
142    abort("wasm_ref_as_module")
143}
144
145#[unsafe(no_mangle)]
146pub extern "C" fn wasm_ref_as_module_const(
147    _ref: Option<&wasm_ref_t>,
148) -> Option<&crate::wasm_module_t> {
149    abort("wasm_ref_as_module_const")
150}
151
152#[unsafe(no_mangle)]
153pub extern "C" fn wasm_ref_as_table(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_table_t> {
154    abort("wasm_ref_as_table")
155}
156
157#[unsafe(no_mangle)]
158pub extern "C" fn wasm_ref_as_table_const(
159    _ref: Option<&wasm_ref_t>,
160) -> Option<&crate::wasm_table_t> {
161    abort("wasm_ref_as_table_const")
162}
163
164#[unsafe(no_mangle)]
165pub extern "C" fn wasm_ref_as_trap(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
166    abort("wasm_ref_as_trap")
167}
168
169#[unsafe(no_mangle)]
170pub extern "C" fn wasm_ref_as_trap_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
171    abort("wasm_ref_as_trap_const")
172}
173
174#[derive(Clone)]
175#[repr(C)]
176pub struct wasm_foreign_t {}
177
178wasmtime_c_api_macros::declare_ref!(wasm_foreign_t);
179
180#[unsafe(no_mangle)]
181pub extern "C" fn wasm_foreign_new(_store: &crate::wasm_store_t) -> Box<wasm_foreign_t> {
182    abort("wasm_foreign_new")
183}
184
185/// C-API representation of `anyref`.
186///
187/// This represented differently in the C API from the header to handle how
188/// this is dispatched internally. Null anyref values are represented with a
189/// `store_id` of zero, and otherwise the `rooted` field is valid.
190///
191/// Note that this relies on the Wasmtime definition of `ManuallyRooted` to have
192/// a 64-bit store_id first.
193macro_rules! ref_wrapper {
194    ($wasmtime:ident => $c:ident) => {
195        pub struct $c {
196            store_id: u64,
197            a: u32,
198            b: u32,
199        }
200
201        impl $c {
202            pub unsafe fn as_wasmtime(&self) -> Option<ManuallyRooted<$wasmtime>> {
203                let store_id = NonZeroU64::new(self.store_id)?;
204                Some(ManuallyRooted::from_raw_parts_for_c_api(
205                    store_id, self.a, self.b,
206                ))
207            }
208        }
209
210        impl From<Option<ManuallyRooted<$wasmtime>>> for $c {
211            fn from(rooted: Option<ManuallyRooted<$wasmtime>>) -> $c {
212                let mut ret = $c {
213                    store_id: 0,
214                    a: 0,
215                    b: 0,
216                };
217                if let Some(rooted) = rooted {
218                    let (store_id, a, b) = rooted.into_parts_for_c_api();
219                    ret.store_id = store_id.get();
220                    ret.a = a;
221                    ret.b = b;
222                }
223                ret
224            }
225        }
226    };
227}
228
229ref_wrapper!(AnyRef => wasmtime_anyref_t);
230ref_wrapper!(ExternRef => wasmtime_externref_t);
231
232#[unsafe(no_mangle)]
233pub unsafe extern "C" fn wasmtime_anyref_clone(
234    cx: WasmtimeStoreContextMut<'_>,
235    anyref: Option<&wasmtime_anyref_t>,
236    out: &mut MaybeUninit<wasmtime_anyref_t>,
237) {
238    let anyref = anyref.and_then(|a| a.as_wasmtime()).map(|a| a.clone(cx));
239    crate::initialize(out, anyref.into());
240}
241
242#[unsafe(no_mangle)]
243pub unsafe extern "C" fn wasmtime_anyref_unroot(
244    cx: WasmtimeStoreContextMut<'_>,
245    val: Option<&mut MaybeUninit<wasmtime_anyref_t>>,
246) {
247    if let Some(val) = val.and_then(|v| v.assume_init_read().as_wasmtime()) {
248        val.unroot(cx);
249    }
250}
251
252#[unsafe(no_mangle)]
253pub unsafe extern "C" fn wasmtime_anyref_to_raw(
254    cx: WasmtimeStoreContextMut<'_>,
255    val: Option<&wasmtime_anyref_t>,
256) -> u32 {
257    val.and_then(|v| v.as_wasmtime())
258        .and_then(|e| e.to_raw(cx).ok())
259        .unwrap_or_default()
260}
261
262#[unsafe(no_mangle)]
263pub unsafe extern "C" fn wasmtime_anyref_from_raw(
264    cx: WasmtimeStoreContextMut<'_>,
265    raw: u32,
266    val: &mut MaybeUninit<wasmtime_anyref_t>,
267) {
268    let mut scope = RootScope::new(cx);
269    let anyref = AnyRef::from_raw(&mut scope, raw)
270        .map(|a| a.to_manually_rooted(&mut scope).expect("in scope"));
271    crate::initialize(val, anyref.into());
272}
273
274#[unsafe(no_mangle)]
275pub extern "C" fn wasmtime_anyref_from_i31(
276    cx: WasmtimeStoreContextMut<'_>,
277    val: u32,
278    out: &mut MaybeUninit<wasmtime_anyref_t>,
279) {
280    let mut scope = RootScope::new(cx);
281    let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val));
282    let anyref = anyref.to_manually_rooted(&mut scope).expect("in scope");
283    crate::initialize(out, Some(anyref).into())
284}
285
286#[unsafe(no_mangle)]
287pub unsafe extern "C" fn wasmtime_anyref_i31_get_u(
288    cx: WasmtimeStoreContextMut<'_>,
289    anyref: Option<&wasmtime_anyref_t>,
290    dst: &mut MaybeUninit<u32>,
291) -> bool {
292    match anyref.and_then(|a| a.as_wasmtime()) {
293        Some(anyref) if anyref.is_i31(&cx).expect("ManuallyRooted always in scope") => {
294            let val = anyref
295                .unwrap_i31(&cx)
296                .expect("ManuallyRooted always in scope")
297                .get_u32();
298            crate::initialize(dst, val);
299            true
300        }
301        _ => false,
302    }
303}
304
305#[unsafe(no_mangle)]
306pub unsafe extern "C" fn wasmtime_anyref_i31_get_s(
307    cx: WasmtimeStoreContextMut<'_>,
308    anyref: Option<&wasmtime_anyref_t>,
309    dst: &mut MaybeUninit<i32>,
310) -> bool {
311    match anyref.and_then(|a| a.as_wasmtime()) {
312        Some(anyref) if anyref.is_i31(&cx).expect("ManuallyRooted always in scope") => {
313            let val = anyref
314                .unwrap_i31(&cx)
315                .expect("ManuallyRooted always in scope")
316                .get_i32();
317            crate::initialize(dst, val);
318            true
319        }
320        _ => false,
321    }
322}
323
324#[unsafe(no_mangle)]
325pub extern "C" fn wasmtime_externref_new(
326    cx: WasmtimeStoreContextMut<'_>,
327    data: *mut c_void,
328    finalizer: Option<extern "C" fn(*mut c_void)>,
329    out: &mut MaybeUninit<wasmtime_externref_t>,
330) -> bool {
331    let mut scope = RootScope::new(cx);
332    let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) {
333        Ok(e) => e,
334        Err(_) => return false,
335    };
336    let e = e.to_manually_rooted(&mut scope).expect("in scope");
337    crate::initialize(out, Some(e).into());
338    true
339}
340
341#[unsafe(no_mangle)]
342pub unsafe extern "C" fn wasmtime_externref_data(
343    cx: WasmtimeStoreContextMut<'_>,
344    externref: Option<&wasmtime_externref_t>,
345) -> *mut c_void {
346    externref
347        .and_then(|e| e.as_wasmtime())
348        .and_then(|e| {
349            let data = e.data(cx).ok()??;
350            Some(data.downcast_ref::<crate::ForeignData>().unwrap().data)
351        })
352        .unwrap_or(ptr::null_mut())
353}
354
355#[unsafe(no_mangle)]
356pub unsafe extern "C" fn wasmtime_externref_clone(
357    cx: WasmtimeStoreContextMut<'_>,
358    externref: Option<&wasmtime_externref_t>,
359    out: &mut MaybeUninit<wasmtime_externref_t>,
360) {
361    let externref = externref.and_then(|e| e.as_wasmtime()).map(|e| e.clone(cx));
362    crate::initialize(out, externref.into());
363}
364
365#[unsafe(no_mangle)]
366pub unsafe extern "C" fn wasmtime_externref_unroot(
367    cx: WasmtimeStoreContextMut<'_>,
368    val: Option<&mut MaybeUninit<wasmtime_externref_t>>,
369) {
370    if let Some(val) = val.and_then(|v| v.assume_init_read().as_wasmtime()) {
371        val.unroot(cx);
372    }
373}
374
375#[unsafe(no_mangle)]
376pub unsafe extern "C" fn wasmtime_externref_to_raw(
377    cx: WasmtimeStoreContextMut<'_>,
378    val: Option<&wasmtime_externref_t>,
379) -> u32 {
380    val.and_then(|e| e.as_wasmtime())
381        .and_then(|e| e.to_raw(cx).ok())
382        .unwrap_or_default()
383}
384
385#[unsafe(no_mangle)]
386pub unsafe extern "C" fn wasmtime_externref_from_raw(
387    cx: WasmtimeStoreContextMut<'_>,
388    raw: u32,
389    val: &mut MaybeUninit<wasmtime_externref_t>,
390) {
391    let mut scope = RootScope::new(cx);
392    let rooted = ExternRef::from_raw(&mut scope, raw)
393        .map(|e| e.to_manually_rooted(&mut scope).expect("in scope"));
394    crate::initialize(val, rooted.into());
395}