Skip to main content

wasmtime_c_api/
ref.rs

1use crate::{WasmtimeStoreContextMut, abort};
2use std::mem::{ManuallyDrop, MaybeUninit};
3use std::{num::NonZeroU64, os::raw::c_void, ptr};
4use wasmtime::{
5    AnyRef, EqRef, ExnRef, ExternRef, FieldType, I31, Mutability, OwnedRooted, Ref, RootScope,
6    StorageType, StructRef, StructRefPre, StructType, Val, ValType,
7};
8
9/// `*mut wasm_ref_t` is a reference type (`externref` or `funcref`), as seen by
10/// the C API. Because we do not have a uniform representation for `funcref`s
11/// and `externref`s, a `*mut wasm_ref_t` is morally a
12/// `Option<Box<Either<ExternRef, Func>>>`.
13///
14/// A null `*mut wasm_ref_t` is either a null `funcref` or a null `externref`
15/// depending on context (e.g. the table's element type that it is going into or
16/// coming out of).
17///
18/// Note: this is not `#[repr(C)]` because it is an opaque type in the header,
19/// and only ever referenced as `*mut wasm_ref_t`. This also lets us use a
20/// regular, non-`repr(C)` `enum` to define `WasmRefInner`.
21#[derive(Clone)]
22pub struct wasm_ref_t {
23    pub(crate) r: Ref,
24}
25
26wasmtime_c_api_macros::declare_own!(wasm_ref_t);
27
28impl wasm_ref_t {
29    pub(crate) fn new(r: Ref) -> Option<Box<wasm_ref_t>> {
30        if r.is_null() || !r.is_func() {
31            None
32        } else {
33            Some(Box::new(wasm_ref_t { r }))
34        }
35    }
36}
37
38pub(crate) fn ref_to_val(r: &wasm_ref_t) -> Val {
39    Val::from(r.r.clone())
40}
41
42#[unsafe(no_mangle)]
43pub extern "C" fn wasm_ref_copy(r: Option<&wasm_ref_t>) -> Option<Box<wasm_ref_t>> {
44    r.map(|r| Box::new(r.clone()))
45}
46
47#[unsafe(no_mangle)]
48pub extern "C" fn wasm_ref_same(_a: Option<&wasm_ref_t>, _b: Option<&wasm_ref_t>) -> bool {
49    // We need a store to determine whether these are the same reference or not.
50    abort("wasm_ref_same")
51}
52
53#[unsafe(no_mangle)]
54pub extern "C" fn wasm_ref_get_host_info(_ref: Option<&wasm_ref_t>) -> *mut c_void {
55    std::ptr::null_mut()
56}
57
58#[unsafe(no_mangle)]
59pub extern "C" fn wasm_ref_set_host_info(_ref: Option<&wasm_ref_t>, _info: *mut c_void) {
60    abort("wasm_ref_set_host_info")
61}
62
63#[unsafe(no_mangle)]
64pub extern "C" fn wasm_ref_set_host_info_with_finalizer(
65    _ref: Option<&wasm_ref_t>,
66    _info: *mut c_void,
67    _finalizer: Option<extern "C" fn(*mut c_void)>,
68) {
69    abort("wasm_ref_set_host_info_with_finalizer")
70}
71
72#[unsafe(no_mangle)]
73pub extern "C" fn wasm_ref_as_extern(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_extern_t> {
74    abort("wasm_ref_as_extern")
75}
76
77#[unsafe(no_mangle)]
78pub extern "C" fn wasm_ref_as_extern_const(
79    _ref: Option<&wasm_ref_t>,
80) -> Option<&crate::wasm_extern_t> {
81    abort("wasm_ref_as_extern_const")
82}
83
84#[unsafe(no_mangle)]
85pub extern "C" fn wasm_ref_as_foreign(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_foreign_t> {
86    abort("wasm_ref_as_foreign")
87}
88
89#[unsafe(no_mangle)]
90pub extern "C" fn wasm_ref_as_foreign_const(
91    _ref: Option<&wasm_ref_t>,
92) -> Option<&crate::wasm_foreign_t> {
93    abort("wasm_ref_as_foreign_const")
94}
95
96#[unsafe(no_mangle)]
97pub extern "C" fn wasm_ref_as_func(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
98    abort("wasm_ref_as_func")
99}
100
101#[unsafe(no_mangle)]
102pub extern "C" fn wasm_ref_as_func_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_func_t> {
103    abort("wasm_ref_as_func_const")
104}
105
106#[unsafe(no_mangle)]
107pub extern "C" fn wasm_ref_as_global(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_global_t> {
108    abort("wasm_ref_as_global")
109}
110
111#[unsafe(no_mangle)]
112pub extern "C" fn wasm_ref_as_global_const(
113    _ref: Option<&wasm_ref_t>,
114) -> Option<&crate::wasm_global_t> {
115    abort("wasm_ref_as_global_const")
116}
117
118#[unsafe(no_mangle)]
119pub extern "C" fn wasm_ref_as_instance(
120    _ref: Option<&wasm_ref_t>,
121) -> Option<&crate::wasm_instance_t> {
122    abort("wasm_ref_as_instance")
123}
124
125#[unsafe(no_mangle)]
126pub extern "C" fn wasm_ref_as_instance_const(
127    _ref: Option<&wasm_ref_t>,
128) -> Option<&crate::wasm_instance_t> {
129    abort("wasm_ref_as_instance_const")
130}
131
132#[unsafe(no_mangle)]
133pub extern "C" fn wasm_ref_as_memory(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_memory_t> {
134    abort("wasm_ref_as_memory")
135}
136
137#[unsafe(no_mangle)]
138pub extern "C" fn wasm_ref_as_memory_const(
139    _ref: Option<&wasm_ref_t>,
140) -> Option<&crate::wasm_memory_t> {
141    abort("wasm_ref_as_memory_const")
142}
143
144#[unsafe(no_mangle)]
145pub extern "C" fn wasm_ref_as_module(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_module_t> {
146    abort("wasm_ref_as_module")
147}
148
149#[unsafe(no_mangle)]
150pub extern "C" fn wasm_ref_as_module_const(
151    _ref: Option<&wasm_ref_t>,
152) -> Option<&crate::wasm_module_t> {
153    abort("wasm_ref_as_module_const")
154}
155
156#[unsafe(no_mangle)]
157pub extern "C" fn wasm_ref_as_table(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_table_t> {
158    abort("wasm_ref_as_table")
159}
160
161#[unsafe(no_mangle)]
162pub extern "C" fn wasm_ref_as_table_const(
163    _ref: Option<&wasm_ref_t>,
164) -> Option<&crate::wasm_table_t> {
165    abort("wasm_ref_as_table_const")
166}
167
168#[unsafe(no_mangle)]
169pub extern "C" fn wasm_ref_as_trap(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
170    abort("wasm_ref_as_trap")
171}
172
173#[unsafe(no_mangle)]
174pub extern "C" fn wasm_ref_as_trap_const(_ref: Option<&wasm_ref_t>) -> Option<&crate::wasm_trap_t> {
175    abort("wasm_ref_as_trap_const")
176}
177
178#[derive(Clone)]
179#[repr(C)]
180pub struct wasm_foreign_t {}
181
182wasmtime_c_api_macros::declare_ref!(wasm_foreign_t);
183
184#[unsafe(no_mangle)]
185pub extern "C" fn wasm_foreign_new(_store: &crate::wasm_store_t) -> Box<wasm_foreign_t> {
186    abort("wasm_foreign_new")
187}
188
189/// C-API representation of `anyref`.
190///
191/// This represented differently in the C API from the header to handle how
192/// this is dispatched internally. Null anyref values are represented with a
193/// `store_id` of zero, and otherwise the `rooted` field is valid.
194///
195/// Note that this relies on the Wasmtime definition of `OwnedRooted` to have
196/// a 64-bit store_id first.
197macro_rules! ref_wrapper {
198    ($wasmtime:ident => $c:ident) => {
199        pub struct $c {
200            store_id: u64,
201            a: u32,
202            b: u32,
203            c: *const (),
204        }
205
206        impl $c {
207            pub unsafe fn as_wasmtime(&self) -> Option<OwnedRooted<$wasmtime>> {
208                let store_id = NonZeroU64::new(self.store_id)?;
209                Some(OwnedRooted::from_borrowed_raw_parts_for_c_api(
210                    store_id, self.a, self.b, self.c,
211                ))
212            }
213
214            pub unsafe fn into_wasmtime(self) -> Option<OwnedRooted<$wasmtime>> {
215                ManuallyDrop::new(self).to_owned()
216            }
217
218            unsafe fn to_owned(&self) -> Option<OwnedRooted<$wasmtime>> {
219                let store_id = NonZeroU64::new(self.store_id)?;
220                Some(OwnedRooted::from_owned_raw_parts_for_c_api(
221                    store_id, self.a, self.b, self.c,
222                ))
223            }
224        }
225
226        impl Drop for $c {
227            fn drop(&mut self) {
228                unsafe {
229                    let _ = self.to_owned();
230                }
231            }
232        }
233
234        impl From<Option<OwnedRooted<$wasmtime>>> for $c {
235            fn from(rooted: Option<OwnedRooted<$wasmtime>>) -> $c {
236                let mut ret = $c {
237                    store_id: 0,
238                    a: 0,
239                    b: 0,
240                    c: core::ptr::null(),
241                };
242                if let Some(rooted) = rooted {
243                    let (store_id, a, b, c) = rooted.into_parts_for_c_api();
244                    ret.store_id = store_id.get();
245                    ret.a = a;
246                    ret.b = b;
247                    ret.c = c;
248                }
249                ret
250            }
251        }
252
253        impl From<OwnedRooted<$wasmtime>> for $c {
254            fn from(rooted: OwnedRooted<$wasmtime>) -> $c {
255                Self::from(Some(rooted))
256            }
257        }
258
259        // SAFETY: The `*const ()` comes from (and is converted back
260        // into) an `Arc<()>`, and is only accessed as such, so this
261        // type is both Send and Sync. These constraints are necessary
262        // in the async machinery in this crate.
263        unsafe impl Send for $c {}
264        unsafe impl Sync for $c {}
265    };
266}
267
268ref_wrapper!(AnyRef => wasmtime_anyref_t);
269ref_wrapper!(ExternRef => wasmtime_externref_t);
270ref_wrapper!(EqRef => wasmtime_eqref_t);
271ref_wrapper!(StructRef => wasmtime_structref_t);
272ref_wrapper!(ExnRef => wasmtime_exnref_t);
273
274// Opaque types for struct type and struct ref pre-allocator
275pub struct wasmtime_struct_type_t {
276    ty: StructType,
277}
278wasmtime_c_api_macros::declare_own!(wasmtime_struct_type_t);
279
280pub struct wasmtime_struct_ref_pre_t {
281    pre: StructRefPre,
282}
283wasmtime_c_api_macros::declare_own!(wasmtime_struct_ref_pre_t);
284
285#[unsafe(no_mangle)]
286pub unsafe extern "C" fn wasmtime_anyref_clone(
287    anyref: Option<&wasmtime_anyref_t>,
288    out: &mut MaybeUninit<wasmtime_anyref_t>,
289) {
290    let anyref = anyref.and_then(|a| a.as_wasmtime());
291    crate::initialize(out, anyref.into());
292}
293
294#[unsafe(no_mangle)]
295pub unsafe extern "C" fn wasmtime_anyref_unroot(val: Option<&mut ManuallyDrop<wasmtime_anyref_t>>) {
296    if let Some(val) = val {
297        unsafe {
298            ManuallyDrop::drop(val);
299        }
300    }
301}
302
303#[unsafe(no_mangle)]
304pub unsafe extern "C" fn wasmtime_anyref_to_raw(
305    cx: WasmtimeStoreContextMut<'_>,
306    val: Option<&wasmtime_anyref_t>,
307) -> u32 {
308    val.and_then(|v| v.as_wasmtime())
309        .and_then(|e| e.to_raw(cx).ok())
310        .unwrap_or_default()
311}
312
313#[unsafe(no_mangle)]
314pub unsafe extern "C" fn wasmtime_anyref_from_raw(
315    cx: WasmtimeStoreContextMut<'_>,
316    raw: u32,
317    val: &mut MaybeUninit<wasmtime_anyref_t>,
318) {
319    let mut scope = RootScope::new(cx);
320    let anyref =
321        AnyRef::from_raw(&mut scope, raw).map(|a| a.to_owned_rooted(&mut scope).expect("in scope"));
322    crate::initialize(val, anyref.into());
323}
324
325#[unsafe(no_mangle)]
326pub extern "C" fn wasmtime_anyref_from_i31(
327    cx: WasmtimeStoreContextMut<'_>,
328    val: u32,
329    out: &mut MaybeUninit<wasmtime_anyref_t>,
330) {
331    let mut scope = RootScope::new(cx);
332    let anyref = AnyRef::from_i31(&mut scope, I31::wrapping_u32(val));
333    let anyref = anyref.to_owned_rooted(&mut scope).expect("in scope");
334    crate::initialize(out, Some(anyref).into())
335}
336
337#[unsafe(no_mangle)]
338pub unsafe extern "C" fn wasmtime_anyref_is_i31(
339    cx: WasmtimeStoreContextMut<'_>,
340    anyref: Option<&wasmtime_anyref_t>,
341) -> bool {
342    match anyref.and_then(|a| a.as_wasmtime()) {
343        Some(anyref) => anyref.is_i31(&cx).expect("OwnedRooted always in scope"),
344        None => false,
345    }
346}
347
348#[unsafe(no_mangle)]
349pub unsafe extern "C" fn wasmtime_anyref_i31_get_u(
350    cx: WasmtimeStoreContextMut<'_>,
351    anyref: Option<&wasmtime_anyref_t>,
352    dst: &mut MaybeUninit<u32>,
353) -> bool {
354    match anyref.and_then(|a| a.as_wasmtime()) {
355        Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
356            let val = anyref
357                .unwrap_i31(&cx)
358                .expect("OwnedRooted always in scope")
359                .get_u32();
360            crate::initialize(dst, val);
361            true
362        }
363        _ => false,
364    }
365}
366
367#[unsafe(no_mangle)]
368pub unsafe extern "C" fn wasmtime_anyref_i31_get_s(
369    cx: WasmtimeStoreContextMut<'_>,
370    anyref: Option<&wasmtime_anyref_t>,
371    dst: &mut MaybeUninit<i32>,
372) -> bool {
373    match anyref.and_then(|a| a.as_wasmtime()) {
374        Some(anyref) if anyref.is_i31(&cx).expect("OwnedRooted always in scope") => {
375            let val = anyref
376                .unwrap_i31(&cx)
377                .expect("OwnedRooted always in scope")
378                .get_i32();
379            crate::initialize(dst, val);
380            true
381        }
382        _ => false,
383    }
384}
385
386#[unsafe(no_mangle)]
387pub extern "C" fn wasmtime_externref_new(
388    cx: WasmtimeStoreContextMut<'_>,
389    data: *mut c_void,
390    finalizer: Option<extern "C" fn(*mut c_void)>,
391    out: &mut MaybeUninit<wasmtime_externref_t>,
392) -> bool {
393    let mut scope = RootScope::new(cx);
394    let e = match ExternRef::new(&mut scope, crate::ForeignData { data, finalizer }) {
395        Ok(e) => e,
396        Err(_) => return false,
397    };
398    let e = e.to_owned_rooted(&mut scope).expect("in scope");
399    crate::initialize(out, Some(e).into());
400    true
401}
402
403#[unsafe(no_mangle)]
404pub unsafe extern "C" fn wasmtime_externref_data(
405    cx: WasmtimeStoreContextMut<'_>,
406    externref: Option<&wasmtime_externref_t>,
407) -> *mut c_void {
408    externref
409        .and_then(|e| e.as_wasmtime())
410        .and_then(|e| {
411            let data = e.data(cx).ok()??;
412            Some(data.downcast_ref::<crate::ForeignData>().unwrap().data)
413        })
414        .unwrap_or(ptr::null_mut())
415}
416
417#[unsafe(no_mangle)]
418pub unsafe extern "C" fn wasmtime_externref_clone(
419    externref: Option<&wasmtime_externref_t>,
420    out: &mut MaybeUninit<wasmtime_externref_t>,
421) {
422    let externref = externref.and_then(|e| e.as_wasmtime());
423    crate::initialize(out, externref.into());
424}
425
426#[unsafe(no_mangle)]
427pub unsafe extern "C" fn wasmtime_externref_unroot(
428    val: Option<&mut ManuallyDrop<wasmtime_externref_t>>,
429) {
430    if let Some(val) = val {
431        unsafe {
432            ManuallyDrop::drop(val);
433        }
434    }
435}
436
437#[unsafe(no_mangle)]
438pub unsafe extern "C" fn wasmtime_externref_to_raw(
439    cx: WasmtimeStoreContextMut<'_>,
440    val: Option<&wasmtime_externref_t>,
441) -> u32 {
442    val.and_then(|e| e.as_wasmtime())
443        .and_then(|e| e.to_raw(cx).ok())
444        .unwrap_or_default()
445}
446
447#[unsafe(no_mangle)]
448pub unsafe extern "C" fn wasmtime_externref_from_raw(
449    cx: WasmtimeStoreContextMut<'_>,
450    raw: u32,
451    val: &mut MaybeUninit<wasmtime_externref_t>,
452) {
453    let mut scope = RootScope::new(cx);
454    let rooted = ExternRef::from_raw(&mut scope, raw)
455        .map(|e| e.to_owned_rooted(&mut scope).expect("in scope"));
456    crate::initialize(val, rooted.into());
457}
458
459#[unsafe(no_mangle)]
460pub unsafe extern "C" fn wasmtime_exnref_clone(
461    exnref: Option<&wasmtime_exnref_t>,
462    out: &mut MaybeUninit<wasmtime_exnref_t>,
463) {
464    let exnref = exnref.and_then(|e| e.as_wasmtime());
465    crate::initialize(out, exnref.into());
466}
467
468#[unsafe(no_mangle)]
469pub unsafe extern "C" fn wasmtime_exnref_unroot(val: Option<&mut ManuallyDrop<wasmtime_exnref_t>>) {
470    if let Some(val) = val {
471        unsafe {
472            ManuallyDrop::drop(val);
473        }
474    }
475}
476
477#[unsafe(no_mangle)]
478pub unsafe extern "C" fn wasmtime_eqref_clone(
479    eqref: Option<&wasmtime_eqref_t>,
480    out: &mut MaybeUninit<wasmtime_eqref_t>,
481) {
482    let eqref = eqref.and_then(|e| e.as_wasmtime());
483    crate::initialize(out, eqref.into());
484}
485
486#[unsafe(no_mangle)]
487pub unsafe extern "C" fn wasmtime_eqref_unroot(val: Option<&mut ManuallyDrop<wasmtime_eqref_t>>) {
488    if let Some(val) = val {
489        unsafe {
490            ManuallyDrop::drop(val);
491        }
492    }
493}
494
495#[unsafe(no_mangle)]
496pub unsafe extern "C" fn wasmtime_eqref_to_anyref(
497    eqref: Option<&wasmtime_eqref_t>,
498    out: &mut MaybeUninit<wasmtime_anyref_t>,
499) {
500    let anyref = eqref.and_then(|e| e.as_wasmtime()).map(|e| e.to_anyref());
501    crate::initialize(out, anyref.into());
502}
503
504#[unsafe(no_mangle)]
505pub extern "C" fn wasmtime_eqref_from_i31(
506    cx: WasmtimeStoreContextMut<'_>,
507    val: u32,
508    out: &mut MaybeUninit<wasmtime_eqref_t>,
509) {
510    let mut scope = RootScope::new(cx);
511    let eqref = EqRef::from_i31(&mut scope, I31::wrapping_u32(val));
512    let eqref = eqref.to_owned_rooted(&mut scope).expect("in scope");
513    crate::initialize(out, Some(eqref).into())
514}
515
516#[unsafe(no_mangle)]
517pub unsafe extern "C" fn wasmtime_eqref_is_i31(
518    cx: WasmtimeStoreContextMut<'_>,
519    eqref: Option<&wasmtime_eqref_t>,
520) -> bool {
521    match eqref.and_then(|e| e.as_wasmtime()) {
522        Some(eqref) => eqref.is_i31(&cx).expect("OwnedRooted always in scope"),
523        None => false,
524    }
525}
526
527#[unsafe(no_mangle)]
528pub unsafe extern "C" fn wasmtime_eqref_i31_get_u(
529    cx: WasmtimeStoreContextMut<'_>,
530    eqref: Option<&wasmtime_eqref_t>,
531    dst: &mut MaybeUninit<u32>,
532) -> bool {
533    let mut scope = RootScope::new(cx);
534    if let Some(eqref) = eqref.and_then(|e| e.as_wasmtime()) {
535        if let Some(val) = eqref.as_i31(&mut scope).expect("in scope") {
536            crate::initialize(dst, val.get_u32());
537            return true;
538        }
539    }
540    false
541}
542
543#[unsafe(no_mangle)]
544pub unsafe extern "C" fn wasmtime_eqref_i31_get_s(
545    cx: WasmtimeStoreContextMut<'_>,
546    eqref: Option<&wasmtime_eqref_t>,
547    dst: &mut MaybeUninit<i32>,
548) -> bool {
549    let mut scope = RootScope::new(cx);
550    if let Some(eqref) = eqref.and_then(|e| e.as_wasmtime()) {
551        if let Some(val) = eqref.as_i31(&mut scope).expect("in scope") {
552            crate::initialize(dst, val.get_i32());
553            return true;
554        }
555    }
556    false
557}
558
559pub type wasmtime_storage_kind_t = u8;
560pub const WASMTIME_STORAGE_KIND_I8: wasmtime_storage_kind_t = 9;
561pub const WASMTIME_STORAGE_KIND_I16: wasmtime_storage_kind_t = 10;
562
563#[repr(C)]
564pub struct wasmtime_field_type_t {
565    pub kind: wasmtime_storage_kind_t,
566    pub mutable_: bool,
567}
568
569fn field_type_from_c(ft: &wasmtime_field_type_t) -> FieldType {
570    let mutability = if ft.mutable_ {
571        Mutability::Var
572    } else {
573        Mutability::Const
574    };
575    let storage = match ft.kind {
576        WASMTIME_STORAGE_KIND_I8 => StorageType::I8,
577        WASMTIME_STORAGE_KIND_I16 => StorageType::I16,
578        crate::WASMTIME_I32 => StorageType::ValType(ValType::I32),
579        crate::WASMTIME_I64 => StorageType::ValType(ValType::I64),
580        crate::WASMTIME_F32 => StorageType::ValType(ValType::F32),
581        crate::WASMTIME_F64 => StorageType::ValType(ValType::F64),
582        crate::WASMTIME_V128 => StorageType::ValType(ValType::V128),
583        crate::WASMTIME_FUNCREF => StorageType::ValType(ValType::FUNCREF),
584        crate::WASMTIME_EXTERNREF => StorageType::ValType(ValType::EXTERNREF),
585        crate::WASMTIME_ANYREF => StorageType::ValType(ValType::ANYREF),
586        crate::WASMTIME_EXNREF => StorageType::ValType(ValType::EXNREF),
587        other => panic!("unknown wasmtime_storage_kind_t: {other}"),
588    };
589    FieldType::new(mutability, storage)
590}
591
592#[unsafe(no_mangle)]
593pub extern "C" fn wasmtime_struct_type_new(
594    engine: &crate::wasm_engine_t,
595    fields: *const wasmtime_field_type_t,
596    nfields: usize,
597) -> Box<wasmtime_struct_type_t> {
598    let fields = if nfields == 0 {
599        &[]
600    } else {
601        unsafe { std::slice::from_raw_parts(fields, nfields) }
602    };
603    let field_types: Vec<FieldType> = fields.iter().map(field_type_from_c).collect();
604    let ty = StructType::new(&engine.engine, field_types).expect("failed to create struct type");
605    Box::new(wasmtime_struct_type_t { ty })
606}
607
608#[unsafe(no_mangle)]
609pub extern "C" fn wasmtime_struct_ref_pre_new(
610    cx: WasmtimeStoreContextMut<'_>,
611    ty: &wasmtime_struct_type_t,
612) -> Box<wasmtime_struct_ref_pre_t> {
613    let pre = StructRefPre::new(cx, ty.ty.clone());
614    Box::new(wasmtime_struct_ref_pre_t { pre })
615}
616
617#[unsafe(no_mangle)]
618pub unsafe extern "C" fn wasmtime_structref_new(
619    mut cx: WasmtimeStoreContextMut<'_>,
620    pre: &wasmtime_struct_ref_pre_t,
621    fields: *const crate::wasmtime_val_t,
622    nfields: usize,
623    out: &mut MaybeUninit<wasmtime_structref_t>,
624) -> Option<Box<crate::wasmtime_error_t>> {
625    let c_fields = if nfields == 0 {
626        &[]
627    } else {
628        std::slice::from_raw_parts(fields, nfields)
629    };
630    let mut scope = RootScope::new(&mut cx);
631    let vals: Vec<Val> = c_fields.iter().map(|v| v.to_val(&mut scope)).collect();
632    match StructRef::new(&mut scope, &pre.pre, &vals) {
633        Ok(structref) => {
634            let owned = structref
635                .to_owned_rooted(&mut scope)
636                .expect("just allocated");
637            crate::initialize(out, Some(owned).into());
638            None
639        }
640        Err(e) => {
641            crate::initialize(out, None::<OwnedRooted<StructRef>>.into());
642            Some(Box::new(e.into()))
643        }
644    }
645}
646
647#[unsafe(no_mangle)]
648pub unsafe extern "C" fn wasmtime_structref_clone(
649    structref: Option<&wasmtime_structref_t>,
650    out: &mut MaybeUninit<wasmtime_structref_t>,
651) {
652    let structref = structref.and_then(|s| s.as_wasmtime());
653    crate::initialize(out, structref.into());
654}
655
656#[unsafe(no_mangle)]
657pub unsafe extern "C" fn wasmtime_structref_unroot(
658    structref: Option<&mut ManuallyDrop<wasmtime_structref_t>>,
659) {
660    if let Some(structref) = structref {
661        ManuallyDrop::drop(structref);
662    }
663}
664
665#[unsafe(no_mangle)]
666pub unsafe extern "C" fn wasmtime_structref_to_anyref(
667    structref: Option<&wasmtime_structref_t>,
668    out: &mut MaybeUninit<wasmtime_anyref_t>,
669) {
670    let anyref = structref
671        .and_then(|s| s.as_wasmtime())
672        .map(|s| s.to_anyref());
673    crate::initialize(out, anyref.into());
674}
675
676#[unsafe(no_mangle)]
677pub unsafe extern "C" fn wasmtime_structref_to_eqref(
678    structref: Option<&wasmtime_structref_t>,
679    out: &mut MaybeUninit<wasmtime_eqref_t>,
680) {
681    let eqref = structref
682        .and_then(|s| s.as_wasmtime())
683        .map(|s| s.to_eqref());
684    crate::initialize(out, eqref.into());
685}
686
687#[unsafe(no_mangle)]
688pub unsafe extern "C" fn wasmtime_structref_field(
689    mut cx: WasmtimeStoreContextMut<'_>,
690    structref: Option<&wasmtime_structref_t>,
691    index: usize,
692    out: &mut MaybeUninit<crate::wasmtime_val_t>,
693) -> Option<Box<crate::wasmtime_error_t>> {
694    let structref = structref
695        .and_then(|s| s.as_wasmtime())
696        .expect("non-null structref required");
697    let mut scope = RootScope::new(&mut cx);
698    let rooted = structref.to_rooted(&mut scope);
699    match rooted.field(&mut scope, index) {
700        Ok(val) => {
701            let c_val = crate::wasmtime_val_t::from_val(&mut scope, val);
702            crate::initialize(out, c_val);
703            None
704        }
705        Err(e) => Some(Box::new(e.into())),
706    }
707}
708
709#[unsafe(no_mangle)]
710pub unsafe extern "C" fn wasmtime_structref_set_field(
711    mut cx: WasmtimeStoreContextMut<'_>,
712    structref: Option<&wasmtime_structref_t>,
713    index: usize,
714    val: &crate::wasmtime_val_t,
715) -> Option<Box<crate::wasmtime_error_t>> {
716    let structref = structref
717        .and_then(|s| s.as_wasmtime())
718        .expect("non-null structref required");
719    let mut scope = RootScope::new(&mut cx);
720    let rooted = structref.to_rooted(&mut scope);
721    let rust_val = val.to_val(&mut scope);
722    match rooted.set_field(&mut scope, index, rust_val) {
723        Ok(()) => None,
724        Err(e) => Some(Box::new(e.into())),
725    }
726}
727
728#[unsafe(no_mangle)]
729pub unsafe extern "C" fn wasmtime_eqref_is_struct(
730    cx: WasmtimeStoreContextMut<'_>,
731    eqref: Option<&wasmtime_eqref_t>,
732) -> bool {
733    match eqref.and_then(|e| e.as_wasmtime()) {
734        Some(eqref) => eqref.is_struct(&cx).expect("OwnedRooted always in scope"),
735        None => false,
736    }
737}
738
739#[unsafe(no_mangle)]
740pub unsafe extern "C" fn wasmtime_eqref_as_struct(
741    mut cx: WasmtimeStoreContextMut<'_>,
742    eqref: Option<&wasmtime_eqref_t>,
743    out: &mut MaybeUninit<wasmtime_structref_t>,
744) -> bool {
745    if let Some(eqref) = eqref.and_then(|e| e.as_wasmtime()) {
746        let mut scope = RootScope::new(&mut cx);
747        let rooted = eqref.to_rooted(&mut scope);
748        if let Ok(Some(structref)) = rooted.as_struct(&scope) {
749            let owned = structref.to_owned_rooted(&mut scope).expect("in scope");
750            crate::initialize(out, Some(owned).into());
751            return true;
752        }
753    }
754    crate::initialize(out, None::<OwnedRooted<StructRef>>.into());
755    false
756}