1use crate::{
2 WasmtimeStoreContextMut, handle_result, wasm_trap_t, wasmtime_error_t, wasmtime_val_t,
3};
4use std::mem::MaybeUninit;
5use wasmtime::{AsContextMut, ExnRef, ExnRefPre, ExnType, RootScope, Tag};
6
7crate::anyref::ref_wrapper!({
8 wasmtime: ExnRef,
9 capi: wasmtime_exnref_t,
10 clone: wasmtime_exnref_clone,
11 unroot: wasmtime_exnref_unroot,
12 to_raw: wasmtime_exnref_to_raw,
13 from_raw: wasmtime_exnref_from_raw,
14});
15
16#[unsafe(no_mangle)]
17pub unsafe extern "C" fn wasmtime_exnref_new(
18 mut store: WasmtimeStoreContextMut<'_>,
19 tag: &Tag,
20 fields: *const wasmtime_val_t,
21 nfields: usize,
22 exn_ret: &mut MaybeUninit<wasmtime_exnref_t>,
23) -> Option<Box<wasmtime_error_t>> {
24 let mut scope = RootScope::new(&mut store);
25
26 let result = (|| {
27 let tag_ty = tag.ty(&scope);
28 let exn_type = ExnType::from_tag_type(&tag_ty)?;
29 let allocator = ExnRefPre::new(&mut scope, exn_type);
30 let raw_fields = crate::slice_from_raw_parts(fields, nfields);
31 let field_vals: Vec<wasmtime::Val> =
32 raw_fields.iter().map(|f| f.to_val(&mut scope)).collect();
33 ExnRef::new(&mut scope, &allocator, tag, &field_vals)
34 })();
35
36 handle_result(result, |rooted| {
37 let owned = rooted.to_owned_rooted(&mut scope).unwrap();
38 exn_ret.write(owned.into());
39 })
40}
41
42#[unsafe(no_mangle)]
43pub extern "C" fn wasmtime_exnref_tag(
44 mut store: WasmtimeStoreContextMut<'_>,
45 exn: &wasmtime_exnref_t,
46 tag_ret: &mut Tag,
47) -> Option<Box<wasmtime_error_t>> {
48 let mut scope = RootScope::new(&mut store);
49 let rooted = unsafe { exn.as_wasmtime()?.to_rooted(&mut scope) };
50 handle_result(rooted.tag(&mut scope), |tag| {
51 *tag_ret = tag;
52 })
53}
54
55#[unsafe(no_mangle)]
56pub extern "C" fn wasmtime_exnref_field_count(
57 mut store: WasmtimeStoreContextMut<'_>,
58 exn: &wasmtime_exnref_t,
59) -> usize {
60 let mut scope = RootScope::new(&mut store);
61 let rooted = match unsafe { exn.as_wasmtime() } {
62 Some(e) => e.to_rooted(&mut scope),
63 None => return 0,
64 };
65 let ty = rooted.ty(&scope).unwrap();
66 ty.fields().len()
67}
68
69#[unsafe(no_mangle)]
70pub unsafe extern "C" fn wasmtime_exnref_field(
71 mut store: WasmtimeStoreContextMut<'_>,
72 exn: &wasmtime_exnref_t,
73 index: usize,
74 val_ret: &mut MaybeUninit<wasmtime_val_t>,
75) -> Option<Box<wasmtime_error_t>> {
76 let mut scope = RootScope::new(&mut store);
77 let rooted = exn.as_wasmtime()?.to_rooted(&mut scope);
78 handle_result(rooted.field(&mut scope, index), |val| {
79 crate::initialize(val_ret, wasmtime_val_t::from_val(&mut scope, val));
80 })
81}
82
83#[unsafe(no_mangle)]
84pub unsafe extern "C" fn wasmtime_context_set_exception(
85 mut store: WasmtimeStoreContextMut<'_>,
86 exn: &wasmtime_exnref_t,
87) -> Option<Box<wasm_trap_t>> {
88 let mut scope = RootScope::new(&mut store);
89 let rooted = exn.as_wasmtime()?.to_rooted(&mut scope);
90 let Err(thrown) = scope
91 .as_context_mut()
92 .throw::<std::convert::Infallible>(rooted);
93 Some(Box::new(wasm_trap_t::new(wasmtime::Error::new(thrown))))
94}
95
96#[unsafe(no_mangle)]
97pub extern "C" fn wasmtime_context_take_exception(
98 mut store: WasmtimeStoreContextMut<'_>,
99 out: &mut MaybeUninit<wasmtime_exnref_t>,
100) -> bool {
101 match store.take_pending_exception() {
102 Some(rooted) => {
103 let owned = rooted.to_owned_rooted(&mut store).unwrap();
104 out.write(owned.into());
105 true
106 }
107 None => false,
108 }
109}
110
111#[unsafe(no_mangle)]
112pub extern "C" fn wasmtime_context_has_exception(store: WasmtimeStoreContextMut<'_>) -> bool {
113 store.has_pending_exception()
114}